From 7d417e26218a4cdb8c56d926eb12881318c082a5 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 9 Apr 2026 20:49:29 +0200 Subject: [PATCH 01/40] chore(intel/metadata): remove bg package bg and cbnt packages will be merged in the follow-up commits. Signed-off-by: Michal Gorlas --- pkg/intel/metadata/bg/bgbootpolicy/bpmh.go | 39 - .../bg/bgbootpolicy/bpmh_manifestcodegen.go | 384 ------- .../metadata/bg/bgbootpolicy/manifest.go | 93 -- .../bgbootpolicy/manifest_manifestcodegen.go | 337 ------- .../bg/bgbootpolicy/manifest_nocodegen.go | 44 - .../metadata/bg/bgbootpolicy/manifest_test.go | 17 - pkg/intel/metadata/bg/bgbootpolicy/pm.go | 13 - .../bg/bgbootpolicy/pm_manifestcodegen.go | 244 ----- pkg/intel/metadata/bg/bgbootpolicy/se.go | 140 --- .../bg/bgbootpolicy/se_manifestcodegen.go | 947 ------------------ .../metadata/bg/bgbootpolicy/signature.go | 15 - .../bgbootpolicy/signature_manifestcodegen.go | 205 ---- .../metadata/bg/bgbootpolicy/testdata/bpm.bin | Bin 699 -> 0 bytes .../bg/bgbootpolicy/testdata/bpm2.bin | Bin 723 -> 0 bytes .../bg/bgbootpolicy/testdata/bpm3.bin | Bin 699 -> 0 bytes pkg/intel/metadata/bg/bgkey/manifest.go | 65 -- .../bg/bgkey/manifest_manifestcodegen.go | 336 ------- .../metadata/bg/bgkey/manifest_nocodegen.go | 21 - pkg/intel/metadata/bg/bgkey/manifest_test.go | 15 - pkg/intel/metadata/bg/bgkey/testdata/km.bin | Bin 577 -> 0 bytes pkg/intel/metadata/bg/config.go | 20 - pkg/intel/metadata/bg/crypto_routines.go | 103 -- .../bg/crypto_routines_manifestcodegen.go | 49 - pkg/intel/metadata/bg/hash.go | 52 - pkg/intel/metadata/bg/hash_manifestcodegen.go | 306 ------ pkg/intel/metadata/bg/key.go | 164 --- pkg/intel/metadata/bg/key_manifestcodegen.go | 253 ----- pkg/intel/metadata/bg/key_signature.go | 81 -- .../bg/key_signature_manifestcodegen.go | 208 ---- pkg/intel/metadata/bg/signature.go | 129 --- .../metadata/bg/signature_manifestcodegen.go | 258 ----- pkg/intel/metadata/bg/signature_types.go | 112 --- pkg/intel/metadata/bg/structure.go | 56 -- .../metadata/bg/structure_manifestcodegen.go | 157 --- pkg/intel/metadata/bg/svn.go | 15 - pkg/intel/metadata/bg/svn_manifestcodegen.go | 54 - 36 files changed, 4932 deletions(-) delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/bpmh.go delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/bpmh_manifestcodegen.go delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/manifest.go delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/manifest_manifestcodegen.go delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/manifest_nocodegen.go delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/manifest_test.go delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/pm.go delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/pm_manifestcodegen.go delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/se.go delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/se_manifestcodegen.go delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/signature.go delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/signature_manifestcodegen.go delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/testdata/bpm.bin delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/testdata/bpm2.bin delete mode 100644 pkg/intel/metadata/bg/bgbootpolicy/testdata/bpm3.bin delete mode 100644 pkg/intel/metadata/bg/bgkey/manifest.go delete mode 100644 pkg/intel/metadata/bg/bgkey/manifest_manifestcodegen.go delete mode 100644 pkg/intel/metadata/bg/bgkey/manifest_nocodegen.go delete mode 100644 pkg/intel/metadata/bg/bgkey/manifest_test.go delete mode 100644 pkg/intel/metadata/bg/bgkey/testdata/km.bin delete mode 100644 pkg/intel/metadata/bg/config.go delete mode 100644 pkg/intel/metadata/bg/crypto_routines.go delete mode 100644 pkg/intel/metadata/bg/crypto_routines_manifestcodegen.go delete mode 100644 pkg/intel/metadata/bg/hash.go delete mode 100644 pkg/intel/metadata/bg/hash_manifestcodegen.go delete mode 100644 pkg/intel/metadata/bg/key.go delete mode 100644 pkg/intel/metadata/bg/key_manifestcodegen.go delete mode 100644 pkg/intel/metadata/bg/key_signature.go delete mode 100644 pkg/intel/metadata/bg/key_signature_manifestcodegen.go delete mode 100644 pkg/intel/metadata/bg/signature.go delete mode 100644 pkg/intel/metadata/bg/signature_manifestcodegen.go delete mode 100644 pkg/intel/metadata/bg/signature_types.go delete mode 100644 pkg/intel/metadata/bg/structure.go delete mode 100644 pkg/intel/metadata/bg/structure_manifestcodegen.go delete mode 100644 pkg/intel/metadata/bg/svn.go delete mode 100644 pkg/intel/metadata/bg/svn_manifestcodegen.go diff --git a/pkg/intel/metadata/bg/bgbootpolicy/bpmh.go b/pkg/intel/metadata/bg/bgbootpolicy/bpmh.go deleted file mode 100644 index d1619d1e..00000000 --- a/pkg/intel/metadata/bg/bgbootpolicy/bpmh.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package bgbootpolicy - -import "github.com/linuxboot/fiano/pkg/intel/metadata/bg" - -type BPMH struct { - StructInfo `id:"__ACBP__" version:"0x10"` - - HdrStructVersion uint8 `json:"HdrStructVersion"` - - PMBPMVersion uint8 `json:"bpmhRevision"` - - // PrettyString: BPM SVN - BPMSVN bg.SVN `json:"bpmhSNV"` - // PrettyString: ACM SVN Auth - ACMSVNAuth bg.SVN `json:"bpmhACMSVN"` - - Reserved0 [1]byte `require:"0" json:"bpmhReserved0,omitempty"` - - NEMDataStack Size4K `json:"bpmhNEMStackSize"` -} - -// Size4K is a size in units of 4096 bytes. -type Size4K uint16 - -// InBytes returns the size in bytes. -func (s Size4K) InBytes() uint32 { - return uint32(s) * 4096 -} - -// NewSize4K returns the given size as multiple of 4K -func NewSize4K(size uint32) Size4K { - return Size4K(size / 4096) -} diff --git a/pkg/intel/metadata/bg/bgbootpolicy/bpmh_manifestcodegen.go b/pkg/intel/metadata/bg/bgbootpolicy/bpmh_manifestcodegen.go deleted file mode 100644 index 8ab2faf3..00000000 --- a/pkg/intel/metadata/bg/bgbootpolicy/bpmh_manifestcodegen.go +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen -package bg github.com/linuxboot/fiano/pkg/intel/metadata/bg/bgbootpolicy - -package bgbootpolicy - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/bg" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = bg.StructInfo{} -) - -// NewBPMH returns a new instance of BPMH with -// all default values set. -func NewBPMH() *BPMH { - s := &BPMH{} - copy(s.StructInfo.ID[:], []byte(StructureIDBPMH)) - s.StructInfo.Version = 0x10 - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *BPMH) Validate() error { - // See tag "require" - for idx := range s.Reserved0 { - if s.Reserved0[idx] != 0 { - return fmt.Errorf("'Reserved0[%d]' is expected to be 0, but it is %v", idx, s.Reserved0[idx]) - } - } - - return nil -} - -// StructureIDBPMH is the StructureID (in terms of -// the document #575623) of element 'BPMH'. -const StructureIDBPMH = "__ACBP__" - -// GetStructInfo returns current value of StructInfo of the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *BPMH) GetStructInfo() bg.StructInfo { - return s.StructInfo -} - -// SetStructInfo sets new value of StructInfo to the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *BPMH) SetStructInfo(newStructInfo bg.StructInfo) { - s.StructInfo = newStructInfo -} - -// ReadFrom reads the BPMH from 'r' in format defined in the document #575623. -func (s *BPMH) ReadFrom(r io.Reader) (int64, error) { - var totalN int64 - - err := binary.Read(r, binary.LittleEndian, &s.StructInfo) - if err != nil { - return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) - } - totalN += int64(binary.Size(s.StructInfo)) - - n, err := s.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read data: %w", err) - } - totalN += n - - return totalN, nil -} - -// ReadDataFrom reads the BPMH from 'r' excluding StructInfo, -// in format defined in the document #575623. -func (s *BPMH) ReadDataFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // StructInfo (ManifestFieldType: structInfo) - { - // ReadDataFrom does not read Struct, use ReadFrom for that. - } - - // HdrStructVersion (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.HdrStructVersion) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'HdrStructVersion': %w", err) - } - totalN += int64(n) - } - - // PMBPMVersion (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.PMBPMVersion) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'PMBPMVersion': %w", err) - } - totalN += int64(n) - } - - // BPMSVN (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.BPMSVN) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'BPMSVN': %w", err) - } - totalN += int64(n) - } - - // ACMSVNAuth (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.ACMSVNAuth) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'ACMSVNAuth': %w", err) - } - totalN += int64(n) - } - - // Reserved0 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Read(r, binary.LittleEndian, s.Reserved0[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved0': %w", err) - } - totalN += int64(n) - } - - // NEMDataStack (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.NEMDataStack) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'NEMDataStack': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *BPMH) RehashRecursive() { - s.StructInfo.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *BPMH) Rehash() { -} - -// WriteTo writes the BPMH into 'w' in format defined in -// the document #575623. -func (s *BPMH) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // StructInfo (ManifestFieldType: structInfo) - { - n, err := s.StructInfo.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'StructInfo': %w", err) - } - totalN += int64(n) - } - - // HdrStructVersion (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.HdrStructVersion) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'HdrStructVersion': %w", err) - } - totalN += int64(n) - } - - // PMBPMVersion (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.PMBPMVersion) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PMBPMVersion': %w", err) - } - totalN += int64(n) - } - - // BPMSVN (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.BPMSVN) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'BPMSVN': %w", err) - } - totalN += int64(n) - } - - // ACMSVNAuth (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.ACMSVNAuth) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'ACMSVNAuth': %w", err) - } - totalN += int64(n) - } - - // Reserved0 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Write(w, binary.LittleEndian, s.Reserved0[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved0': %w", err) - } - totalN += int64(n) - } - - // NEMDataStack (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.NEMDataStack) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'NEMDataStack': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// StructInfoSize returns the size in bytes of the value of field StructInfo -func (s *BPMH) StructInfoTotalSize() uint64 { - return s.StructInfo.TotalSize() -} - -// HdrStructVersionSize returns the size in bytes of the value of field HdrStructVersion -func (s *BPMH) HdrStructVersionTotalSize() uint64 { - return 1 -} - -// PMBPMVersionSize returns the size in bytes of the value of field PMBPMVersion -func (s *BPMH) PMBPMVersionTotalSize() uint64 { - return 1 -} - -// BPMSVNSize returns the size in bytes of the value of field BPMSVN -func (s *BPMH) BPMSVNTotalSize() uint64 { - return 1 -} - -// ACMSVNAuthSize returns the size in bytes of the value of field ACMSVNAuth -func (s *BPMH) ACMSVNAuthTotalSize() uint64 { - return 1 -} - -// Reserved0Size returns the size in bytes of the value of field Reserved0 -func (s *BPMH) Reserved0TotalSize() uint64 { - return 1 -} - -// NEMDataStackSize returns the size in bytes of the value of field NEMDataStack -func (s *BPMH) NEMDataStackTotalSize() uint64 { - return 2 -} - -// StructInfoOffset returns the offset in bytes of field StructInfo -func (s *BPMH) StructInfoOffset() uint64 { - return 0 -} - -// HdrStructVersionOffset returns the offset in bytes of field HdrStructVersion -func (s *BPMH) HdrStructVersionOffset() uint64 { - return s.StructInfoOffset() + s.StructInfoTotalSize() -} - -// PMBPMVersionOffset returns the offset in bytes of field PMBPMVersion -func (s *BPMH) PMBPMVersionOffset() uint64 { - return s.HdrStructVersionOffset() + s.HdrStructVersionTotalSize() -} - -// BPMSVNOffset returns the offset in bytes of field BPMSVN -func (s *BPMH) BPMSVNOffset() uint64 { - return s.PMBPMVersionOffset() + s.PMBPMVersionTotalSize() -} - -// ACMSVNAuthOffset returns the offset in bytes of field ACMSVNAuth -func (s *BPMH) ACMSVNAuthOffset() uint64 { - return s.BPMSVNOffset() + s.BPMSVNTotalSize() -} - -// Reserved0Offset returns the offset in bytes of field Reserved0 -func (s *BPMH) Reserved0Offset() uint64 { - return s.ACMSVNAuthOffset() + s.ACMSVNAuthTotalSize() -} - -// NEMDataStackOffset returns the offset in bytes of field NEMDataStack -func (s *BPMH) NEMDataStackOffset() uint64 { - return s.Reserved0Offset() + s.Reserved0TotalSize() -} - -// Size returns the total size of the BPMH. -func (s *BPMH) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.StructInfoTotalSize() - size += s.HdrStructVersionTotalSize() - size += s.PMBPMVersionTotalSize() - size += s.BPMSVNTotalSize() - size += s.ACMSVNAuthTotalSize() - size += s.Reserved0TotalSize() - size += s.NEMDataStackTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *BPMH) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "BPMH", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is structInfo - lines = append(lines, pretty.SubValue(depth+1, "Struct Info", "", &s.StructInfo, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Hdr Struct Version", "", &s.HdrStructVersion, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "PMBPM Version", "", &s.PMBPMVersion, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "BPM SVN", "", &s.BPMSVN, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "ACM SVN Auth", "", &s.ACMSVNAuth, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved 0", "", &s.Reserved0, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "NEM Data Stack", "", &s.NEMDataStack, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v Size4K) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Size 4 K", v)) - } - lines = append(lines, pretty.SubValue(depth+1, "In Bytes", "", v.InBytes(), opts...)...) - return strings.Join(lines, "\n") -} - -// TotalSize returns the total size measured through binary.Size. -func (v Size4K) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the Size4K into 'w' in binary format. -func (v Size4K) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the Size4K from 'r' in binary format. -func (v Size4K) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} diff --git a/pkg/intel/metadata/bg/bgbootpolicy/manifest.go b/pkg/intel/metadata/bg/bgbootpolicy/manifest.go deleted file mode 100644 index 67016104..00000000 --- a/pkg/intel/metadata/bg/bgbootpolicy/manifest.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package bgbootpolicy - -import ( - "bytes" - "fmt" - - pkgbytes "github.com/linuxboot/fiano/pkg/bytes" - - "github.com/linuxboot/fiano/pkg/intel/metadata/bg" - "github.com/linuxboot/fiano/pkg/uefi" -) - -// StructInfo is the common header of any element. -type StructInfo = bg.StructInfo - -// PrettyString: Boot Policy Manifest -type Manifest struct { - // PrettyString: BPMH: Header - BPMH `rehashValue:"rehashedBPMH()" json:"bpmHeader"` - // PrettyString: SE: Header - SE []SE `json:"bpmSE"` - // PrettyString: PME: Platform Manufacturer - PME *PM `json:"bpmPME,omitempty"` - // PrettyString: PMSE: Signature - PMSE Signature `json:"bpmSignature"` -} - -// StructInfo is the information about how to parse the structure. -func (bpm Manifest) StructInfo() StructInfo { - return bpm.BPMH.StructInfo -} - -// ValidateIBB returns an error if IBB segments does not match the signature -func (bpm *Manifest) ValidateIBB(firmware uefi.Firmware) error { - if bpm.SE[0].Digest.TotalSize() == 0 { - return fmt.Errorf("no IBB hashes") - } - - digest := bpm.SE[0].Digest - - h, err := digest.HashAlg.Hash() - if err != nil { - return fmt.Errorf("invalid hash function: %v", digest.HashAlg) - } - - for _, _range := range bpm.IBBDataRanges(uint64(len(firmware.Buf()))) { - if _, err := h.Write(firmware.Buf()[_range.Offset:_range.End()]); err != nil { - return fmt.Errorf("unable to hash: %w", err) - } - } - hashValue := h.Sum(nil) - - if !bytes.Equal(hashValue, digest.HashBuffer) { - return fmt.Errorf("IBB %s hash mismatch: %X != %X", digest.HashAlg, hashValue, digest.HashBuffer) - } - - return nil -} - -// IBBDataRanges returns data ranges of IBB. -func (bpm *Manifest) IBBDataRanges(firmwareSize uint64) pkgbytes.Ranges { - var result pkgbytes.Ranges - - for _, seg := range bpm.SE[0].IBBSegments { - if seg.Flags&1 == 1 { - continue - } - startIdx := calculateOffsetFromPhysAddr(uint64(seg.Base), firmwareSize) - result = append(result, pkgbytes.Range{Offset: startIdx, Length: uint64(seg.Size)}) - } - - return result -} - -// calculateOffsetFromPhysAddr calculates the offset within an image -// of the physical address (address to a region mapped from -// the SPI chip). -// -// Examples: -// -// calculateOffsetFromPhysAddr(0xffffffff, 0x1000) == 0xfff -// calculateOffsetFromPhysAddr(0xffffffc0, 0x1000) == 0xfc0 -func calculateOffsetFromPhysAddr(physAddr uint64, imageSize uint64) uint64 { - const basePhysAddr = 1 << 32 // "4GiB" - startAddr := basePhysAddr - imageSize - return physAddr - startAddr -} diff --git a/pkg/intel/metadata/bg/bgbootpolicy/manifest_manifestcodegen.go b/pkg/intel/metadata/bg/bgbootpolicy/manifest_manifestcodegen.go deleted file mode 100644 index 263b4a32..00000000 --- a/pkg/intel/metadata/bg/bgbootpolicy/manifest_manifestcodegen.go +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen -package bg github.com/linuxboot/fiano/pkg/intel/metadata/bg/bgbootpolicy - -package bgbootpolicy - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/bg" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = bg.StructInfo{} -) - -// NewManifest returns a new instance of Manifest with -// all default values set. -func NewManifest() *Manifest { - s := &Manifest{} - // Recursively initializing a child structure: - s.BPMH = *NewBPMH() - // Recursively initializing a child structure: - s.PMSE = *NewSignature() - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *Manifest) Validate() error { - // Recursively validating a child structure: - if err := s.BPMH.Validate(); err != nil { - return fmt.Errorf("error on field 'BPMH': %w", err) - } - // See tag "rehashValue" - { - expectedValue := BPMH(s.rehashedBPMH()) - if s.BPMH != expectedValue { - return fmt.Errorf("field 'BPMH' expects write-value '%v', but has %v", expectedValue, s.BPMH) - } - } - // Recursively validating a child structure: - if err := s.PMSE.Validate(); err != nil { - return fmt.Errorf("error on field 'PMSE': %w", err) - } - - return nil -} - -// fieldIndexByStructID returns the position index within -// structure Manifest of the field by its StructureID -// (see document #575623, an example of StructureID value is "__KEYM__"). -func (_ Manifest) fieldIndexByStructID(structID string) int { - switch structID { - case StructureIDBPMH: - return 0 - case StructureIDSE: - return 1 - case StructureIDPM: - return 2 - case StructureIDSignature: - return 3 - } - - return -1 -} - -// fieldNameByIndex returns the name of the field by its position number -// within structure Manifest. -func (_ Manifest) fieldNameByIndex(fieldIndex int) string { - switch fieldIndex { - case 0: - return "BPMH" - case 1: - return "SE" - case 2: - return "PME" - case 3: - return "PMSE" - } - - return fmt.Sprintf("invalidFieldIndex_%d", fieldIndex) -} - -// ReadFrom reads the Manifest from 'r' in format defined in the document #575623. -func (s *Manifest) ReadFrom(r io.Reader) (returnN int64, returnErr error) { - var missingFieldsByIndices = [4]bool{ - 0: true, - 3: true, - } - defer func() { - if returnErr != nil { - return - } - for fieldIndex, v := range missingFieldsByIndices { - if v { - returnErr = fmt.Errorf("field '%s' is missing", s.fieldNameByIndex(fieldIndex)) - break - } - } - }() - var totalN int64 - previousFieldIndex := int(-1) - for { - var structInfo bg.StructInfo - err := binary.Read(r, binary.LittleEndian, &structInfo) - if err == io.EOF || err == io.ErrUnexpectedEOF { - return totalN, nil - } - if err != nil { - return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) - } - totalN += int64(binary.Size(structInfo)) - - structID := structInfo.ID.String() - fieldIndex := s.fieldIndexByStructID(structID) - if fieldIndex < 0 { - // TODO: report error "unknown structure ID: '"+structID+"'" - continue - } - if bg.StrictOrderCheck && fieldIndex < previousFieldIndex { - return totalN, fmt.Errorf("invalid order of fields (%d < %d): structure '%s' is out of order", fieldIndex, previousFieldIndex, structID) - } - missingFieldsByIndices[fieldIndex] = false - - var n int64 - switch structID { - case StructureIDBPMH: - if fieldIndex == previousFieldIndex { - return totalN, fmt.Errorf("field 'BPMH' is not a slice, but multiple elements found") - } - s.BPMH.SetStructInfo(structInfo) - n, err = s.BPMH.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field BPMH at %d: %w", totalN, err) - } - case StructureIDSE: - var el SE - el.SetStructInfo(structInfo) - n, err = el.ReadDataFrom(r) - s.SE = append(s.SE, el) - if err != nil { - return totalN, fmt.Errorf("unable to read field SE at %d: %w", totalN, err) - } - case StructureIDPM: - if fieldIndex == previousFieldIndex { - return totalN, fmt.Errorf("field 'PME' is not a slice, but multiple elements found") - } - s.PME = &PM{} - s.PME.SetStructInfo(structInfo) - n, err = s.PME.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field PME at %d: %w", totalN, err) - } - case StructureIDSignature: - if fieldIndex == previousFieldIndex { - return totalN, fmt.Errorf("field 'PMSE' is not a slice, but multiple elements found") - } - s.PMSE.SetStructInfo(structInfo) - n, err = s.PMSE.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field PMSE at %d: %w", totalN, err) - } - default: - return totalN, fmt.Errorf("there is no field with structure ID '%s' in Manifest", structInfo.ID) - } - totalN += n - previousFieldIndex = fieldIndex - } -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *Manifest) RehashRecursive() { - s.BPMH.Rehash() - if s.PME != nil { - s.PME.Rehash() - } - s.PMSE.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *Manifest) Rehash() { - s.BPMH = BPMH(s.rehashedBPMH()) -} - -// WriteTo writes the Manifest into 'w' in format defined in -// the document #575623. -func (s *Manifest) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // BPMH (ManifestFieldType: element) - { - n, err := s.BPMH.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'BPMH': %w", err) - } - totalN += int64(n) - } - - // SE (ManifestFieldType: elementList) - { - for idx := range s.SE { - n, err := s.SE[idx].WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'SE[%d]': %w", idx, err) - } - totalN += int64(n) - } - } - - // PME (ManifestFieldType: element) - if s.PME != nil { - n, err := s.PME.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PME': %w", err) - } - totalN += int64(n) - } - - // PMSE (ManifestFieldType: element) - { - n, err := s.PMSE.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PMSE': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// BPMHSize returns the size in bytes of the value of field BPMH -func (s *Manifest) BPMHTotalSize() uint64 { - return s.BPMH.TotalSize() -} - -// SESize returns the size in bytes of the value of field SE -func (s *Manifest) SETotalSize() uint64 { - var size uint64 - for idx := range s.SE { - size += s.SE[idx].TotalSize() - } - return size -} - -// PMESize returns the size in bytes of the value of field PME -func (s *Manifest) PMETotalSize() uint64 { - return s.PME.TotalSize() -} - -// PMSESize returns the size in bytes of the value of field PMSE -func (s *Manifest) PMSETotalSize() uint64 { - return s.PMSE.TotalSize() -} - -// BPMHOffset returns the offset in bytes of field BPMH -func (s *Manifest) BPMHOffset() uint64 { - return 0 -} - -// SEOffset returns the offset in bytes of field SE -func (s *Manifest) SEOffset() uint64 { - return s.BPMHOffset() + s.BPMHTotalSize() -} - -// PMEOffset returns the offset in bytes of field PME -func (s *Manifest) PMEOffset() uint64 { - return s.SEOffset() + s.SETotalSize() -} - -// PMSEOffset returns the offset in bytes of field PMSE -func (s *Manifest) PMSEOffset() uint64 { - return s.PMEOffset() + s.PMETotalSize() -} - -// Size returns the total size of the Manifest. -func (s *Manifest) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.BPMHTotalSize() - size += s.SETotalSize() - size += s.PMETotalSize() - size += s.PMSETotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *Manifest) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Boot Policy Manifest", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is element - lines = append(lines, pretty.SubValue(depth+1, "BPMH: Header", "", &s.BPMH, opts...)...) - // ManifestFieldType is elementList - lines = append(lines, pretty.Header(depth+1, fmt.Sprintf("SE: Array of \"Boot Policy Manifest\" of length %d", len(s.SE)), s.SE)) - for i := 0; i < len(s.SE); i++ { - lines = append(lines, fmt.Sprintf("%sitem #%d: ", strings.Repeat(" ", int(depth+2)), i)+strings.TrimSpace(s.SE[i].PrettyString(depth+2, true))) - } - if depth < 1 { - lines = append(lines, "") - } - // ManifestFieldType is element - lines = append(lines, pretty.SubValue(depth+1, "PME: Platform Manufacturer", "", s.PME, opts...)...) - // ManifestFieldType is element - lines = append(lines, pretty.SubValue(depth+1, "PMSE: Signature", "", &s.PMSE, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/bg/bgbootpolicy/manifest_nocodegen.go b/pkg/intel/metadata/bg/bgbootpolicy/manifest_nocodegen.go deleted file mode 100644 index 823a427e..00000000 --- a/pkg/intel/metadata/bg/bgbootpolicy/manifest_nocodegen.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// -// To avoid errors "bpm.KeySignatureOffsetTotalSize undefined" and -// "bpm.BPMH.PrettyString undefined" we place these functions to a file -// with a build tag "!manifestcodegen" - -package bgbootpolicy - -import ( - "fmt" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -func (bpm *Manifest) rehashedBPMH() BPMH { - return bpm.BPMH -} - -// Print prints the Manifest -func (bpm Manifest) Print() { - fmt.Printf("%v", bpm.BPMH.PrettyString(1, true)) - for _, item := range bpm.SE { - fmt.Printf("%v", item.PrettyString(1, true)) - } - - if bpm.PME != nil { - fmt.Printf("%v\n", bpm.PME.PrettyString(1, true)) - } else { - fmt.Println(" --PME--\n\tnot set!(optional)") - } - - if bpm.PMSE.Signature.DataTotalSize() < 1 { - fmt.Printf("%v\n", bpm.PMSE.PrettyString(1, true, pretty.OptionOmitKeySignature(true))) - fmt.Printf(" --PMSE--\n\tBoot Policy Manifest not signed!\n\n") - } else { - fmt.Printf("%v\n", bpm.PMSE.PrettyString(1, true, pretty.OptionOmitKeySignature(false))) - } -} diff --git a/pkg/intel/metadata/bg/bgbootpolicy/manifest_test.go b/pkg/intel/metadata/bg/bgbootpolicy/manifest_test.go deleted file mode 100644 index 7c7139b4..00000000 --- a/pkg/intel/metadata/bg/bgbootpolicy/manifest_test.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package bgbootpolicy - -import ( - "testing" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/unittest" -) - -func TestReadWrite(t *testing.T) { - unittest.BGManifestReadWrite(t, &Manifest{}, "testdata/bpm.bin") - unittest.BGManifestReadWrite(t, &Manifest{}, "testdata/bpm2.bin") - unittest.BGManifestReadWrite(t, &Manifest{}, "testdata/bpm3.bin") -} diff --git a/pkg/intel/metadata/bg/bgbootpolicy/pm.go b/pkg/intel/metadata/bg/bgbootpolicy/pm.go deleted file mode 100644 index 1ff19427..00000000 --- a/pkg/intel/metadata/bg/bgbootpolicy/pm.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package bgbootpolicy - -type PM struct { - StructInfo `id:"__PMDA__" version:"0x10"` - DataSize uint16 `json:"pcDataSize"` - Data []byte `json:"pcData"` -} diff --git a/pkg/intel/metadata/bg/bgbootpolicy/pm_manifestcodegen.go b/pkg/intel/metadata/bg/bgbootpolicy/pm_manifestcodegen.go deleted file mode 100644 index 8ed47f54..00000000 --- a/pkg/intel/metadata/bg/bgbootpolicy/pm_manifestcodegen.go +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen -package bg github.com/linuxboot/fiano/pkg/intel/metadata/bg/bgbootpolicy - -package bgbootpolicy - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/bg" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = bg.StructInfo{} -) - -// NewPM returns a new instance of PM with -// all default values set. -func NewPM() *PM { - s := &PM{} - copy(s.StructInfo.ID[:], []byte(StructureIDPM)) - s.StructInfo.Version = 0x10 - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *PM) Validate() error { - - return nil -} - -// StructureIDPM is the StructureID (in terms of -// the document #575623) of element 'PM'. -const StructureIDPM = "__PMDA__" - -// GetStructInfo returns current value of StructInfo of the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *PM) GetStructInfo() bg.StructInfo { - return s.StructInfo -} - -// SetStructInfo sets new value of StructInfo to the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *PM) SetStructInfo(newStructInfo bg.StructInfo) { - s.StructInfo = newStructInfo -} - -// ReadFrom reads the PM from 'r' in format defined in the document #575623. -func (s *PM) ReadFrom(r io.Reader) (int64, error) { - var totalN int64 - - err := binary.Read(r, binary.LittleEndian, &s.StructInfo) - if err != nil { - return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) - } - totalN += int64(binary.Size(s.StructInfo)) - - n, err := s.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read data: %w", err) - } - totalN += n - - return totalN, nil -} - -// ReadDataFrom reads the PM from 'r' excluding StructInfo, -// in format defined in the document #575623. -func (s *PM) ReadDataFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // StructInfo (ManifestFieldType: structInfo) - { - // ReadDataFrom does not read Struct, use ReadFrom for that. - } - - // DataSize (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.DataSize) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'DataSize': %w", err) - } - totalN += int64(n) - } - - // Data (ManifestFieldType: arrayDynamic) - { - var size uint16 - err := binary.Read(r, binary.LittleEndian, &size) - if err != nil { - return totalN, fmt.Errorf("unable to the read size of field 'Data': %w", err) - } - totalN += int64(binary.Size(size)) - s.Data = make([]byte, size) - n, err := len(s.Data), binary.Read(r, binary.LittleEndian, s.Data) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Data': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *PM) RehashRecursive() { - s.StructInfo.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *PM) Rehash() { -} - -// WriteTo writes the PM into 'w' in format defined in -// the document #575623. -func (s *PM) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // StructInfo (ManifestFieldType: structInfo) - { - n, err := s.StructInfo.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'StructInfo': %w", err) - } - totalN += int64(n) - } - - // DataSize (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.DataSize) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'DataSize': %w", err) - } - totalN += int64(n) - } - - // Data (ManifestFieldType: arrayDynamic) - { - size := uint16(len(s.Data)) - err := binary.Write(w, binary.LittleEndian, size) - if err != nil { - return totalN, fmt.Errorf("unable to write the size of field 'Data': %w", err) - } - totalN += int64(binary.Size(size)) - n, err := len(s.Data), binary.Write(w, binary.LittleEndian, s.Data) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Data': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// StructInfoSize returns the size in bytes of the value of field StructInfo -func (s *PM) StructInfoTotalSize() uint64 { - return s.StructInfo.TotalSize() -} - -// DataSizeSize returns the size in bytes of the value of field DataSize -func (s *PM) DataSizeTotalSize() uint64 { - return 2 -} - -// DataSize returns the size in bytes of the value of field Data -func (s *PM) DataTotalSize() uint64 { - size := uint64(binary.Size(uint16(0))) - size += uint64(len(s.Data)) - return size -} - -// StructInfoOffset returns the offset in bytes of field StructInfo -func (s *PM) StructInfoOffset() uint64 { - return 0 -} - -// DataSizeOffset returns the offset in bytes of field DataSize -func (s *PM) DataSizeOffset() uint64 { - return s.StructInfoOffset() + s.StructInfoTotalSize() -} - -// DataOffset returns the offset in bytes of field Data -func (s *PM) DataOffset() uint64 { - return s.DataSizeOffset() + s.DataSizeTotalSize() -} - -// Size returns the total size of the PM. -func (s *PM) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.StructInfoTotalSize() - size += s.DataSizeTotalSize() - size += s.DataTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *PM) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "PM", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is structInfo - lines = append(lines, pretty.SubValue(depth+1, "Struct Info", "", &s.StructInfo, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Data Size", "", &s.DataSize, opts...)...) - // ManifestFieldType is arrayDynamic - lines = append(lines, pretty.SubValue(depth+1, "Data", "", &s.Data, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/bg/bgbootpolicy/se.go b/pkg/intel/metadata/bg/bgbootpolicy/se.go deleted file mode 100644 index 4490445e..00000000 --- a/pkg/intel/metadata/bg/bgbootpolicy/se.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package bgbootpolicy - -import ( - "fmt" - "math" - "time" - - "github.com/linuxboot/fiano/pkg/intel/metadata/bg" -) - -// PrettyString: IBB Segments Element -type SE struct { - StructInfo `id:"__IBBS__" version:"0x10"` - Reserved0 [1]byte `require:"0" json:"seReserved0,omitempty"` - Reserved1 [1]byte `require:"0" json:"seReserved1,omitempty"` - PBETValue PBETValue `json:"sePBETValue"` - Flags SEFlags `json:"seFlags"` - // PrettyString: IBB MCHBAR - IBBMCHBAR uint64 `json:"seIBBMCHBAR"` - // PrettyString: VT-d BAR - VTdBAR uint64 `json:"seVTdBAR"` - // PrettyString: DMA Protection 0 Base Address - PMRLBase uint32 `json:"seDMAProtBase0"` - // PrettyString: DMA Protection 0 Limit Address - PMRLLimit uint32 `json:"seDMAProtLimit0"` - // PrettyString: DMA Protection 1 Base Address - Reserved2 [8]byte `json:"seDMAProtBase1"` - // PrettyString: DMA Protection 2 Limit Address - Reserved3 [8]byte `json:"seDMAProtLimit1"` - - PostIBBHash bg.HashStructureFill `json:"sePostIBBHash"` - - IBBEntryPoint uint32 `json:"seIBBEntry"` - - Digest bg.HashStructure `json:"seDigestList"` - - IBBSegments []IBBSegment `countType:"uint8" json:"seIBBSegments,omitempty"` -} - -type PBETValue uint8 - -// PBETValue returns the raw value of the timer setting. -func (pbet PBETValue) PBETValue() uint8 { - return uint8(pbet) & 0x0f -} - -// Duration returns the value as time.Duration. -func (pbet PBETValue) Duration() time.Duration { - v := pbet.PBETValue() - if v == 0 { - return math.MaxInt64 - } - return time.Second * time.Duration(5+v) -} - -func (pbet *PBETValue) SetDuration(duration time.Duration) time.Duration { - v := duration.Nanoseconds()/time.Second.Nanoseconds() - 5 - if v <= 0 { - v = 1 - } - if v >= 16 { - v = 0 - } - *pbet = PBETValue(v) - - return pbet.Duration() -} - -type SEFlags uint32 - -func (flags SEFlags) Reserved0() uint32 { - return uint32(flags & 0xffffffe0) -} - -// PrettyString-true: BIOS supports Top Swap remediation action -// PrettyString-false: BIOS does not support Top Swap remediation action -func (flags SEFlags) SupportsTopSwapRemediation() bool { - return flags&0x10 != 0 -} - -// PrettyString-true: Leave Hierarchies enabled. Cap all PCRs on failure. -// PrettyString-false: Do not leave enabled. Disable all Hierarchies or deactivate on failure. -func (flags SEFlags) TPMFailureLeavesHierarchiesEnabled() bool { - return flags&0x08 != 0 -} - -// PrettyString-true: Extend Authority Measurements into the Authority PCR 7 -// PrettyString-false: Do not extend into the Authority PCR 7 -func (flags SEFlags) AuthorityMeasure() bool { - return flags&0x04 != 0 -} - -// PrettyString-true: Issue TPM Start-up from Locality 3 -// PrettyString-false: Disabled -func (flags SEFlags) Locality3Startup() bool { - return flags&0x02 != 0 -} - -// PrettyString-true: Enable DMA Protection -// PrettyString-false: Disable DMA Protection -func (flags SEFlags) DMAProtection() bool { - return flags&0x01 != 0 -} - -type IBBSegment struct { - Reserved [2]byte `require:"0" json:"ibbSegReserved"` - Flags uint16 `json:"ibbSegFlags"` - Base uint32 `json:"ibbSegBase"` - Size uint32 `json:"ibbSegSize"` -} - -type CachingType uint8 - -const ( - CachingTypeWriteProtect = CachingType(iota) - CachingTypeWriteBack - CachingTypeReserved0 - CachingTypeReserved1 -) - -// String implements fmt.Stringer. -func (c CachingType) String() string { - switch c { - case CachingTypeWriteProtect: - return "write_protect" - case CachingTypeWriteBack: - return "write_back" - case CachingTypeReserved0: - return "value_0x02" - case CachingTypeReserved1: - return "value_0x03" - } - return fmt.Sprintf("unexpected_value_0x%02X", uint8(c)) -} diff --git a/pkg/intel/metadata/bg/bgbootpolicy/se_manifestcodegen.go b/pkg/intel/metadata/bg/bgbootpolicy/se_manifestcodegen.go deleted file mode 100644 index dc315619..00000000 --- a/pkg/intel/metadata/bg/bgbootpolicy/se_manifestcodegen.go +++ /dev/null @@ -1,947 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen -package bg github.com/linuxboot/fiano/pkg/intel/metadata/bg/bgbootpolicy - -package bgbootpolicy - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/bg" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = bg.StructInfo{} -) - -// NewIBBSegment returns a new instance of IBBSegment with -// all default values set. -func NewIBBSegment() *IBBSegment { - s := &IBBSegment{} - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *IBBSegment) Validate() error { - // See tag "require" - for idx := range s.Reserved { - if s.Reserved[idx] != 0 { - return fmt.Errorf("'Reserved[%d]' is expected to be 0, but it is %v", idx, s.Reserved[idx]) - } - } - - return nil -} - -// ReadFrom reads the IBBSegment from 'r' in format defined in the document #575623. -func (s *IBBSegment) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // Reserved (ManifestFieldType: arrayStatic) - { - n, err := 2, binary.Read(r, binary.LittleEndian, s.Reserved[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved': %w", err) - } - totalN += int64(n) - } - - // Flags (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.Flags) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Flags': %w", err) - } - totalN += int64(n) - } - - // Base (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.Base) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Base': %w", err) - } - totalN += int64(n) - } - - // Size (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.Size) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Size': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *IBBSegment) RehashRecursive() { - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *IBBSegment) Rehash() { -} - -// WriteTo writes the IBBSegment into 'w' in format defined in -// the document #575623. -func (s *IBBSegment) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // Reserved (ManifestFieldType: arrayStatic) - { - n, err := 2, binary.Write(w, binary.LittleEndian, s.Reserved[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved': %w", err) - } - totalN += int64(n) - } - - // Flags (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.Flags) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Flags': %w", err) - } - totalN += int64(n) - } - - // Base (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.Base) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Base': %w", err) - } - totalN += int64(n) - } - - // Size (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.Size) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Size': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// ReservedSize returns the size in bytes of the value of field Reserved -func (s *IBBSegment) ReservedTotalSize() uint64 { - return 2 -} - -// FlagsSize returns the size in bytes of the value of field Flags -func (s *IBBSegment) FlagsTotalSize() uint64 { - return 2 -} - -// BaseSize returns the size in bytes of the value of field Base -func (s *IBBSegment) BaseTotalSize() uint64 { - return 4 -} - -// SizeSize returns the size in bytes of the value of field Size -func (s *IBBSegment) SizeTotalSize() uint64 { - return 4 -} - -// ReservedOffset returns the offset in bytes of field Reserved -func (s *IBBSegment) ReservedOffset() uint64 { - return 0 -} - -// FlagsOffset returns the offset in bytes of field Flags -func (s *IBBSegment) FlagsOffset() uint64 { - return s.ReservedOffset() + s.ReservedTotalSize() -} - -// BaseOffset returns the offset in bytes of field Base -func (s *IBBSegment) BaseOffset() uint64 { - return s.FlagsOffset() + s.FlagsTotalSize() -} - -// SizeOffset returns the offset in bytes of field Size -func (s *IBBSegment) SizeOffset() uint64 { - return s.BaseOffset() + s.BaseTotalSize() -} - -// Size returns the total size of the IBBSegment. -func (s *IBBSegment) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.ReservedTotalSize() - size += s.FlagsTotalSize() - size += s.BaseTotalSize() - size += s.SizeTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *IBBSegment) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "IBB Segment", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved", "", &s.Reserved, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Flags", "", &s.Flags, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Base", "", &s.Base, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Size", "", &s.Size, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} - -// NewSE returns a new instance of SE with -// all default values set. -func NewSE() *SE { - s := &SE{} - copy(s.StructInfo.ID[:], []byte(StructureIDSE)) - s.StructInfo.Version = 0x10 - // Recursively initializing a child structure: - s.PostIBBHash = *bg.NewHashStructureFill() - // Recursively initializing a child structure: - s.Digest = *bg.NewHashStructure() - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *SE) Validate() error { - // See tag "require" - for idx := range s.Reserved0 { - if s.Reserved0[idx] != 0 { - return fmt.Errorf("'Reserved0[%d]' is expected to be 0, but it is %v", idx, s.Reserved0[idx]) - } - } - // See tag "require" - for idx := range s.Reserved1 { - if s.Reserved1[idx] != 0 { - return fmt.Errorf("'Reserved1[%d]' is expected to be 0, but it is %v", idx, s.Reserved1[idx]) - } - } - // Recursively validating a child structure: - if err := s.PostIBBHash.Validate(); err != nil { - return fmt.Errorf("error on field 'PostIBBHash': %w", err) - } - // Recursively validating a child structure: - if err := s.Digest.Validate(); err != nil { - return fmt.Errorf("error on field 'Digest': %w", err) - } - - return nil -} - -// StructureIDSE is the StructureID (in terms of -// the document #575623) of element 'SE'. -const StructureIDSE = "__IBBS__" - -// GetStructInfo returns current value of StructInfo of the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *SE) GetStructInfo() bg.StructInfo { - return s.StructInfo -} - -// SetStructInfo sets new value of StructInfo to the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *SE) SetStructInfo(newStructInfo bg.StructInfo) { - s.StructInfo = newStructInfo -} - -// ReadFrom reads the SE from 'r' in format defined in the document #575623. -func (s *SE) ReadFrom(r io.Reader) (int64, error) { - var totalN int64 - - err := binary.Read(r, binary.LittleEndian, &s.StructInfo) - if err != nil { - return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) - } - totalN += int64(binary.Size(s.StructInfo)) - - n, err := s.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read data: %w", err) - } - totalN += n - - return totalN, nil -} - -// ReadDataFrom reads the SE from 'r' excluding StructInfo, -// in format defined in the document #575623. -func (s *SE) ReadDataFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // StructInfo (ManifestFieldType: structInfo) - { - // ReadDataFrom does not read Struct, use ReadFrom for that. - } - - // Reserved0 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Read(r, binary.LittleEndian, s.Reserved0[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved0': %w", err) - } - totalN += int64(n) - } - - // Reserved1 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Read(r, binary.LittleEndian, s.Reserved1[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved1': %w", err) - } - totalN += int64(n) - } - - // PBETValue (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.PBETValue) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'PBETValue': %w", err) - } - totalN += int64(n) - } - - // Flags (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.Flags) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Flags': %w", err) - } - totalN += int64(n) - } - - // IBBMCHBAR (ManifestFieldType: endValue) - { - n, err := 8, binary.Read(r, binary.LittleEndian, &s.IBBMCHBAR) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'IBBMCHBAR': %w", err) - } - totalN += int64(n) - } - - // VTdBAR (ManifestFieldType: endValue) - { - n, err := 8, binary.Read(r, binary.LittleEndian, &s.VTdBAR) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'VTdBAR': %w", err) - } - totalN += int64(n) - } - - // PMRLBase (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.PMRLBase) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'PMRLBase': %w", err) - } - totalN += int64(n) - } - - // PMRLLimit (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.PMRLLimit) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'PMRLLimit': %w", err) - } - totalN += int64(n) - } - - // Reserved2 (ManifestFieldType: arrayStatic) - { - n, err := 8, binary.Read(r, binary.LittleEndian, s.Reserved2[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved2': %w", err) - } - totalN += int64(n) - } - - // Reserved3 (ManifestFieldType: arrayStatic) - { - n, err := 8, binary.Read(r, binary.LittleEndian, s.Reserved3[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved3': %w", err) - } - totalN += int64(n) - } - - // PostIBBHash (ManifestFieldType: subStruct) - { - n, err := s.PostIBBHash.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'PostIBBHash': %w", err) - } - totalN += int64(n) - } - - // IBBEntryPoint (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.IBBEntryPoint) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'IBBEntryPoint': %w", err) - } - totalN += int64(n) - } - - // Digest (ManifestFieldType: subStruct) - { - n, err := s.Digest.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Digest': %w", err) - } - totalN += int64(n) - } - - // IBBSegments (ManifestFieldType: list) - { - var count uint8 - err := binary.Read(r, binary.LittleEndian, &count) - if err != nil { - return totalN, fmt.Errorf("unable to read the count for field 'IBBSegments': %w", err) - } - totalN += int64(binary.Size(count)) - s.IBBSegments = make([]IBBSegment, count) - - for idx := range s.IBBSegments { - n, err := s.IBBSegments[idx].ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'IBBSegments[%d]': %w", idx, err) - } - totalN += int64(n) - } - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *SE) RehashRecursive() { - s.StructInfo.Rehash() - s.PostIBBHash.Rehash() - s.Digest.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *SE) Rehash() { -} - -// WriteTo writes the SE into 'w' in format defined in -// the document #575623. -func (s *SE) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // StructInfo (ManifestFieldType: structInfo) - { - n, err := s.StructInfo.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'StructInfo': %w", err) - } - totalN += int64(n) - } - - // Reserved0 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Write(w, binary.LittleEndian, s.Reserved0[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved0': %w", err) - } - totalN += int64(n) - } - - // Reserved1 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Write(w, binary.LittleEndian, s.Reserved1[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved1': %w", err) - } - totalN += int64(n) - } - - // PBETValue (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.PBETValue) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PBETValue': %w", err) - } - totalN += int64(n) - } - - // Flags (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.Flags) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Flags': %w", err) - } - totalN += int64(n) - } - - // IBBMCHBAR (ManifestFieldType: endValue) - { - n, err := 8, binary.Write(w, binary.LittleEndian, &s.IBBMCHBAR) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'IBBMCHBAR': %w", err) - } - totalN += int64(n) - } - - // VTdBAR (ManifestFieldType: endValue) - { - n, err := 8, binary.Write(w, binary.LittleEndian, &s.VTdBAR) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'VTdBAR': %w", err) - } - totalN += int64(n) - } - - // PMRLBase (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.PMRLBase) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PMRLBase': %w", err) - } - totalN += int64(n) - } - - // PMRLLimit (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.PMRLLimit) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PMRLLimit': %w", err) - } - totalN += int64(n) - } - - // Reserved2 (ManifestFieldType: arrayStatic) - { - n, err := 8, binary.Write(w, binary.LittleEndian, s.Reserved2[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved2': %w", err) - } - totalN += int64(n) - } - - // Reserved3 (ManifestFieldType: arrayStatic) - { - n, err := 8, binary.Write(w, binary.LittleEndian, s.Reserved3[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved3': %w", err) - } - totalN += int64(n) - } - - // PostIBBHash (ManifestFieldType: subStruct) - { - n, err := s.PostIBBHash.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PostIBBHash': %w", err) - } - totalN += int64(n) - } - - // IBBEntryPoint (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.IBBEntryPoint) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'IBBEntryPoint': %w", err) - } - totalN += int64(n) - } - - // Digest (ManifestFieldType: subStruct) - { - n, err := s.Digest.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Digest': %w", err) - } - totalN += int64(n) - } - - // IBBSegments (ManifestFieldType: list) - { - count := uint8(len(s.IBBSegments)) - err := binary.Write(w, binary.LittleEndian, &count) - if err != nil { - return totalN, fmt.Errorf("unable to write the count for field 'IBBSegments': %w", err) - } - totalN += int64(binary.Size(count)) - for idx := range s.IBBSegments { - n, err := s.IBBSegments[idx].WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'IBBSegments[%d]': %w", idx, err) - } - totalN += int64(n) - } - } - - return totalN, nil -} - -// StructInfoSize returns the size in bytes of the value of field StructInfo -func (s *SE) StructInfoTotalSize() uint64 { - return s.StructInfo.TotalSize() -} - -// Reserved0Size returns the size in bytes of the value of field Reserved0 -func (s *SE) Reserved0TotalSize() uint64 { - return 1 -} - -// Reserved1Size returns the size in bytes of the value of field Reserved1 -func (s *SE) Reserved1TotalSize() uint64 { - return 1 -} - -// PBETValueSize returns the size in bytes of the value of field PBETValue -func (s *SE) PBETValueTotalSize() uint64 { - return 1 -} - -// FlagsSize returns the size in bytes of the value of field Flags -func (s *SE) FlagsTotalSize() uint64 { - return 4 -} - -// IBBMCHBARSize returns the size in bytes of the value of field IBBMCHBAR -func (s *SE) IBBMCHBARTotalSize() uint64 { - return 8 -} - -// VTdBARSize returns the size in bytes of the value of field VTdBAR -func (s *SE) VTdBARTotalSize() uint64 { - return 8 -} - -// PMRLBaseSize returns the size in bytes of the value of field PMRLBase -func (s *SE) PMRLBaseTotalSize() uint64 { - return 4 -} - -// PMRLLimitSize returns the size in bytes of the value of field PMRLLimit -func (s *SE) PMRLLimitTotalSize() uint64 { - return 4 -} - -// Reserved2Size returns the size in bytes of the value of field Reserved2 -func (s *SE) Reserved2TotalSize() uint64 { - return 8 -} - -// Reserved3Size returns the size in bytes of the value of field Reserved3 -func (s *SE) Reserved3TotalSize() uint64 { - return 8 -} - -// PostIBBHashSize returns the size in bytes of the value of field PostIBBHash -func (s *SE) PostIBBHashTotalSize() uint64 { - return s.PostIBBHash.TotalSize() -} - -// IBBEntryPointSize returns the size in bytes of the value of field IBBEntryPoint -func (s *SE) IBBEntryPointTotalSize() uint64 { - return 4 -} - -// DigestSize returns the size in bytes of the value of field Digest -func (s *SE) DigestTotalSize() uint64 { - return s.Digest.TotalSize() -} - -// IBBSegmentsSize returns the size in bytes of the value of field IBBSegments -func (s *SE) IBBSegmentsTotalSize() uint64 { - var size uint64 - size += uint64(binary.Size(uint8(0))) - for idx := range s.IBBSegments { - size += s.IBBSegments[idx].TotalSize() - } - return size -} - -// StructInfoOffset returns the offset in bytes of field StructInfo -func (s *SE) StructInfoOffset() uint64 { - return 0 -} - -// Reserved0Offset returns the offset in bytes of field Reserved0 -func (s *SE) Reserved0Offset() uint64 { - return s.StructInfoOffset() + s.StructInfoTotalSize() -} - -// Reserved1Offset returns the offset in bytes of field Reserved1 -func (s *SE) Reserved1Offset() uint64 { - return s.Reserved0Offset() + s.Reserved0TotalSize() -} - -// PBETValueOffset returns the offset in bytes of field PBETValue -func (s *SE) PBETValueOffset() uint64 { - return s.Reserved1Offset() + s.Reserved1TotalSize() -} - -// FlagsOffset returns the offset in bytes of field Flags -func (s *SE) FlagsOffset() uint64 { - return s.PBETValueOffset() + s.PBETValueTotalSize() -} - -// IBBMCHBAROffset returns the offset in bytes of field IBBMCHBAR -func (s *SE) IBBMCHBAROffset() uint64 { - return s.FlagsOffset() + s.FlagsTotalSize() -} - -// VTdBAROffset returns the offset in bytes of field VTdBAR -func (s *SE) VTdBAROffset() uint64 { - return s.IBBMCHBAROffset() + s.IBBMCHBARTotalSize() -} - -// PMRLBaseOffset returns the offset in bytes of field PMRLBase -func (s *SE) PMRLBaseOffset() uint64 { - return s.VTdBAROffset() + s.VTdBARTotalSize() -} - -// PMRLLimitOffset returns the offset in bytes of field PMRLLimit -func (s *SE) PMRLLimitOffset() uint64 { - return s.PMRLBaseOffset() + s.PMRLBaseTotalSize() -} - -// Reserved2Offset returns the offset in bytes of field Reserved2 -func (s *SE) Reserved2Offset() uint64 { - return s.PMRLLimitOffset() + s.PMRLLimitTotalSize() -} - -// Reserved3Offset returns the offset in bytes of field Reserved3 -func (s *SE) Reserved3Offset() uint64 { - return s.Reserved2Offset() + s.Reserved2TotalSize() -} - -// PostIBBHashOffset returns the offset in bytes of field PostIBBHash -func (s *SE) PostIBBHashOffset() uint64 { - return s.Reserved3Offset() + s.Reserved3TotalSize() -} - -// IBBEntryPointOffset returns the offset in bytes of field IBBEntryPoint -func (s *SE) IBBEntryPointOffset() uint64 { - return s.PostIBBHashOffset() + s.PostIBBHashTotalSize() -} - -// DigestOffset returns the offset in bytes of field Digest -func (s *SE) DigestOffset() uint64 { - return s.IBBEntryPointOffset() + s.IBBEntryPointTotalSize() -} - -// IBBSegmentsOffset returns the offset in bytes of field IBBSegments -func (s *SE) IBBSegmentsOffset() uint64 { - return s.DigestOffset() + s.DigestTotalSize() -} - -// Size returns the total size of the SE. -func (s *SE) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.StructInfoTotalSize() - size += s.Reserved0TotalSize() - size += s.Reserved1TotalSize() - size += s.PBETValueTotalSize() - size += s.FlagsTotalSize() - size += s.IBBMCHBARTotalSize() - size += s.VTdBARTotalSize() - size += s.PMRLBaseTotalSize() - size += s.PMRLLimitTotalSize() - size += s.Reserved2TotalSize() - size += s.Reserved3TotalSize() - size += s.PostIBBHashTotalSize() - size += s.IBBEntryPointTotalSize() - size += s.DigestTotalSize() - size += s.IBBSegmentsTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *SE) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "IBB Segments Element", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is structInfo - lines = append(lines, pretty.SubValue(depth+1, "Struct Info", "", &s.StructInfo, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved 0", "", &s.Reserved0, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved 1", "", &s.Reserved1, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "PBET Value", "", &s.PBETValue, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Flags", "", &s.Flags, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "IBB MCHBAR", "", &s.IBBMCHBAR, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "VT-d BAR", "", &s.VTdBAR, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "DMA Protection 0 Base Address", "", &s.PMRLBase, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "DMA Protection 0 Limit Address", "", &s.PMRLLimit, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "DMA Protection 1 Base Address", "", &s.Reserved2, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "DMA Protection 2 Limit Address", "", &s.Reserved3, opts...)...) - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "Post IBB Hash", "", &s.PostIBBHash, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "IBB Entry Point", "", &s.IBBEntryPoint, opts...)...) - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "Digest", "", &s.Digest, opts...)...) - // ManifestFieldType is list - lines = append(lines, pretty.Header(depth+1, fmt.Sprintf("IBBSegments: Array of \"IBB Segments Element\" of length %d", len(s.IBBSegments)), s.IBBSegments)) - for i := 0; i < len(s.IBBSegments); i++ { - lines = append(lines, fmt.Sprintf("%sitem #%d: ", strings.Repeat(" ", int(depth+2)), i)+strings.TrimSpace(s.IBBSegments[i].PrettyString(depth+2, true))) - } - if depth < 1 { - lines = append(lines, "") - } - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v CachingType) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - return v.String() -} - -// TotalSize returns the total size measured through binary.Size. -func (v CachingType) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the CachingType into 'w' in binary format. -func (v CachingType) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the CachingType from 'r' in binary format. -func (v CachingType) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v PBETValue) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "PBET Value", v)) - } - lines = append(lines, pretty.SubValue(depth+1, "PBET Value", "", v.PBETValue(), opts...)...) - return strings.Join(lines, "\n") -} - -// TotalSize returns the total size measured through binary.Size. -func (v PBETValue) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the PBETValue into 'w' in binary format. -func (v PBETValue) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the PBETValue from 'r' in binary format. -func (v PBETValue) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v SEFlags) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "SE Flags", v)) - } - lines = append(lines, pretty.SubValue(depth+1, "Reserved 0", "", v.Reserved0(), opts...)...) - if v.SupportsTopSwapRemediation() { - lines = append(lines, pretty.SubValue(depth+1, "Supports Top Swap Remediation", "BIOS supports Top Swap remediation action", true, opts...)...) - } else { - lines = append(lines, pretty.SubValue(depth+1, "Supports Top Swap Remediation", "BIOS does not support Top Swap remediation action", false, opts...)...) - } - if v.TPMFailureLeavesHierarchiesEnabled() { - lines = append(lines, pretty.SubValue(depth+1, "TPM Failure Leaves Hierarchies Enabled", "Leave Hierarchies enabled. Cap all PCRs on failure.", true, opts...)...) - } else { - lines = append(lines, pretty.SubValue(depth+1, "TPM Failure Leaves Hierarchies Enabled", "Do not leave enabled. Disable all Hierarchies or deactivate on failure.", false, opts...)...) - } - if v.AuthorityMeasure() { - lines = append(lines, pretty.SubValue(depth+1, "Authority Measure", "Extend Authority Measurements into the Authority PCR 7", true, opts...)...) - } else { - lines = append(lines, pretty.SubValue(depth+1, "Authority Measure", "Do not extend into the Authority PCR 7", false, opts...)...) - } - if v.Locality3Startup() { - lines = append(lines, pretty.SubValue(depth+1, "Locality 3 Startup", "Issue TPM Start-up from Locality 3", true, opts...)...) - } else { - lines = append(lines, pretty.SubValue(depth+1, "Locality 3 Startup", "Disabled", false, opts...)...) - } - if v.DMAProtection() { - lines = append(lines, pretty.SubValue(depth+1, "DMA Protection", "Enable DMA Protection", true, opts...)...) - } else { - lines = append(lines, pretty.SubValue(depth+1, "DMA Protection", "Disable DMA Protection", false, opts...)...) - } - return strings.Join(lines, "\n") -} - -// TotalSize returns the total size measured through binary.Size. -func (v SEFlags) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the SEFlags into 'w' in binary format. -func (v SEFlags) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the SEFlags from 'r' in binary format. -func (v SEFlags) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} diff --git a/pkg/intel/metadata/bg/bgbootpolicy/signature.go b/pkg/intel/metadata/bg/bgbootpolicy/signature.go deleted file mode 100644 index 8e971f73..00000000 --- a/pkg/intel/metadata/bg/bgbootpolicy/signature.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package bgbootpolicy - -import "github.com/linuxboot/fiano/pkg/intel/metadata/bg" - -// Signature contains the signature of the BPM. -type Signature struct { - StructInfo `id:"__PMSG__" version:"0x10"` - bg.KeySignature `json:"sigKeySignature"` -} diff --git a/pkg/intel/metadata/bg/bgbootpolicy/signature_manifestcodegen.go b/pkg/intel/metadata/bg/bgbootpolicy/signature_manifestcodegen.go deleted file mode 100644 index f3ee9732..00000000 --- a/pkg/intel/metadata/bg/bgbootpolicy/signature_manifestcodegen.go +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen -package bg github.com/linuxboot/fiano/pkg/intel/metadata/bg/bgbootpolicy - -package bgbootpolicy - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/bg" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = bg.StructInfo{} -) - -// NewSignature returns a new instance of Signature with -// all default values set. -func NewSignature() *Signature { - s := &Signature{} - copy(s.StructInfo.ID[:], []byte(StructureIDSignature)) - s.StructInfo.Version = 0x10 - // Recursively initializing a child structure: - s.KeySignature = *bg.NewKeySignature() - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *Signature) Validate() error { - // Recursively validating a child structure: - if err := s.KeySignature.Validate(); err != nil { - return fmt.Errorf("error on field 'KeySignature': %w", err) - } - - return nil -} - -// StructureIDSignature is the StructureID (in terms of -// the document #575623) of element 'Signature'. -const StructureIDSignature = "__PMSG__" - -// GetStructInfo returns current value of StructInfo of the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *Signature) GetStructInfo() bg.StructInfo { - return s.StructInfo -} - -// SetStructInfo sets new value of StructInfo to the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *Signature) SetStructInfo(newStructInfo bg.StructInfo) { - s.StructInfo = newStructInfo -} - -// ReadFrom reads the Signature from 'r' in format defined in the document #575623. -func (s *Signature) ReadFrom(r io.Reader) (int64, error) { - var totalN int64 - - err := binary.Read(r, binary.LittleEndian, &s.StructInfo) - if err != nil { - return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) - } - totalN += int64(binary.Size(s.StructInfo)) - - n, err := s.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read data: %w", err) - } - totalN += n - - return totalN, nil -} - -// ReadDataFrom reads the Signature from 'r' excluding StructInfo, -// in format defined in the document #575623. -func (s *Signature) ReadDataFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // StructInfo (ManifestFieldType: structInfo) - { - // ReadDataFrom does not read Struct, use ReadFrom for that. - } - - // KeySignature (ManifestFieldType: subStruct) - { - n, err := s.KeySignature.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'KeySignature': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *Signature) RehashRecursive() { - s.StructInfo.Rehash() - s.KeySignature.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *Signature) Rehash() { -} - -// WriteTo writes the Signature into 'w' in format defined in -// the document #575623. -func (s *Signature) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // StructInfo (ManifestFieldType: structInfo) - { - n, err := s.StructInfo.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'StructInfo': %w", err) - } - totalN += int64(n) - } - - // KeySignature (ManifestFieldType: subStruct) - { - n, err := s.KeySignature.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'KeySignature': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// StructInfoSize returns the size in bytes of the value of field StructInfo -func (s *Signature) StructInfoTotalSize() uint64 { - return s.StructInfo.TotalSize() -} - -// KeySignatureSize returns the size in bytes of the value of field KeySignature -func (s *Signature) KeySignatureTotalSize() uint64 { - return s.KeySignature.TotalSize() -} - -// StructInfoOffset returns the offset in bytes of field StructInfo -func (s *Signature) StructInfoOffset() uint64 { - return 0 -} - -// KeySignatureOffset returns the offset in bytes of field KeySignature -func (s *Signature) KeySignatureOffset() uint64 { - return s.StructInfoOffset() + s.StructInfoTotalSize() -} - -// Size returns the total size of the Signature. -func (s *Signature) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.StructInfoTotalSize() - size += s.KeySignatureTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *Signature) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Signature", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is structInfo - lines = append(lines, pretty.SubValue(depth+1, "Struct Info", "", &s.StructInfo, opts...)...) - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "Key Signature", "", &s.KeySignature, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/bg/bgbootpolicy/testdata/bpm.bin b/pkg/intel/metadata/bg/bgbootpolicy/testdata/bpm.bin deleted file mode 100644 index 0eabfa3fadaac2726a13500ff7e2f4fecb9841d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 699 zcma!#cXW0Nh>sUw6kuRxaA1g!_jGa!2J#sg_!+?9;y(y|6G{VR7(PIRNF+b}|Nozx zL4m~~n0t_6C42%q|{eBG$dJO`tyG}ps3eEiGw)dljhh+No`Ht($UjKi5M$pFLCXb=L zfx?v+7rrg)HLyDNc`47;3N@|w3zqCT!#P`_y=OZigM;OJ+qwCA}ea>e#ZAl#Y&A&i%&iOE9Lw1phw2K zY1%1U-W@QTt6Y=5MfO_fe$mT*Z0Fm$Yrln@))8BzDm<^r+DqXG(<#>3+}2u=A)!yq zF5Ro+~>KUoFWGJS_qW2yTY;7kD+N+|Y=gbG-hbx^j&3b&j;}CDOAe zWt6SWy`1?9VZCqcm>(DR1xEnI5N^5_aI+tfE zEn8aRxb?P2_ks=bj!|I?SFQAUD157Mo}r7p-|5s-33KKwe_8gm?ppu)sU>_Dc{grY z@cwpf0`sLjF{LSKJ(DzFgm}9cZ@R7gN1>O`Pq1Bm`op{1r#5&VZl1*RLAm>n+>3I> z&xJ)bqJOTfT-J1>_~TB|cyqq&+wn3IUZ&nn8bQnDUa+%W-u-$_v?0st}FBPjp? diff --git a/pkg/intel/metadata/bg/bgbootpolicy/testdata/bpm2.bin b/pkg/intel/metadata/bg/bgbootpolicy/testdata/bpm2.bin deleted file mode 100644 index 7c991661bbda72260d022f34e58a9880ac3c7e98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 723 zcma!#cXW0Nh>sUwWME)oaA1g!_jGa!2J#sgSQ$tFK=lN{hyVZob2BI~q}D_oo?5MP zSWIsJb^8Y!mgSW#=Q%p<7URLl9YtauAGR`sO%nL~ALt$kaQOef0q8&wIN{hxbX<-PK?E=SGH`Lx72c7wdrzm7_2bjSbO`6eu2^3wJ)F2%jQ zAKyxA_G{a6*gSf(nfu(8Sv!7PePxQSzh5f9^vp_zjk|JtXXTb}v~8Zb$Zm1$l^2`B z6bu%It*aLBS=+^^{JK|Q-P)fPX#&Z16YS=TfC7S>fz3}yD!JjA@Zp_Nx_h=>PqCD| zAZdLq-Er00~YP|`fedV zMZq^gA$i`Eaf|9C9>;l1i=}#7II`xf<}A_e_193pv#N_HhILg$;E}s)^DgwZ%_>^A z{p_QMZx`H_;n=QW^IuC%s?+ZM#Km{DgKVRdSDJI($!Ixq(9osrlZh+K?V0rowI368 t*@I??D7t6~N;Vm!h|ErrSmxfU`}d~h$NEJ|`O}Txz51;hIWy|qGXTTI9Bcpp diff --git a/pkg/intel/metadata/bg/bgbootpolicy/testdata/bpm3.bin b/pkg/intel/metadata/bg/bgbootpolicy/testdata/bpm3.bin deleted file mode 100644 index e00cbce34cb46b81b99ef6b57c7e6cde39e8aea9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 699 zcma!#cXW0Nh>sUw6kuRxIKU7e@9E?e4CFJwz{P(M)=el4lKB9WB#Hj;|Nnn(1_g!> zk1tphaUR{ebxWFiruf3CcUqQU#UpwXKZjF}p>Y{=@>uWOi$f|41dTp~R zd|j~#dnDUlrY}LY&YX-7vUl>v>fFq+;QN+sbY{H4eG zxVtiC!W^z1VA~}3aPJ%?qrD=afZ%4B&a5%DfbqM@nuPY1c~inTwRb)15`6hGQ%b&W z%a7WIkjaO_w%uW!Mep_Sor#jnBS%;)N%~SN)UM!h@=}Es%(f(=Ewz=Lt zU0iPB@$}~US8oPq2>Cb<@=2Ta4+Nyw{2`8D{54tw8+4LG-UZSqM;zk?4 z-<~HwR;$j8{?#Ka=<=`O%ZKDpAFitJpQ5(s|LE)wT+JX_FSg%!M|Ay!8oT>G3zt+) kY~6PIcb!w)k<0+@RQEG7I_LHO1rUUrR+T0RRvH2mt^A0D~8w{W4T_xurF^OX>SZgSg)j((<9gNYaB|Bh{R(lQ%Zcq1(8#Wfb_fXy#6H1wMkP6q7H*sD$9pwMCq7vXT~yWr$d7hoSG<(`=^&@ zw0kpIa~c_u`ImNk=;q6*Klg5Q3Mmvjb{nUZpYz*JEa6<^w>w!C8}gxmTB=lZlF?in z@GtWicU~uUrnP}mGGj9_R0-hF$v1F7y1qD>>l7o3- z_=?|WU`%TmoD={M00;{J1%`on|0qy`D|;ec%X43lt;`ohT9lPWo1bDLRaeetUWANU zQSyu_?`TVCbe2s~?Whi%T^Wu|-MShUaC|}5y9r~A)>%al5NBwJ=WSd~gWF8iu=8o` z4q8&D@6*U{CxDX@-s^J#{@*OTziqi)nDSr;8vw0%N{pM119{YPS@OOBGjeWrUyd4F zj3|Z^@-Cp!78qT132RGE9T4IFnjM=VV%(cWf5#~Gq!Q}5ne<|n;ezKm)oiUuIt7MI z@Wb-x$*nxU@kF$AA{XhFGwZeOqu5PM#(Y*__W The order of the elements and the order of the fields within each - // > element are architectural and must be followed. - StrictOrderCheck = true -) diff --git a/pkg/intel/metadata/bg/crypto_routines.go b/pkg/intel/metadata/bg/crypto_routines.go deleted file mode 100644 index 4608ea87..00000000 --- a/pkg/intel/metadata/bg/crypto_routines.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package bg - -import ( - "crypto" - "fmt" - "hash" - "strings" - - // Required for hash.Hash return in hashInfo struct - _ "crypto/sha1" - _ "crypto/sha256" - _ "crypto/sha512" -) - -// Algorithm represents a crypto algorithm value. -type Algorithm uint16 - -const ( - AlgUnknown Algorithm = 0x0000 - AlgRSA Algorithm = 0x0001 - AlgSHA1 Algorithm = 0x0004 - AlgSHA256 Algorithm = 0x000B - AlgNull Algorithm = 0x0010 - AlgRSASSA Algorithm = 0x0014 -) - -var hashInfo = []struct { - alg Algorithm - hashFactory func() hash.Hash -}{ - {AlgSHA1, crypto.SHA1.New}, - {AlgSHA256, crypto.SHA256.New}, -} - -// IsNull returns true if a is AlgNull or zero (unset). -func (a Algorithm) IsNull() bool { - return a == AlgNull || a == AlgUnknown -} - -// Hash returns a crypto.Hash based on the given id. -// An error is returned if the given algorithm is not a hash algorithm or is not available. -func (a Algorithm) Hash() (hash.Hash, error) { - for _, info := range hashInfo { - if info.alg == a { - if info.hashFactory == nil { - return nil, fmt.Errorf("go hash algorithm #%snot available", info.alg.String()) - } - return info.hashFactory(), nil - } - } - return nil, fmt.Errorf("hash algorithm not supported: %s", a.String()) -} - -func (a Algorithm) String() string { - var s strings.Builder - var err error - switch a { - case AlgUnknown: - _, err = s.WriteString("AlgUnknown") - case AlgRSA: - _, err = s.WriteString("RSA") - case AlgSHA1: - _, err = s.WriteString("SHA1") - case AlgSHA256: - _, err = s.WriteString("SHA256") - case AlgNull: - _, err = s.WriteString("AlgNull") - case AlgRSASSA: - _, err = s.WriteString("RSASSA") - default: - return fmt.Sprintf("Alg?<%d>", int(a)) - } - if err != nil { - return fmt.Sprintf("Writing to string builder failed: %v", err) - } - return s.String() -} - -func GetAlgFromString(name string) (Algorithm, error) { - n := strings.ToUpper(name) - switch n { - case "ALGUNKNOWN": - return AlgUnknown, nil - case "RSA": - return AlgRSA, nil - case "SHA1": - return AlgSHA1, nil - case "SHA256": - return AlgSHA256, nil - case "ALGNULL": - return AlgNull, nil - case "RSASSA": - return AlgRSASSA, nil - default: - return AlgNull, fmt.Errorf("algorithm name provided unknown") - } -} diff --git a/pkg/intel/metadata/bg/crypto_routines_manifestcodegen.go b/pkg/intel/metadata/bg/crypto_routines_manifestcodegen.go deleted file mode 100644 index c6d0909a..00000000 --- a/pkg/intel/metadata/bg/crypto_routines_manifestcodegen.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen -package bg github.com/linuxboot/fiano/pkg/intel/metadata/bg - -package bg - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v Algorithm) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - return v.String() -} - -// TotalSize returns the total size measured through binary.Size. -func (v Algorithm) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the Algorithm into 'w' in binary format. -func (v Algorithm) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the Algorithm from 'r' in binary format. -func (v Algorithm) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} diff --git a/pkg/intel/metadata/bg/hash.go b/pkg/intel/metadata/bg/hash.go deleted file mode 100644 index e0ec47a3..00000000 --- a/pkg/intel/metadata/bg/hash.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package bg - -// HashStructure describes a digest. -type HashStructure struct { - HashAlg Algorithm `default:"0x10" json:"hsAlg"` - HashBuffer []byte `json:"hsBuffer"` -} - -type HashStructureFill struct { - HashAlg Algorithm `default:"0x0b" json:"hsAlg"` - HashBuffer []byte `countValue:"hashSize()" prettyValue:"hashSizePrint()" json:"hsBuffer"` -} - -func (a Algorithm) size() uint16 { - switch a { - case AlgUnknown: - return 0 - case AlgNull: - return 0 - case AlgSHA1: - return 20 - case AlgSHA256: - return 32 - default: - return 0 - } -} - -func (h HashStructureFill) hashSize() uint16 { - const hashSizeFieldLen = 2 - if h.HashAlg.IsNull() { - // Evil hack, more investigation needed - return AlgSHA256.size() + hashSizeFieldLen - } else { - return h.HashAlg.size() + hashSizeFieldLen - } -} - -func (h HashStructureFill) hashSizePrint() interface{} { - if h.HashAlg.IsNull() { - // Evil hack, more investigation needed - return make([]byte, AlgSHA256.size()) - } else { - return h.HashBuffer - } -} diff --git a/pkg/intel/metadata/bg/hash_manifestcodegen.go b/pkg/intel/metadata/bg/hash_manifestcodegen.go deleted file mode 100644 index 4a98f14c..00000000 --- a/pkg/intel/metadata/bg/hash_manifestcodegen.go +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen -package bg github.com/linuxboot/fiano/pkg/intel/metadata/bg - -package bg - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// NewHashStructure returns a new instance of HashStructure with -// all default values set. -func NewHashStructure() *HashStructure { - s := &HashStructure{} - // Set through tag "default": - s.HashAlg = 0x10 - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *HashStructure) Validate() error { - - return nil -} - -// ReadFrom reads the HashStructure from 'r' in format defined in the document #575623. -func (s *HashStructure) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // HashAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.HashAlg) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'HashAlg': %w", err) - } - totalN += int64(n) - } - - // HashBuffer (ManifestFieldType: arrayDynamic) - { - var size uint16 - err := binary.Read(r, binary.LittleEndian, &size) - if err != nil { - return totalN, fmt.Errorf("unable to the read size of field 'HashBuffer': %w", err) - } - totalN += int64(binary.Size(size)) - s.HashBuffer = make([]byte, size) - n, err := len(s.HashBuffer), binary.Read(r, binary.LittleEndian, s.HashBuffer) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'HashBuffer': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *HashStructure) RehashRecursive() { - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *HashStructure) Rehash() { -} - -// WriteTo writes the HashStructure into 'w' in format defined in -// the document #575623. -func (s *HashStructure) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // HashAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.HashAlg) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'HashAlg': %w", err) - } - totalN += int64(n) - } - - // HashBuffer (ManifestFieldType: arrayDynamic) - { - size := uint16(len(s.HashBuffer)) - err := binary.Write(w, binary.LittleEndian, size) - if err != nil { - return totalN, fmt.Errorf("unable to write the size of field 'HashBuffer': %w", err) - } - totalN += int64(binary.Size(size)) - n, err := len(s.HashBuffer), binary.Write(w, binary.LittleEndian, s.HashBuffer) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'HashBuffer': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// HashAlgSize returns the size in bytes of the value of field HashAlg -func (s *HashStructure) HashAlgTotalSize() uint64 { - return 2 -} - -// HashBufferSize returns the size in bytes of the value of field HashBuffer -func (s *HashStructure) HashBufferTotalSize() uint64 { - size := uint64(binary.Size(uint16(0))) - size += uint64(len(s.HashBuffer)) - return size -} - -// HashAlgOffset returns the offset in bytes of field HashAlg -func (s *HashStructure) HashAlgOffset() uint64 { - return 0 -} - -// HashBufferOffset returns the offset in bytes of field HashBuffer -func (s *HashStructure) HashBufferOffset() uint64 { - return s.HashAlgOffset() + s.HashAlgTotalSize() -} - -// Size returns the total size of the HashStructure. -func (s *HashStructure) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.HashAlgTotalSize() - size += s.HashBufferTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *HashStructure) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Hash Structure", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Hash Alg", "", &s.HashAlg, opts...)...) - // ManifestFieldType is arrayDynamic - lines = append(lines, pretty.SubValue(depth+1, "Hash Buffer", "", &s.HashBuffer, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} - -// NewHashStructureFill returns a new instance of HashStructureFill with -// all default values set. -func NewHashStructureFill() *HashStructureFill { - s := &HashStructureFill{} - // Set through tag "default": - s.HashAlg = 0x0b - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *HashStructureFill) Validate() error { - - return nil -} - -// ReadFrom reads the HashStructureFill from 'r' in format defined in the document #575623. -func (s *HashStructureFill) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // HashAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.HashAlg) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'HashAlg': %w", err) - } - totalN += int64(n) - } - - // HashBuffer (ManifestFieldType: arrayDynamic) - { - size := uint16(s.hashSize()) - s.HashBuffer = make([]byte, size) - n, err := len(s.HashBuffer), binary.Read(r, binary.LittleEndian, s.HashBuffer) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'HashBuffer': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *HashStructureFill) RehashRecursive() { - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *HashStructureFill) Rehash() { -} - -// WriteTo writes the HashStructureFill into 'w' in format defined in -// the document #575623. -func (s *HashStructureFill) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // HashAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.HashAlg) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'HashAlg': %w", err) - } - totalN += int64(n) - } - - // HashBuffer (ManifestFieldType: arrayDynamic) - { - n, err := len(s.HashBuffer), binary.Write(w, binary.LittleEndian, s.HashBuffer) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'HashBuffer': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// HashAlgSize returns the size in bytes of the value of field HashAlg -func (s *HashStructureFill) HashAlgTotalSize() uint64 { - return 2 -} - -// HashBufferSize returns the size in bytes of the value of field HashBuffer -func (s *HashStructureFill) HashBufferTotalSize() uint64 { - return uint64(len(s.HashBuffer)) -} - -// HashAlgOffset returns the offset in bytes of field HashAlg -func (s *HashStructureFill) HashAlgOffset() uint64 { - return 0 -} - -// HashBufferOffset returns the offset in bytes of field HashBuffer -func (s *HashStructureFill) HashBufferOffset() uint64 { - return s.HashAlgOffset() + s.HashAlgTotalSize() -} - -// Size returns the total size of the HashStructureFill. -func (s *HashStructureFill) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.HashAlgTotalSize() - size += s.HashBufferTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *HashStructureFill) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Hash Structure Fill", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Hash Alg", "", &s.HashAlg, opts...)...) - // ManifestFieldType is arrayDynamic - lines = append(lines, pretty.SubValue(depth+1, "Hash Buffer", "", s.hashSizePrint(), opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/bg/key.go b/pkg/intel/metadata/bg/key.go deleted file mode 100644 index 4e66a458..00000000 --- a/pkg/intel/metadata/bg/key.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package bg - -import ( - "bytes" - "crypto" - "crypto/rsa" - "encoding/binary" - "fmt" - "math/big" -) - -// Key is a public key of an asymmetric crypto keypair. -type Key struct { - KeyAlg Algorithm `json:"keyAlg"` - Version uint8 `require:"0x10" json:"keyVersion"` - KeySize BitSize `json:"keyBitsize"` - Data []byte `countValue:"keyDataSize()" json:"keyData"` -} - -// BitSize is a size in bits. -type BitSize uint16 - -// InBits returns the size in bits. -func (ks BitSize) InBits() uint16 { - return uint16(ks) -} - -// InBytes returns the size in bytes. -func (ks BitSize) InBytes() uint16 { - return uint16(ks >> 3) -} - -// SetInBits sets the size in bits. -func (ks *BitSize) SetInBits(amountOfBits uint16) { - *ks = BitSize(amountOfBits) -} - -// SetInBytes sets the size in bytes. -func (ks *BitSize) SetInBytes(amountOfBytes uint16) { - *ks = BitSize(amountOfBytes << 3) -} - -// keyDataSize returns the expected length of Data for specified -// KeyAlg and KeySize. -func (k Key) keyDataSize() int64 { - switch k.KeyAlg { - case AlgRSA: - return int64(k.KeySize.InBytes()) + 4 - } - return -1 -} - -// PubKey parses Data into crypto.PublicKey. -func (k Key) PubKey() (crypto.PublicKey, error) { - expectedSize := int(k.keyDataSize()) - if expectedSize < 0 { - return nil, fmt.Errorf("unexpected algorithm: %s", k.KeyAlg) - } - if len(k.Data) != expectedSize { - return nil, fmt.Errorf("unexpected size: expected:%d, received %d", expectedSize, len(k.Data)) - } - - switch k.KeyAlg { - case AlgRSA: - result := &rsa.PublicKey{ - N: new(big.Int).SetBytes(reverseBytes(k.Data[4:])), - E: int(binaryOrder.Uint32(k.Data)), - } - return result, nil - } - - return nil, fmt.Errorf("unexpected TPM algorithm: %s", k.KeyAlg) -} - -func reverseBytes(b []byte) []byte { - r := make([]byte, len(b)) - for idx := range b { - r[idx] = b[len(b)-idx-1] - } - return r -} - -// SetPubKey sets Data the value corresponding to passed `key`. -func (k *Key) SetPubKey(key crypto.PublicKey) error { - k.Version = 0x10 - - switch key := key.(type) { - case *rsa.PublicKey: - k.KeyAlg = AlgRSA - n := key.N.Bytes() - k.KeySize.SetInBytes(uint16(len(n))) - k.Data = make([]byte, 4+len(n)) - binaryOrder.PutUint32(k.Data, uint32(key.E)) - copy(k.Data[4:], reverseBytes(n)) - return nil - } - - return fmt.Errorf("unexpected key type: %T", key) -} - -// PrintBPMPubKey prints the BPM public signing key hash to fuse into the Intel ME -func (k *Key) PrintBPMPubKey(bpmAlg Algorithm) error { - buf := new(bytes.Buffer) - if len(k.Data) > 1 { - hash, err := bpmAlg.Hash() - if err != nil { - return err - } - if k.KeyAlg == AlgRSA { - if err := binary.Write(buf, binary.LittleEndian, k.Data[4:]); err != nil { - return err - } - hash.Write(buf.Bytes()) - fmt.Printf(" Boot Policy Manifest Pubkey Hash: 0x%x\n", hash.Sum(nil)) - } else { - fmt.Printf(" Boot Policy Manifest Pubkey Hash: Unknown Algorithm\n") - } - } else { - fmt.Printf(" Boot Policy Pubkey Hash: No km public key set in KM\n") - } - - return nil -} - -// PrintKMPubKey prints the KM public signing key hash to fuse into the Intel ME -func (k *Key) PrintKMPubKey(kmAlg Algorithm) error { - buf := new(bytes.Buffer) - if len(k.Data) > 1 { - if k.KeyAlg == AlgRSA { - if err := binary.Write(buf, binary.LittleEndian, k.Data[4:]); err != nil { - return err - } - if err := binary.Write(buf, binary.LittleEndian, k.Data[:4]); err != nil { - return err - } - if kmAlg != AlgSHA256 { - return fmt.Errorf("KM public key hash algorithm must be SHA256") - } - hash, err := kmAlg.Hash() - if err != nil { - return err - } - hash.Write(buf.Bytes()) - fmt.Printf(" Key Manifest Pubkey Hash: 0x%x\n", hash.Sum(nil)) - // On SKL and KBL the exponent is not included in the KM hash - buf.Truncate(len(k.Data[4:])) - hash.Reset() - hash.Write(buf.Bytes()) - fmt.Printf(" Key Manifest Pubkey Hash (Skylake and Kabylake only): 0x%x\n", hash.Sum(nil)) - } else { - fmt.Printf(" Key Manifest Pubkey Hash: Unsupported Algorithm\n") - } - } else { - fmt.Printf(" Key Manifest Pubkey Hash: No km public key set in KM\n") - } - - return nil -} diff --git a/pkg/intel/metadata/bg/key_manifestcodegen.go b/pkg/intel/metadata/bg/key_manifestcodegen.go deleted file mode 100644 index 1893f1e3..00000000 --- a/pkg/intel/metadata/bg/key_manifestcodegen.go +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen -package bg github.com/linuxboot/fiano/pkg/intel/metadata/bg - -package bg - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// NewKey returns a new instance of Key with -// all default values set. -func NewKey() *Key { - s := &Key{} - // Set through tag "required": - s.Version = 0x10 - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *Key) Validate() error { - // See tag "require" - if s.Version != 0x10 { - return fmt.Errorf("field 'Version' expects value '0x10', but has %v", s.Version) - } - - return nil -} - -// ReadFrom reads the Key from 'r' in format defined in the document #575623. -func (s *Key) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // KeyAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.KeyAlg) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'KeyAlg': %w", err) - } - totalN += int64(n) - } - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Version': %w", err) - } - totalN += int64(n) - } - - // KeySize (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.KeySize) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'KeySize': %w", err) - } - totalN += int64(n) - } - - // Data (ManifestFieldType: arrayDynamic) - { - size := uint16(s.keyDataSize()) - s.Data = make([]byte, size) - n, err := len(s.Data), binary.Read(r, binary.LittleEndian, s.Data) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Data': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *Key) RehashRecursive() { - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *Key) Rehash() { -} - -// WriteTo writes the Key into 'w' in format defined in -// the document #575623. -func (s *Key) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // KeyAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.KeyAlg) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'KeyAlg': %w", err) - } - totalN += int64(n) - } - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Version': %w", err) - } - totalN += int64(n) - } - - // KeySize (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.KeySize) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'KeySize': %w", err) - } - totalN += int64(n) - } - - // Data (ManifestFieldType: arrayDynamic) - { - n, err := len(s.Data), binary.Write(w, binary.LittleEndian, s.Data) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Data': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// KeyAlgSize returns the size in bytes of the value of field KeyAlg -func (s *Key) KeyAlgTotalSize() uint64 { - return 2 -} - -// VersionSize returns the size in bytes of the value of field Version -func (s *Key) VersionTotalSize() uint64 { - return 1 -} - -// KeySizeSize returns the size in bytes of the value of field KeySize -func (s *Key) KeySizeTotalSize() uint64 { - return 2 -} - -// DataSize returns the size in bytes of the value of field Data -func (s *Key) DataTotalSize() uint64 { - return uint64(len(s.Data)) -} - -// KeyAlgOffset returns the offset in bytes of field KeyAlg -func (s *Key) KeyAlgOffset() uint64 { - return 0 -} - -// VersionOffset returns the offset in bytes of field Version -func (s *Key) VersionOffset() uint64 { - return s.KeyAlgOffset() + s.KeyAlgTotalSize() -} - -// KeySizeOffset returns the offset in bytes of field KeySize -func (s *Key) KeySizeOffset() uint64 { - return s.VersionOffset() + s.VersionTotalSize() -} - -// DataOffset returns the offset in bytes of field Data -func (s *Key) DataOffset() uint64 { - return s.KeySizeOffset() + s.KeySizeTotalSize() -} - -// Size returns the total size of the Key. -func (s *Key) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.KeyAlgTotalSize() - size += s.VersionTotalSize() - size += s.KeySizeTotalSize() - size += s.DataTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *Key) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Key", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Key Alg", "", &s.KeyAlg, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Version", "", &s.Version, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Key Size", "", &s.KeySize, opts...)...) - // ManifestFieldType is arrayDynamic - lines = append(lines, pretty.SubValue(depth+1, "Data", "", &s.Data, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v BitSize) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Bit Size", v)) - } - lines = append(lines, pretty.SubValue(depth+1, "In Bits", "", v.InBits(), opts...)...) - lines = append(lines, pretty.SubValue(depth+1, "In Bytes", "", v.InBytes(), opts...)...) - return strings.Join(lines, "\n") -} - -// TotalSize returns the total size measured through binary.Size. -func (v BitSize) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the BitSize into 'w' in binary format. -func (v BitSize) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the BitSize from 'r' in binary format. -func (v BitSize) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} diff --git a/pkg/intel/metadata/bg/key_signature.go b/pkg/intel/metadata/bg/key_signature.go deleted file mode 100644 index 560be54c..00000000 --- a/pkg/intel/metadata/bg/key_signature.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package bg - -import ( - "crypto" - "fmt" -) - -// KeySignature -type KeySignature struct { - Version uint8 `require:"0x10" json:"ksVersion,omitempty"` - Key Key `json:"ksKey"` - Signature Signature `json:"ksSignature"` -} - -// Verify verifies the builtin signature with the builtin public key. -func (ks *KeySignature) Verify(signedData []byte) error { - sig, err := ks.Signature.SignatureData() - if err != nil { - return fmt.Errorf("invalid signature: %w", err) - } - pk, err := ks.Key.PubKey() - if err != nil { - return fmt.Errorf("invalid public key: %w", err) - } - err = sig.Verify(pk, signedData) - if err != nil { - return fmt.Errorf("verification failed: %w", err) - } - return nil -} - -// SetSignature generates a signature and sets all the values of KeyManifest, -// accordingly to arguments signAlgo, privKey and signedData. -// -// if signAlgo is zero then it is detected automatically, based on the type -// of the provided private key. -func (ks *KeySignature) SetSignature(signAlgo Algorithm, privKey crypto.Signer, signedData []byte) error { - ks.Version = 0x10 - err := ks.Key.SetPubKey(privKey.Public()) - if err != nil { - return fmt.Errorf("unable to set public key: %w", err) - } - - return ks.Signature.SetSignature(signAlgo, privKey, signedData) -} - -// SetSignatureAuto generates a signature and sets all the values of KeyManifest, -// accordingly to arguments privKey and signedData. -// -// Signing algorithm will be detected automatically based on the type of the -// provided private key. -func (ks *KeySignature) SetSignatureAuto(privKey crypto.Signer, signedData []byte) error { - ks.Version = 0x10 - err := ks.Key.SetPubKey(privKey.Public()) - if err != nil { - return fmt.Errorf("unable to set public key: %w", err) - } - - return ks.SetSignature(0, privKey, signedData) -} - -// FillSignature sets a signature and all the values of KeyManifest, -// accordingly to arguments signAlgo, pubKey and signedData. -// -// if signAlgo is zero then it is detected automatically, based on the type -// of the provided private key. -func (ks *KeySignature) FillSignature(signAlgo Algorithm, pubKey crypto.PublicKey, signedData []byte, hashAlgo Algorithm) error { - ks.Version = 0x10 - err := ks.Key.SetPubKey(pubKey) - if err != nil { - return fmt.Errorf("unable to set public key: %w", err) - } - - return ks.Signature.FillSignature(signAlgo, pubKey, signedData, hashAlgo) -} diff --git a/pkg/intel/metadata/bg/key_signature_manifestcodegen.go b/pkg/intel/metadata/bg/key_signature_manifestcodegen.go deleted file mode 100644 index 807d1ec4..00000000 --- a/pkg/intel/metadata/bg/key_signature_manifestcodegen.go +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen -package bg github.com/linuxboot/fiano/pkg/intel/metadata/bg - -package bg - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// NewKeySignature returns a new instance of KeySignature with -// all default values set. -func NewKeySignature() *KeySignature { - s := &KeySignature{} - // Set through tag "required": - s.Version = 0x10 - // Recursively initializing a child structure: - s.Key = *NewKey() - // Recursively initializing a child structure: - s.Signature = *NewSignature() - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *KeySignature) Validate() error { - // See tag "require" - if s.Version != 0x10 { - return fmt.Errorf("field 'Version' expects value '0x10', but has %v", s.Version) - } - // Recursively validating a child structure: - if err := s.Key.Validate(); err != nil { - return fmt.Errorf("error on field 'Key': %w", err) - } - // Recursively validating a child structure: - if err := s.Signature.Validate(); err != nil { - return fmt.Errorf("error on field 'Signature': %w", err) - } - - return nil -} - -// ReadFrom reads the KeySignature from 'r' in format defined in the document #575623. -func (s *KeySignature) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Version': %w", err) - } - totalN += int64(n) - } - - // Key (ManifestFieldType: subStruct) - { - n, err := s.Key.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Key': %w", err) - } - totalN += int64(n) - } - - // Signature (ManifestFieldType: subStruct) - { - n, err := s.Signature.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Signature': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *KeySignature) RehashRecursive() { - s.Key.Rehash() - s.Signature.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *KeySignature) Rehash() { -} - -// WriteTo writes the KeySignature into 'w' in format defined in -// the document #575623. -func (s *KeySignature) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Version': %w", err) - } - totalN += int64(n) - } - - // Key (ManifestFieldType: subStruct) - { - n, err := s.Key.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Key': %w", err) - } - totalN += int64(n) - } - - // Signature (ManifestFieldType: subStruct) - { - n, err := s.Signature.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Signature': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// VersionSize returns the size in bytes of the value of field Version -func (s *KeySignature) VersionTotalSize() uint64 { - return 1 -} - -// KeySize returns the size in bytes of the value of field Key -func (s *KeySignature) KeyTotalSize() uint64 { - return s.Key.TotalSize() -} - -// SignatureSize returns the size in bytes of the value of field Signature -func (s *KeySignature) SignatureTotalSize() uint64 { - return s.Signature.TotalSize() -} - -// VersionOffset returns the offset in bytes of field Version -func (s *KeySignature) VersionOffset() uint64 { - return 0 -} - -// KeyOffset returns the offset in bytes of field Key -func (s *KeySignature) KeyOffset() uint64 { - return s.VersionOffset() + s.VersionTotalSize() -} - -// SignatureOffset returns the offset in bytes of field Signature -func (s *KeySignature) SignatureOffset() uint64 { - return s.KeyOffset() + s.KeyTotalSize() -} - -// Size returns the total size of the KeySignature. -func (s *KeySignature) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.VersionTotalSize() - size += s.KeyTotalSize() - size += s.SignatureTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *KeySignature) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Key Signature", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Version", "", &s.Version, opts...)...) - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "Key", "", &s.Key, opts...)...) - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "Signature", "", &s.Signature, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/bg/signature.go b/pkg/intel/metadata/bg/signature.go deleted file mode 100644 index d3d5a659..00000000 --- a/pkg/intel/metadata/bg/signature.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package bg - -import ( - "crypto" - "crypto/rand" - "fmt" -) - -var ( - // RandReader exports the rand.Reader - RandReader = rand.Reader -) - -// Signature exports the Signature structure -type Signature struct { - SigScheme Algorithm `json:"sigScheme"` - Version uint8 `require:"0x10" json:"sigVersion,omitempty"` - KeySize BitSize `json:"sigKeysize,omitempty"` - HashAlg Algorithm `json:"sigHashAlg"` - Data []byte `countValue:"KeySize.InBytes()" prettyValue:"dataPrettyValue()" json:"sigData"` -} - -func (m Signature) dataPrettyValue() interface{} { - r, _ := m.SignatureData() - return r -} - -// SignatureData parses field Data and returns the signature as one of these types: -// * SignatureRSAPSS -// * SignatureRSAASA -// * SignatureECDSA -// * SignatureSM2 -func (m Signature) SignatureData() (SignatureDataInterface, error) { - switch m.SigScheme { - case AlgRSASSA: - return SignatureRSAASA(m.Data), nil - } - - return nil, fmt.Errorf("unexpected signature scheme: %s", m.SigScheme) -} - -// SetSignatureByData sets all the fields of the structure Signature by -// accepting one of these types as the input argument `sig`: -// * SignatureRSAPSS -// * SignatureRSAASA -// * SignatureECDSA -// * SignatureSM2 -func (m *Signature) SetSignatureByData(sig SignatureDataInterface, hashAlgo Algorithm) error { - err := m.SetSignatureData(sig) - if err != nil { - return err - } - - switch sig := sig.(type) { - case SignatureRSAASA: - m.SigScheme = AlgRSASSA - if hashAlgo.IsNull() { - m.HashAlg = AlgSHA256 - } else { - m.HashAlg = hashAlgo - } - m.KeySize.SetInBytes(uint16(len(m.Data))) - default: - return fmt.Errorf("unexpected signature type: %T", sig) - } - return nil -} - -// SetSignatureData sets the value of the field Data by accepting one of these -// types as the input argument `sig`: -// * SignatureRSAPSS -// * SignatureRSAASA -// * SignatureECDSA -// * SignatureSM2 -func (m *Signature) SetSignatureData(sig SignatureDataInterface) error { - switch sig := sig.(type) { - case SignatureRSAASA: - m.Data = sig - default: - return fmt.Errorf("unexpected signature type: %T", sig) - } - return nil -} - -// SetSignature calculates the signature accordingly to arguments signAlgo, -// privKey and signedData; and sets all the fields of the structure Signature. -// -// if signAlgo is zero then it is detected automatically, based on the type -// of the provided private key. -func (m *Signature) SetSignature(signAlgo Algorithm, privKey crypto.Signer, signedData []byte) error { - m.Version = 0x10 - signData, err := NewSignatureData(signAlgo, privKey, signedData) - if err != nil { - return fmt.Errorf("unable to construct the signature data: %w", err) - } - - err = m.SetSignatureByData(signData, AlgNull) - if err != nil { - return fmt.Errorf("unable to set the signature: %w", err) - } - - return nil -} - -// FillSignature sets the signature accordingly to arguments signAlgo, -// pubKey and signedData; and sets all the fields of the structure Signature. -// -// if signAlgo is zero then it is detected automatically, based on the type -// of the provided private key. -func (m *Signature) FillSignature(signAlgo Algorithm, pubKey crypto.PublicKey, signedData []byte, hashAlgo Algorithm) error { - m.Version = 0x10 - signData, err := NewSignatureByData(signAlgo, pubKey, signedData) - if err != nil { - return fmt.Errorf("unable to construct the signature data: %w", err) - } - - err = m.SetSignatureByData(signData, hashAlgo) - if err != nil { - return fmt.Errorf("unable to set the signature: %w", err) - } - - return nil -} diff --git a/pkg/intel/metadata/bg/signature_manifestcodegen.go b/pkg/intel/metadata/bg/signature_manifestcodegen.go deleted file mode 100644 index eba005bf..00000000 --- a/pkg/intel/metadata/bg/signature_manifestcodegen.go +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen -package bg github.com/linuxboot/fiano/pkg/intel/metadata/bg - -package bg - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// NewSignature returns a new instance of Signature with -// all default values set. -func NewSignature() *Signature { - s := &Signature{} - // Set through tag "required": - s.Version = 0x10 - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *Signature) Validate() error { - // See tag "require" - if s.Version != 0x10 { - return fmt.Errorf("field 'Version' expects value '0x10', but has %v", s.Version) - } - - return nil -} - -// ReadFrom reads the Signature from 'r' in format defined in the document #575623. -func (s *Signature) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // SigScheme (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.SigScheme) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'SigScheme': %w", err) - } - totalN += int64(n) - } - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Version': %w", err) - } - totalN += int64(n) - } - - // KeySize (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.KeySize) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'KeySize': %w", err) - } - totalN += int64(n) - } - - // HashAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.HashAlg) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'HashAlg': %w", err) - } - totalN += int64(n) - } - - // Data (ManifestFieldType: arrayDynamic) - { - size := uint16(s.KeySize.InBytes()) - s.Data = make([]byte, size) - n, err := len(s.Data), binary.Read(r, binary.LittleEndian, s.Data) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Data': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *Signature) RehashRecursive() { - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *Signature) Rehash() { -} - -// WriteTo writes the Signature into 'w' in format defined in -// the document #575623. -func (s *Signature) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // SigScheme (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.SigScheme) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'SigScheme': %w", err) - } - totalN += int64(n) - } - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Version': %w", err) - } - totalN += int64(n) - } - - // KeySize (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.KeySize) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'KeySize': %w", err) - } - totalN += int64(n) - } - - // HashAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.HashAlg) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'HashAlg': %w", err) - } - totalN += int64(n) - } - - // Data (ManifestFieldType: arrayDynamic) - { - n, err := len(s.Data), binary.Write(w, binary.LittleEndian, s.Data) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Data': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// SigSchemeSize returns the size in bytes of the value of field SigScheme -func (s *Signature) SigSchemeTotalSize() uint64 { - return 2 -} - -// VersionSize returns the size in bytes of the value of field Version -func (s *Signature) VersionTotalSize() uint64 { - return 1 -} - -// KeySizeSize returns the size in bytes of the value of field KeySize -func (s *Signature) KeySizeTotalSize() uint64 { - return 2 -} - -// HashAlgSize returns the size in bytes of the value of field HashAlg -func (s *Signature) HashAlgTotalSize() uint64 { - return 2 -} - -// DataSize returns the size in bytes of the value of field Data -func (s *Signature) DataTotalSize() uint64 { - return uint64(len(s.Data)) -} - -// SigSchemeOffset returns the offset in bytes of field SigScheme -func (s *Signature) SigSchemeOffset() uint64 { - return 0 -} - -// VersionOffset returns the offset in bytes of field Version -func (s *Signature) VersionOffset() uint64 { - return s.SigSchemeOffset() + s.SigSchemeTotalSize() -} - -// KeySizeOffset returns the offset in bytes of field KeySize -func (s *Signature) KeySizeOffset() uint64 { - return s.VersionOffset() + s.VersionTotalSize() -} - -// HashAlgOffset returns the offset in bytes of field HashAlg -func (s *Signature) HashAlgOffset() uint64 { - return s.KeySizeOffset() + s.KeySizeTotalSize() -} - -// DataOffset returns the offset in bytes of field Data -func (s *Signature) DataOffset() uint64 { - return s.HashAlgOffset() + s.HashAlgTotalSize() -} - -// Size returns the total size of the Signature. -func (s *Signature) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.SigSchemeTotalSize() - size += s.VersionTotalSize() - size += s.KeySizeTotalSize() - size += s.HashAlgTotalSize() - size += s.DataTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *Signature) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Signature", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Sig Scheme", "", &s.SigScheme, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Version", "", &s.Version, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Key Size", "", &s.KeySize, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Hash Alg", "", &s.HashAlg, opts...)...) - // ManifestFieldType is arrayDynamic - lines = append(lines, pretty.SubValue(depth+1, "Data", "", s.dataPrettyValue(), opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/bg/signature_types.go b/pkg/intel/metadata/bg/signature_types.go deleted file mode 100644 index 9cf98456..00000000 --- a/pkg/intel/metadata/bg/signature_types.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package bg - -import ( - "crypto" - "crypto/rsa" - "crypto/sha256" - "fmt" -) - -var SM2UID = []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38} - -// NewSignatureData returns an implementation of SignatureDataInterface, -// accordingly to signAlgo, privKey and signedData. -// -// if signAlgo is zero then it is detected automatically, based on the type -// of the provided private key. -func NewSignatureData( - signAlgo Algorithm, - privKey crypto.Signer, - signedData []byte, -) (SignatureDataInterface, error) { - if signAlgo == 0 { - // auto-detect the sign algorithm, based on the provided signing key - switch privKey.(type) { - case *rsa.PrivateKey: - signAlgo = AlgRSASSA - } - } - switch signAlgo { - case AlgRSASSA: - rsaPrivateKey, ok := privKey.(*rsa.PrivateKey) - if !ok { - return nil, fmt.Errorf("expected private RSA key (type %T), but received %T", rsaPrivateKey, privKey) - } - h := sha256.New() - _, _ = h.Write(signedData) - bpmHash := h.Sum(nil) - data, err := rsa.SignPKCS1v15(RandReader, rsaPrivateKey, crypto.SHA256, bpmHash) - if err != nil { - return nil, fmt.Errorf("unable to sign with RSASSA the data: %w", err) - } - return SignatureRSAASA(data), nil - } - - return nil, fmt.Errorf("signing algorithm '%s' is not implemented in this library", signAlgo) -} - -// NewSignatureByData returns an implementation of SignatureDataInterface, -// accordingly to signAlgo, publicKey and signedData. -// -// if signAlgo is zero then it is detected automatically, based on the type -// of the provided private key. -func NewSignatureByData( - signAlgo Algorithm, - pubKey crypto.PublicKey, - signedData []byte, -) (SignatureDataInterface, error) { - if signAlgo == 0 { - // auto-detect the sign algorithm, based on the provided signing key - switch pubKey.(type) { - case *rsa.PublicKey: - signAlgo = AlgRSASSA - } - } - switch signAlgo { - case AlgRSASSA: - return SignatureRSAASA(signedData), nil - } - return nil, fmt.Errorf("signing algorithm '%s' is not implemented in this library", signAlgo) -} - -// SignatureDataInterface is the interface which abstracts all the signature data types. -type SignatureDataInterface interface { - fmt.Stringer - - // Verify returns nil if signedData was indeed signed by key pk, and - // returns an appropriate error otherwise. - Verify(pk crypto.PublicKey, signedData []byte) error -} - -// SignatureRSAASA is RSAASA signature bytes. -type SignatureRSAASA []byte - -// String implements fmt.Stringer -func (s SignatureRSAASA) String() string { - return fmt.Sprintf("0x%X", []byte(s)) -} - -// Verify implements SignatureDataInterface. -func (s SignatureRSAASA) Verify(pkIface crypto.PublicKey, signedData []byte) error { - pk, ok := pkIface.(*rsa.PublicKey) - if !ok { - return fmt.Errorf("expected public key of type %T, but received %T", pk, pkIface) - } - - h := sha256.New() - h.Write(signedData) - hash := h.Sum(nil) - - err := rsa.VerifyPKCS1v15(pk, crypto.SHA256, hash, s) - if err != nil { - return fmt.Errorf("data was not signed by the key: %w", err) - } - - return nil -} diff --git a/pkg/intel/metadata/bg/structure.go b/pkg/intel/metadata/bg/structure.go deleted file mode 100644 index 44fbbc68..00000000 --- a/pkg/intel/metadata/bg/structure.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package bg - -import ( - "encoding/binary" - "io" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - binaryOrder = binary.LittleEndian -) - -type StructInfo struct { - ID StructureID `json:"StructInfoID"` - Version uint8 `json:"StructInfoVersion"` -} - -func (s StructInfo) StructInfo() StructInfo { - return s -} - -type StructureID [8]byte - -func (s StructureID) String() string { - return string(s[:]) -} - -type Structure interface { - io.ReaderFrom - io.WriterTo - TotalSize() uint64 - PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string -} - -type Element interface { - Structure - ReadDataFrom(r io.Reader) (int64, error) - GetStructInfo() StructInfo - SetStructInfo(StructInfo) -} - -type ElementsContainer interface { - Structure - GetFieldByStructID(structID string) interface{} -} - -type Manifest interface { - Structure -} diff --git a/pkg/intel/metadata/bg/structure_manifestcodegen.go b/pkg/intel/metadata/bg/structure_manifestcodegen.go deleted file mode 100644 index 47d05a67..00000000 --- a/pkg/intel/metadata/bg/structure_manifestcodegen.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen -package bg github.com/linuxboot/fiano/pkg/intel/metadata/bg - -package bg - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// NewStructInfo returns a new instance of StructInfo with -// all default values set. -func NewStructInfo() *StructInfo { - s := &StructInfo{} - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *StructInfo) Validate() error { - - return nil -} - -// ReadFrom reads the StructInfo from 'r' in format defined in the document #575623. -func (s *StructInfo) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // ID (ManifestFieldType: arrayStatic) - { - n, err := 8, binary.Read(r, binary.LittleEndian, s.ID[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'ID': %w", err) - } - totalN += int64(n) - } - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Version': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *StructInfo) RehashRecursive() { - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *StructInfo) Rehash() { -} - -// WriteTo writes the StructInfo into 'w' in format defined in -// the document #575623. -func (s *StructInfo) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // ID (ManifestFieldType: arrayStatic) - { - n, err := 8, binary.Write(w, binary.LittleEndian, s.ID[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'ID': %w", err) - } - totalN += int64(n) - } - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Version': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// IDSize returns the size in bytes of the value of field ID -func (s *StructInfo) IDTotalSize() uint64 { - return 8 -} - -// VersionSize returns the size in bytes of the value of field Version -func (s *StructInfo) VersionTotalSize() uint64 { - return 1 -} - -// IDOffset returns the offset in bytes of field ID -func (s *StructInfo) IDOffset() uint64 { - return 0 -} - -// VersionOffset returns the offset in bytes of field Version -func (s *StructInfo) VersionOffset() uint64 { - return s.IDOffset() + s.IDTotalSize() -} - -// Size returns the total size of the StructInfo. -func (s *StructInfo) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.IDTotalSize() - size += s.VersionTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *StructInfo) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Struct Info", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "ID", "", &s.ID, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Version", "", &s.Version, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/bg/svn.go b/pkg/intel/metadata/bg/svn.go deleted file mode 100644 index 1b6e7db1..00000000 --- a/pkg/intel/metadata/bg/svn.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package bg - -// SVN represents Security Version Number. -type SVN uint8 - -// SVN returns the Security Version Number of an SVN field -func (svn SVN) SVN() uint8 { - return uint8(svn) & 0x0f -} diff --git a/pkg/intel/metadata/bg/svn_manifestcodegen.go b/pkg/intel/metadata/bg/svn_manifestcodegen.go deleted file mode 100644 index b4e2c18e..00000000 --- a/pkg/intel/metadata/bg/svn_manifestcodegen.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen -package bg github.com/linuxboot/fiano/pkg/intel/metadata/bg - -package bg - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v SVN) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "SVN", v)) - } - lines = append(lines, pretty.SubValue(depth+1, "SVN", "", v.SVN(), opts...)...) - return strings.Join(lines, "\n") -} - -// TotalSize returns the total size measured through binary.Size. -func (v SVN) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the SVN into 'w' in binary format. -func (v SVN) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the SVN from 'r' in binary format. -func (v SVN) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} From c095e293e3f5f36622b1644133dba5a70b1e04ae Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 9 Apr 2026 20:56:35 +0200 Subject: [PATCH 02/40] chore(intel/metadata): remove *_manifestcodegen.go files Signed-off-by: Michal Gorlas --- .../Reserved_manifestcodegen.go | 200 ---- .../cbntbootpolicy/bpmh_manifestcodegen.go | 386 ------ .../manifest_manifestcodegen.go | 454 ------- .../cbntbootpolicy/pcd_manifestcodegen.go | 246 ---- .../cbnt/cbntbootpolicy/pm_manifestcodegen.go | 252 ---- .../cbnt/cbntbootpolicy/se_manifestcodegen.go | 1061 ----------------- .../signature_manifestcodegen.go | 207 ---- .../txt_control_flags_manifestcodegen.go | 144 --- .../cbntbootpolicy/txt_manifestcodegen.go | 670 ----------- .../cbnt/cbntkey/hash_manifestcodegen.go | 186 --- .../cbnt/cbntkey/manifest_manifestcodegen.go | 461 ------- ...t_ac_module_information_manifestcodegen.go | 571 --------- .../cbnt/crypto_routines_manifestcodegen.go | 49 - .../metadata/cbnt/hash_manifestcodegen.go | 339 ------ .../metadata/cbnt/key_manifestcodegen.go | 253 ---- .../cbnt/key_signature_manifestcodegen.go | 208 ---- .../cbnt/signature_manifestcodegen.go | 258 ---- .../cbnt/structure_manifestcodegen.go | 219 ---- .../cbnt/tpm_info_list_manifestcodegen.go | 275 ----- 19 files changed, 6439 deletions(-) delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/Reserved_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/bpmh_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/manifest_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/pcd_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/pm_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/se_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/signature_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/txt_control_flags_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/txt_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/cbntkey/hash_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/cbntkey/manifest_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/chipset_ac_module_information_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/crypto_routines_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/hash_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/key_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/key_signature_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/signature_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/structure_manifestcodegen.go delete mode 100644 pkg/intel/metadata/cbnt/tpm_info_list_manifestcodegen.go diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/Reserved_manifestcodegen.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/Reserved_manifestcodegen.go deleted file mode 100644 index a3ed4475..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/Reserved_manifestcodegen.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy - -package cbntbootpolicy - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = cbnt.StructInfo{} -) - -// NewReserved returns a new instance of Reserved with -// all default values set. -func NewReserved() *Reserved { - s := &Reserved{} - copy(s.StructInfo.ID[:], []byte(StructureIDReserved)) - s.StructInfo.Version = 0x21 - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *Reserved) Validate() error { - - return nil -} - -// StructureIDReserved is the StructureID (in terms of -// the document #575623) of element 'Reserved'. -const StructureIDReserved = "__PFRS__" - -// GetStructInfo returns current value of StructInfo of the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *Reserved) GetStructInfo() cbnt.StructInfo { - return s.StructInfo -} - -// SetStructInfo sets new value of StructInfo to the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *Reserved) SetStructInfo(newStructInfo cbnt.StructInfo) { - s.StructInfo = newStructInfo -} - -// ReadFrom reads the Reserved from 'r' in format defined in the document #575623. -func (s *Reserved) ReadFrom(r io.Reader) (int64, error) { - var totalN int64 - - err := binary.Read(r, binary.LittleEndian, &s.StructInfo) - if err != nil { - return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) - } - totalN += int64(binary.Size(s.StructInfo)) - - n, err := s.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read data: %w", err) - } - totalN += n - - return totalN, nil -} - -// ReadDataFrom reads the Reserved from 'r' excluding StructInfo, -// in format defined in the document #575623. -func (s *Reserved) ReadDataFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // StructInfo (ManifestFieldType: structInfo) - { - // ReadDataFrom does not read Struct, use ReadFrom for that. - } - - // ReservedData (ManifestFieldType: arrayStatic) - { - n, err := 32, binary.Read(r, binary.LittleEndian, s.ReservedData[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'ReservedData': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *Reserved) RehashRecursive() { - s.StructInfo.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *Reserved) Rehash() { - s.Variable0 = 0 - s.ElementSize = uint16(s.TotalSize()) -} - -// WriteTo writes the Reserved into 'w' in format defined in -// the document #575623. -func (s *Reserved) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // StructInfo (ManifestFieldType: structInfo) - { - n, err := s.StructInfo.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'StructInfo': %w", err) - } - totalN += int64(n) - } - - // ReservedData (ManifestFieldType: arrayStatic) - { - n, err := 32, binary.Write(w, binary.LittleEndian, s.ReservedData[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'ReservedData': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// StructInfoSize returns the size in bytes of the value of field StructInfo -func (s *Reserved) StructInfoTotalSize() uint64 { - return s.StructInfo.TotalSize() -} - -// ReservedDataSize returns the size in bytes of the value of field ReservedData -func (s *Reserved) ReservedDataTotalSize() uint64 { - return 32 -} - -// StructInfoOffset returns the offset in bytes of field StructInfo -func (s *Reserved) StructInfoOffset() uint64 { - return 0 -} - -// ReservedDataOffset returns the offset in bytes of field ReservedData -func (s *Reserved) ReservedDataOffset() uint64 { - return s.StructInfoOffset() + s.StructInfoTotalSize() -} - -// Size returns the total size of the Reserved. -func (s *Reserved) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.StructInfoTotalSize() - size += s.ReservedDataTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *Reserved) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Reserved", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is structInfo - lines = append(lines, pretty.SubValue(depth+1, "Struct Info", "", &s.StructInfo, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved Data", "", &s.ReservedData, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/bpmh_manifestcodegen.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/bpmh_manifestcodegen.go deleted file mode 100644 index c336b58e..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/bpmh_manifestcodegen.go +++ /dev/null @@ -1,386 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy - -package cbntbootpolicy - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = cbnt.StructInfo{} -) - -// NewBPMH returns a new instance of BPMH with -// all default values set. -func NewBPMH() *BPMH { - s := &BPMH{} - copy(s.StructInfo.ID[:], []byte(StructureIDBPMH)) - s.StructInfo.Version = 0x23 - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *BPMH) Validate() error { - // See tag "require" - for idx := range s.Reserved0 { - if s.Reserved0[idx] != 0 { - return fmt.Errorf("'Reserved0[%d]' is expected to be 0, but it is %v", idx, s.Reserved0[idx]) - } - } - - return nil -} - -// StructureIDBPMH is the StructureID (in terms of -// the document #575623) of element 'BPMH'. -const StructureIDBPMH = "__ACBP__" - -// GetStructInfo returns current value of StructInfo of the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *BPMH) GetStructInfo() cbnt.StructInfo { - return s.StructInfo -} - -// SetStructInfo sets new value of StructInfo to the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *BPMH) SetStructInfo(newStructInfo cbnt.StructInfo) { - s.StructInfo = newStructInfo -} - -// ReadFrom reads the BPMH from 'r' in format defined in the document #575623. -func (s *BPMH) ReadFrom(r io.Reader) (int64, error) { - var totalN int64 - - err := binary.Read(r, binary.LittleEndian, &s.StructInfo) - if err != nil { - return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) - } - totalN += int64(binary.Size(s.StructInfo)) - - n, err := s.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read data: %w", err) - } - totalN += n - - return totalN, nil -} - -// ReadDataFrom reads the BPMH from 'r' excluding StructInfo, -// in format defined in the document #575623. -func (s *BPMH) ReadDataFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // StructInfo (ManifestFieldType: structInfo) - { - // ReadDataFrom does not read Struct, use ReadFrom for that. - } - - // KeySignatureOffset (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.KeySignatureOffset) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'KeySignatureOffset': %w", err) - } - totalN += int64(n) - } - - // BPMRevision (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.BPMRevision) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'BPMRevision': %w", err) - } - totalN += int64(n) - } - - // BPMSVN (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.BPMSVN) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'BPMSVN': %w", err) - } - totalN += int64(n) - } - - // ACMSVNAuth (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.ACMSVNAuth) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'ACMSVNAuth': %w", err) - } - totalN += int64(n) - } - - // Reserved0 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Read(r, binary.LittleEndian, s.Reserved0[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved0': %w", err) - } - totalN += int64(n) - } - - // NEMDataStack (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.NEMDataStack) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'NEMDataStack': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *BPMH) RehashRecursive() { - s.StructInfo.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *BPMH) Rehash() { - s.Variable0 = 0x20 - s.ElementSize = uint16(s.TotalSize()) -} - -// WriteTo writes the BPMH into 'w' in format defined in -// the document #575623. -func (s *BPMH) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // StructInfo (ManifestFieldType: structInfo) - { - n, err := s.StructInfo.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'StructInfo': %w", err) - } - totalN += int64(n) - } - - // KeySignatureOffset (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.KeySignatureOffset) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'KeySignatureOffset': %w", err) - } - totalN += int64(n) - } - - // BPMRevision (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.BPMRevision) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'BPMRevision': %w", err) - } - totalN += int64(n) - } - - // BPMSVN (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.BPMSVN) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'BPMSVN': %w", err) - } - totalN += int64(n) - } - - // ACMSVNAuth (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.ACMSVNAuth) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'ACMSVNAuth': %w", err) - } - totalN += int64(n) - } - - // Reserved0 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Write(w, binary.LittleEndian, s.Reserved0[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved0': %w", err) - } - totalN += int64(n) - } - - // NEMDataStack (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.NEMDataStack) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'NEMDataStack': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// StructInfoSize returns the size in bytes of the value of field StructInfo -func (s *BPMH) StructInfoTotalSize() uint64 { - return s.StructInfo.TotalSize() -} - -// KeySignatureOffsetSize returns the size in bytes of the value of field KeySignatureOffset -func (s *BPMH) KeySignatureOffsetTotalSize() uint64 { - return 2 -} - -// BPMRevisionSize returns the size in bytes of the value of field BPMRevision -func (s *BPMH) BPMRevisionTotalSize() uint64 { - return 1 -} - -// BPMSVNSize returns the size in bytes of the value of field BPMSVN -func (s *BPMH) BPMSVNTotalSize() uint64 { - return 1 -} - -// ACMSVNAuthSize returns the size in bytes of the value of field ACMSVNAuth -func (s *BPMH) ACMSVNAuthTotalSize() uint64 { - return 1 -} - -// Reserved0Size returns the size in bytes of the value of field Reserved0 -func (s *BPMH) Reserved0TotalSize() uint64 { - return 1 -} - -// NEMDataStackSize returns the size in bytes of the value of field NEMDataStack -func (s *BPMH) NEMDataStackTotalSize() uint64 { - return 2 -} - -// StructInfoOffset returns the offset in bytes of field StructInfo -func (s *BPMH) StructInfoOffset() uint64 { - return 0 -} - -// KeySignatureOffsetOffset returns the offset in bytes of field KeySignatureOffset -func (s *BPMH) KeySignatureOffsetOffset() uint64 { - return s.StructInfoOffset() + s.StructInfoTotalSize() -} - -// BPMRevisionOffset returns the offset in bytes of field BPMRevision -func (s *BPMH) BPMRevisionOffset() uint64 { - return s.KeySignatureOffsetOffset() + s.KeySignatureOffsetTotalSize() -} - -// BPMSVNOffset returns the offset in bytes of field BPMSVN -func (s *BPMH) BPMSVNOffset() uint64 { - return s.BPMRevisionOffset() + s.BPMRevisionTotalSize() -} - -// ACMSVNAuthOffset returns the offset in bytes of field ACMSVNAuth -func (s *BPMH) ACMSVNAuthOffset() uint64 { - return s.BPMSVNOffset() + s.BPMSVNTotalSize() -} - -// Reserved0Offset returns the offset in bytes of field Reserved0 -func (s *BPMH) Reserved0Offset() uint64 { - return s.ACMSVNAuthOffset() + s.ACMSVNAuthTotalSize() -} - -// NEMDataStackOffset returns the offset in bytes of field NEMDataStack -func (s *BPMH) NEMDataStackOffset() uint64 { - return s.Reserved0Offset() + s.Reserved0TotalSize() -} - -// Size returns the total size of the BPMH. -func (s *BPMH) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.StructInfoTotalSize() - size += s.KeySignatureOffsetTotalSize() - size += s.BPMRevisionTotalSize() - size += s.BPMSVNTotalSize() - size += s.ACMSVNAuthTotalSize() - size += s.Reserved0TotalSize() - size += s.NEMDataStackTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *BPMH) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "BPMH", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is structInfo - lines = append(lines, pretty.SubValue(depth+1, "Struct Info", "", &s.StructInfo, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Key Signature Offset", "", &s.KeySignatureOffset, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "BPM Revision", "", &s.BPMRevision, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "BPM SVN", "", &s.BPMSVN, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "ACM SVN Auth", "", &s.ACMSVNAuth, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved 0", "", &s.Reserved0, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "NEM Data Stack", "", &s.NEMDataStack, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v Size4K) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Size 4 K", v)) - } - lines = append(lines, pretty.SubValue(depth+1, "In Bytes", "", v.InBytes(), opts...)...) - return strings.Join(lines, "\n") -} - -// TotalSize returns the total size measured through binary.Size. -func (v Size4K) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the Size4K into 'w' in binary format. -func (v Size4K) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the Size4K from 'r' in binary format. -func (v Size4K) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/manifest_manifestcodegen.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/manifest_manifestcodegen.go deleted file mode 100644 index 89a53843..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/manifest_manifestcodegen.go +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy - -package cbntbootpolicy - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = cbnt.StructInfo{} -) - -// NewManifest returns a new instance of Manifest with -// all default values set. -func NewManifest() *Manifest { - s := &Manifest{} - // Recursively initializing a child structure: - s.BPMH = *NewBPMH() - // Recursively initializing a child structure: - s.PMSE = *NewSignature() - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *Manifest) Validate() error { - // Recursively validating a child structure: - if err := s.BPMH.Validate(); err != nil { - return fmt.Errorf("error on field 'BPMH': %w", err) - } - // See tag "rehashValue" - { - expectedValue := BPMH(s.rehashedBPMH()) - if s.BPMH != expectedValue { - return fmt.Errorf("field 'BPMH' expects write-value '%v', but has %v", expectedValue, s.BPMH) - } - } - // Recursively validating a child structure: - if err := s.PMSE.Validate(); err != nil { - return fmt.Errorf("error on field 'PMSE': %w", err) - } - - return nil -} - -// fieldIndexByStructID returns the position index within -// structure Manifest of the field by its StructureID -// (see document #575623, an example of StructureID value is "__KEYM__"). -func (_ Manifest) fieldIndexByStructID(structID string) int { - switch structID { - case StructureIDBPMH: - return 0 - case StructureIDSE: - return 1 - case StructureIDTXT: - return 2 - case StructureIDReserved: - return 3 - case StructureIDPCD: - return 4 - case StructureIDPM: - return 5 - case StructureIDSignature: - return 6 - } - - return -1 -} - -// fieldNameByIndex returns the name of the field by its position number -// within structure Manifest. -func (_ Manifest) fieldNameByIndex(fieldIndex int) string { - switch fieldIndex { - case 0: - return "BPMH" - case 1: - return "SE" - case 2: - return "TXTE" - case 3: - return "Res" - case 4: - return "PCDE" - case 5: - return "PME" - case 6: - return "PMSE" - } - - return fmt.Sprintf("invalidFieldIndex_%d", fieldIndex) -} - -// ReadFrom reads the Manifest from 'r' in format defined in the document #575623. -func (s *Manifest) ReadFrom(r io.Reader) (returnN int64, returnErr error) { - var missingFieldsByIndices = [7]bool{ - 0: true, - 6: true, - } - defer func() { - if returnErr != nil { - return - } - for fieldIndex, v := range missingFieldsByIndices { - if v { - returnErr = fmt.Errorf("field '%s' is missing", s.fieldNameByIndex(fieldIndex)) - break - } - } - }() - var totalN int64 - previousFieldIndex := int(-1) - for { - var structInfo cbnt.StructInfo - err := binary.Read(r, binary.LittleEndian, &structInfo) - if err == io.EOF || err == io.ErrUnexpectedEOF { - return totalN, nil - } - if err != nil { - return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) - } - totalN += int64(binary.Size(structInfo)) - - structID := structInfo.ID.String() - fieldIndex := s.fieldIndexByStructID(structID) - if fieldIndex < 0 { - // TODO: report error "unknown structure ID: '"+structID+"'" - continue - } - if cbnt.StrictOrderCheck && fieldIndex < previousFieldIndex { - return totalN, fmt.Errorf("invalid order of fields (%d < %d): structure '%s' is out of order", fieldIndex, previousFieldIndex, structID) - } - missingFieldsByIndices[fieldIndex] = false - - var n int64 - switch structID { - case StructureIDBPMH: - if fieldIndex == previousFieldIndex { - return totalN, fmt.Errorf("field 'BPMH' is not a slice, but multiple elements found") - } - s.BPMH.SetStructInfo(structInfo) - n, err = s.BPMH.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field BPMH at %d: %w", totalN, err) - } - case StructureIDSE: - var el SE - el.SetStructInfo(structInfo) - n, err = el.ReadDataFrom(r) - s.SE = append(s.SE, el) - if err != nil { - return totalN, fmt.Errorf("unable to read field SE at %d: %w", totalN, err) - } - case StructureIDTXT: - if fieldIndex == previousFieldIndex { - return totalN, fmt.Errorf("field 'TXTE' is not a slice, but multiple elements found") - } - s.TXTE = &TXT{} - s.TXTE.SetStructInfo(structInfo) - n, err = s.TXTE.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field TXTE at %d: %w", totalN, err) - } - case StructureIDReserved: - if fieldIndex == previousFieldIndex { - return totalN, fmt.Errorf("field 'Res' is not a slice, but multiple elements found") - } - s.Res = &Reserved{} - s.Res.SetStructInfo(structInfo) - n, err = s.Res.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field Res at %d: %w", totalN, err) - } - case StructureIDPCD: - if fieldIndex == previousFieldIndex { - return totalN, fmt.Errorf("field 'PCDE' is not a slice, but multiple elements found") - } - s.PCDE = &PCD{} - s.PCDE.SetStructInfo(structInfo) - n, err = s.PCDE.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field PCDE at %d: %w", totalN, err) - } - case StructureIDPM: - if fieldIndex == previousFieldIndex { - return totalN, fmt.Errorf("field 'PME' is not a slice, but multiple elements found") - } - s.PME = &PM{} - s.PME.SetStructInfo(structInfo) - n, err = s.PME.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field PME at %d: %w", totalN, err) - } - case StructureIDSignature: - if fieldIndex == previousFieldIndex { - return totalN, fmt.Errorf("field 'PMSE' is not a slice, but multiple elements found") - } - s.PMSE.SetStructInfo(structInfo) - n, err = s.PMSE.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field PMSE at %d: %w", totalN, err) - } - default: - return totalN, fmt.Errorf("there is no field with structure ID '%s' in Manifest", structInfo.ID) - } - totalN += n - previousFieldIndex = fieldIndex - } -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *Manifest) RehashRecursive() { - s.BPMH.Rehash() - if s.TXTE != nil { - s.TXTE.Rehash() - } - if s.Res != nil { - s.Res.Rehash() - } - if s.PCDE != nil { - s.PCDE.Rehash() - } - if s.PME != nil { - s.PME.Rehash() - } - s.PMSE.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *Manifest) Rehash() { - s.BPMH = BPMH(s.rehashedBPMH()) -} - -// WriteTo writes the Manifest into 'w' in format defined in -// the document #575623. -func (s *Manifest) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // BPMH (ManifestFieldType: element) - { - n, err := s.BPMH.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'BPMH': %w", err) - } - totalN += int64(n) - } - - // SE (ManifestFieldType: elementList) - { - for idx := range s.SE { - n, err := s.SE[idx].WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'SE[%d]': %w", idx, err) - } - totalN += int64(n) - } - } - - // TXTE (ManifestFieldType: element) - if s.TXTE != nil { - n, err := s.TXTE.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'TXTE': %w", err) - } - totalN += int64(n) - } - - // Res (ManifestFieldType: element) - if s.Res != nil { - n, err := s.Res.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Res': %w", err) - } - totalN += int64(n) - } - - // PCDE (ManifestFieldType: element) - if s.PCDE != nil { - n, err := s.PCDE.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PCDE': %w", err) - } - totalN += int64(n) - } - - // PME (ManifestFieldType: element) - if s.PME != nil { - n, err := s.PME.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PME': %w", err) - } - totalN += int64(n) - } - - // PMSE (ManifestFieldType: element) - { - n, err := s.PMSE.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PMSE': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// BPMHSize returns the size in bytes of the value of field BPMH -func (s *Manifest) BPMHTotalSize() uint64 { - return s.BPMH.TotalSize() -} - -// SESize returns the size in bytes of the value of field SE -func (s *Manifest) SETotalSize() uint64 { - var size uint64 - for idx := range s.SE { - size += s.SE[idx].TotalSize() - } - return size -} - -// TXTESize returns the size in bytes of the value of field TXTE -func (s *Manifest) TXTETotalSize() uint64 { - return s.TXTE.TotalSize() -} - -// ResSize returns the size in bytes of the value of field Res -func (s *Manifest) ResTotalSize() uint64 { - return s.Res.TotalSize() -} - -// PCDESize returns the size in bytes of the value of field PCDE -func (s *Manifest) PCDETotalSize() uint64 { - return s.PCDE.TotalSize() -} - -// PMESize returns the size in bytes of the value of field PME -func (s *Manifest) PMETotalSize() uint64 { - return s.PME.TotalSize() -} - -// PMSESize returns the size in bytes of the value of field PMSE -func (s *Manifest) PMSETotalSize() uint64 { - return s.PMSE.TotalSize() -} - -// BPMHOffset returns the offset in bytes of field BPMH -func (s *Manifest) BPMHOffset() uint64 { - return 0 -} - -// SEOffset returns the offset in bytes of field SE -func (s *Manifest) SEOffset() uint64 { - return s.BPMHOffset() + s.BPMHTotalSize() -} - -// TXTEOffset returns the offset in bytes of field TXTE -func (s *Manifest) TXTEOffset() uint64 { - return s.SEOffset() + s.SETotalSize() -} - -// ResOffset returns the offset in bytes of field Res -func (s *Manifest) ResOffset() uint64 { - return s.TXTEOffset() + s.TXTETotalSize() -} - -// PCDEOffset returns the offset in bytes of field PCDE -func (s *Manifest) PCDEOffset() uint64 { - return s.ResOffset() + s.ResTotalSize() -} - -// PMEOffset returns the offset in bytes of field PME -func (s *Manifest) PMEOffset() uint64 { - return s.PCDEOffset() + s.PCDETotalSize() -} - -// PMSEOffset returns the offset in bytes of field PMSE -func (s *Manifest) PMSEOffset() uint64 { - return s.PMEOffset() + s.PMETotalSize() -} - -// Size returns the total size of the Manifest. -func (s *Manifest) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.BPMHTotalSize() - size += s.SETotalSize() - size += s.TXTETotalSize() - size += s.ResTotalSize() - size += s.PCDETotalSize() - size += s.PMETotalSize() - size += s.PMSETotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *Manifest) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Boot Policy Manifest", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is element - lines = append(lines, pretty.SubValue(depth+1, "BPMH: Header", "", &s.BPMH, opts...)...) - // ManifestFieldType is elementList - lines = append(lines, pretty.Header(depth+1, fmt.Sprintf("SE: Array of \"Boot Policy Manifest\" of length %d", len(s.SE)), s.SE)) - for i := 0; i < len(s.SE); i++ { - lines = append(lines, fmt.Sprintf("%sitem #%d: ", strings.Repeat(" ", int(depth+2)), i)+strings.TrimSpace(s.SE[i].PrettyString(depth+2, true))) - } - if depth < 1 { - lines = append(lines, "") - } - // ManifestFieldType is element - lines = append(lines, pretty.SubValue(depth+1, "TXTE", "", s.TXTE, opts...)...) - // ManifestFieldType is element - lines = append(lines, pretty.SubValue(depth+1, "Res", "", s.Res, opts...)...) - // ManifestFieldType is element - lines = append(lines, pretty.SubValue(depth+1, "PCDE: Platform Config Data", "", s.PCDE, opts...)...) - // ManifestFieldType is element - lines = append(lines, pretty.SubValue(depth+1, "PME: Platform Manufacturer", "", s.PME, opts...)...) - // ManifestFieldType is element - lines = append(lines, pretty.SubValue(depth+1, "PMSE: Signature", "", &s.PMSE, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/pcd_manifestcodegen.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/pcd_manifestcodegen.go deleted file mode 100644 index 63ad3e3a..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/pcd_manifestcodegen.go +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy - -package cbntbootpolicy - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = cbnt.StructInfo{} -) - -// NewPCD returns a new instance of PCD with -// all default values set. -func NewPCD() *PCD { - s := &PCD{} - copy(s.StructInfo.ID[:], []byte(StructureIDPCD)) - s.StructInfo.Version = 0x20 - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *PCD) Validate() error { - - return nil -} - -// StructureIDPCD is the StructureID (in terms of -// the document #575623) of element 'PCD'. -const StructureIDPCD = "__PCDS__" - -// GetStructInfo returns current value of StructInfo of the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *PCD) GetStructInfo() cbnt.StructInfo { - return s.StructInfo -} - -// SetStructInfo sets new value of StructInfo to the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *PCD) SetStructInfo(newStructInfo cbnt.StructInfo) { - s.StructInfo = newStructInfo -} - -// ReadFrom reads the PCD from 'r' in format defined in the document #575623. -func (s *PCD) ReadFrom(r io.Reader) (int64, error) { - var totalN int64 - - err := binary.Read(r, binary.LittleEndian, &s.StructInfo) - if err != nil { - return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) - } - totalN += int64(binary.Size(s.StructInfo)) - - n, err := s.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read data: %w", err) - } - totalN += n - - return totalN, nil -} - -// ReadDataFrom reads the PCD from 'r' excluding StructInfo, -// in format defined in the document #575623. -func (s *PCD) ReadDataFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // StructInfo (ManifestFieldType: structInfo) - { - // ReadDataFrom does not read Struct, use ReadFrom for that. - } - - // Reserved0 (ManifestFieldType: arrayStatic) - { - n, err := 2, binary.Read(r, binary.LittleEndian, s.Reserved0[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved0': %w", err) - } - totalN += int64(n) - } - - // Data (ManifestFieldType: arrayDynamic) - { - var size uint16 - err := binary.Read(r, binary.LittleEndian, &size) - if err != nil { - return totalN, fmt.Errorf("unable to the read size of field 'Data': %w", err) - } - totalN += int64(binary.Size(size)) - s.Data = make([]byte, size) - n, err := len(s.Data), binary.Read(r, binary.LittleEndian, s.Data) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Data': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *PCD) RehashRecursive() { - s.StructInfo.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *PCD) Rehash() { - s.Variable0 = 0 - s.ElementSize = uint16(s.TotalSize()) -} - -// WriteTo writes the PCD into 'w' in format defined in -// the document #575623. -func (s *PCD) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // StructInfo (ManifestFieldType: structInfo) - { - n, err := s.StructInfo.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'StructInfo': %w", err) - } - totalN += int64(n) - } - - // Reserved0 (ManifestFieldType: arrayStatic) - { - n, err := 2, binary.Write(w, binary.LittleEndian, s.Reserved0[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved0': %w", err) - } - totalN += int64(n) - } - - // Data (ManifestFieldType: arrayDynamic) - { - size := uint16(len(s.Data)) - err := binary.Write(w, binary.LittleEndian, size) - if err != nil { - return totalN, fmt.Errorf("unable to write the size of field 'Data': %w", err) - } - totalN += int64(binary.Size(size)) - n, err := len(s.Data), binary.Write(w, binary.LittleEndian, s.Data) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Data': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// StructInfoSize returns the size in bytes of the value of field StructInfo -func (s *PCD) StructInfoTotalSize() uint64 { - return s.StructInfo.TotalSize() -} - -// Reserved0Size returns the size in bytes of the value of field Reserved0 -func (s *PCD) Reserved0TotalSize() uint64 { - return 2 -} - -// DataSize returns the size in bytes of the value of field Data -func (s *PCD) DataTotalSize() uint64 { - size := uint64(binary.Size(uint16(0))) - size += uint64(len(s.Data)) - return size -} - -// StructInfoOffset returns the offset in bytes of field StructInfo -func (s *PCD) StructInfoOffset() uint64 { - return 0 -} - -// Reserved0Offset returns the offset in bytes of field Reserved0 -func (s *PCD) Reserved0Offset() uint64 { - return s.StructInfoOffset() + s.StructInfoTotalSize() -} - -// DataOffset returns the offset in bytes of field Data -func (s *PCD) DataOffset() uint64 { - return s.Reserved0Offset() + s.Reserved0TotalSize() -} - -// Size returns the total size of the PCD. -func (s *PCD) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.StructInfoTotalSize() - size += s.Reserved0TotalSize() - size += s.DataTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *PCD) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "PCD", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is structInfo - lines = append(lines, pretty.SubValue(depth+1, "Struct Info", "", &s.StructInfo, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved 0", "", &s.Reserved0, opts...)...) - // ManifestFieldType is arrayDynamic - lines = append(lines, pretty.SubValue(depth+1, "Data", "", &s.Data, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/pm_manifestcodegen.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/pm_manifestcodegen.go deleted file mode 100644 index 6054707c..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/pm_manifestcodegen.go +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy - -package cbntbootpolicy - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = cbnt.StructInfo{} -) - -// NewPM returns a new instance of PM with -// all default values set. -func NewPM() *PM { - s := &PM{} - copy(s.StructInfo.ID[:], []byte(StructureIDPM)) - s.StructInfo.Version = 0x20 - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *PM) Validate() error { - // See tag "require" - for idx := range s.Reserved0 { - if s.Reserved0[idx] != 0 { - return fmt.Errorf("'Reserved0[%d]' is expected to be 0, but it is %v", idx, s.Reserved0[idx]) - } - } - - return nil -} - -// StructureIDPM is the StructureID (in terms of -// the document #575623) of element 'PM'. -const StructureIDPM = "__PMDA__" - -// GetStructInfo returns current value of StructInfo of the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *PM) GetStructInfo() cbnt.StructInfo { - return s.StructInfo -} - -// SetStructInfo sets new value of StructInfo to the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *PM) SetStructInfo(newStructInfo cbnt.StructInfo) { - s.StructInfo = newStructInfo -} - -// ReadFrom reads the PM from 'r' in format defined in the document #575623. -func (s *PM) ReadFrom(r io.Reader) (int64, error) { - var totalN int64 - - err := binary.Read(r, binary.LittleEndian, &s.StructInfo) - if err != nil { - return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) - } - totalN += int64(binary.Size(s.StructInfo)) - - n, err := s.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read data: %w", err) - } - totalN += n - - return totalN, nil -} - -// ReadDataFrom reads the PM from 'r' excluding StructInfo, -// in format defined in the document #575623. -func (s *PM) ReadDataFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // StructInfo (ManifestFieldType: structInfo) - { - // ReadDataFrom does not read Struct, use ReadFrom for that. - } - - // Reserved0 (ManifestFieldType: arrayStatic) - { - n, err := 2, binary.Read(r, binary.LittleEndian, s.Reserved0[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved0': %w", err) - } - totalN += int64(n) - } - - // Data (ManifestFieldType: arrayDynamic) - { - var size uint16 - err := binary.Read(r, binary.LittleEndian, &size) - if err != nil { - return totalN, fmt.Errorf("unable to the read size of field 'Data': %w", err) - } - totalN += int64(binary.Size(size)) - s.Data = make([]byte, size) - n, err := len(s.Data), binary.Read(r, binary.LittleEndian, s.Data) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Data': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *PM) RehashRecursive() { - s.StructInfo.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *PM) Rehash() { - s.Variable0 = 0 - s.ElementSize = uint16(s.TotalSize()) -} - -// WriteTo writes the PM into 'w' in format defined in -// the document #575623. -func (s *PM) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // StructInfo (ManifestFieldType: structInfo) - { - n, err := s.StructInfo.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'StructInfo': %w", err) - } - totalN += int64(n) - } - - // Reserved0 (ManifestFieldType: arrayStatic) - { - n, err := 2, binary.Write(w, binary.LittleEndian, s.Reserved0[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved0': %w", err) - } - totalN += int64(n) - } - - // Data (ManifestFieldType: arrayDynamic) - { - size := uint16(len(s.Data)) - err := binary.Write(w, binary.LittleEndian, size) - if err != nil { - return totalN, fmt.Errorf("unable to write the size of field 'Data': %w", err) - } - totalN += int64(binary.Size(size)) - n, err := len(s.Data), binary.Write(w, binary.LittleEndian, s.Data) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Data': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// StructInfoSize returns the size in bytes of the value of field StructInfo -func (s *PM) StructInfoTotalSize() uint64 { - return s.StructInfo.TotalSize() -} - -// Reserved0Size returns the size in bytes of the value of field Reserved0 -func (s *PM) Reserved0TotalSize() uint64 { - return 2 -} - -// DataSize returns the size in bytes of the value of field Data -func (s *PM) DataTotalSize() uint64 { - size := uint64(binary.Size(uint16(0))) - size += uint64(len(s.Data)) - return size -} - -// StructInfoOffset returns the offset in bytes of field StructInfo -func (s *PM) StructInfoOffset() uint64 { - return 0 -} - -// Reserved0Offset returns the offset in bytes of field Reserved0 -func (s *PM) Reserved0Offset() uint64 { - return s.StructInfoOffset() + s.StructInfoTotalSize() -} - -// DataOffset returns the offset in bytes of field Data -func (s *PM) DataOffset() uint64 { - return s.Reserved0Offset() + s.Reserved0TotalSize() -} - -// Size returns the total size of the PM. -func (s *PM) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.StructInfoTotalSize() - size += s.Reserved0TotalSize() - size += s.DataTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *PM) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "PM", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is structInfo - lines = append(lines, pretty.SubValue(depth+1, "Struct Info", "", &s.StructInfo, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved 0", "", &s.Reserved0, opts...)...) - // ManifestFieldType is arrayDynamic - lines = append(lines, pretty.SubValue(depth+1, "Data", "", &s.Data, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/se_manifestcodegen.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/se_manifestcodegen.go deleted file mode 100644 index ce5b82da..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/se_manifestcodegen.go +++ /dev/null @@ -1,1061 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy - -package cbntbootpolicy - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = cbnt.StructInfo{} -) - -// NewIBBSegment returns a new instance of IBBSegment with -// all default values set. -func NewIBBSegment() *IBBSegment { - s := &IBBSegment{} - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *IBBSegment) Validate() error { - // See tag "require" - for idx := range s.Reserved { - if s.Reserved[idx] != 0 { - return fmt.Errorf("'Reserved[%d]' is expected to be 0, but it is %v", idx, s.Reserved[idx]) - } - } - - return nil -} - -// ReadFrom reads the IBBSegment from 'r' in format defined in the document #575623. -func (s *IBBSegment) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // Reserved (ManifestFieldType: arrayStatic) - { - n, err := 2, binary.Read(r, binary.LittleEndian, s.Reserved[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved': %w", err) - } - totalN += int64(n) - } - - // Flags (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.Flags) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Flags': %w", err) - } - totalN += int64(n) - } - - // Base (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.Base) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Base': %w", err) - } - totalN += int64(n) - } - - // Size (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.Size) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Size': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *IBBSegment) RehashRecursive() { - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *IBBSegment) Rehash() { -} - -// WriteTo writes the IBBSegment into 'w' in format defined in -// the document #575623. -func (s *IBBSegment) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // Reserved (ManifestFieldType: arrayStatic) - { - n, err := 2, binary.Write(w, binary.LittleEndian, s.Reserved[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved': %w", err) - } - totalN += int64(n) - } - - // Flags (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.Flags) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Flags': %w", err) - } - totalN += int64(n) - } - - // Base (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.Base) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Base': %w", err) - } - totalN += int64(n) - } - - // Size (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.Size) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Size': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// ReservedSize returns the size in bytes of the value of field Reserved -func (s *IBBSegment) ReservedTotalSize() uint64 { - return 2 -} - -// FlagsSize returns the size in bytes of the value of field Flags -func (s *IBBSegment) FlagsTotalSize() uint64 { - return 2 -} - -// BaseSize returns the size in bytes of the value of field Base -func (s *IBBSegment) BaseTotalSize() uint64 { - return 4 -} - -// SizeSize returns the size in bytes of the value of field Size -func (s *IBBSegment) SizeTotalSize() uint64 { - return 4 -} - -// ReservedOffset returns the offset in bytes of field Reserved -func (s *IBBSegment) ReservedOffset() uint64 { - return 0 -} - -// FlagsOffset returns the offset in bytes of field Flags -func (s *IBBSegment) FlagsOffset() uint64 { - return s.ReservedOffset() + s.ReservedTotalSize() -} - -// BaseOffset returns the offset in bytes of field Base -func (s *IBBSegment) BaseOffset() uint64 { - return s.FlagsOffset() + s.FlagsTotalSize() -} - -// SizeOffset returns the offset in bytes of field Size -func (s *IBBSegment) SizeOffset() uint64 { - return s.BaseOffset() + s.BaseTotalSize() -} - -// Size returns the total size of the IBBSegment. -func (s *IBBSegment) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.ReservedTotalSize() - size += s.FlagsTotalSize() - size += s.BaseTotalSize() - size += s.SizeTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *IBBSegment) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "IBB Segment", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved", "", &s.Reserved, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Flags", "", &s.Flags, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Base", "", &s.Base, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Size", "", &s.Size, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} - -// NewSE returns a new instance of SE with -// all default values set. -func NewSE() *SE { - s := &SE{} - copy(s.StructInfo.ID[:], []byte(StructureIDSE)) - s.StructInfo.Version = 0x20 - // Set through tag "required": - s.SetNumber = 0 - // Recursively initializing a child structure: - s.PostIBBHash = *cbnt.NewHashStructure() - // Recursively initializing a child structure: - s.DigestList = *cbnt.NewHashList() - // Recursively initializing a child structure: - s.OBBHash = *cbnt.NewHashStructure() - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *SE) Validate() error { - // See tag "require" - for idx := range s.Reserved0 { - if s.Reserved0[idx] != 0 { - return fmt.Errorf("'Reserved0[%d]' is expected to be 0, but it is %v", idx, s.Reserved0[idx]) - } - } - // See tag "require" - if s.SetNumber != 0 { - return fmt.Errorf("field 'SetNumber' expects value '0', but has %v", s.SetNumber) - } - // See tag "require" - for idx := range s.Reserved1 { - if s.Reserved1[idx] != 0 { - return fmt.Errorf("'Reserved1[%d]' is expected to be 0, but it is %v", idx, s.Reserved1[idx]) - } - } - // Recursively validating a child structure: - if err := s.PostIBBHash.Validate(); err != nil { - return fmt.Errorf("error on field 'PostIBBHash': %w", err) - } - // Recursively validating a child structure: - if err := s.DigestList.Validate(); err != nil { - return fmt.Errorf("error on field 'DigestList': %w", err) - } - // Recursively validating a child structure: - if err := s.OBBHash.Validate(); err != nil { - return fmt.Errorf("error on field 'OBBHash': %w", err) - } - // See tag "require" - for idx := range s.Reserved2 { - if s.Reserved2[idx] != 0 { - return fmt.Errorf("'Reserved2[%d]' is expected to be 0, but it is %v", idx, s.Reserved2[idx]) - } - } - - return nil -} - -// StructureIDSE is the StructureID (in terms of -// the document #575623) of element 'SE'. -const StructureIDSE = "__IBBS__" - -// GetStructInfo returns current value of StructInfo of the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *SE) GetStructInfo() cbnt.StructInfo { - return s.StructInfo -} - -// SetStructInfo sets new value of StructInfo to the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *SE) SetStructInfo(newStructInfo cbnt.StructInfo) { - s.StructInfo = newStructInfo -} - -// ReadFrom reads the SE from 'r' in format defined in the document #575623. -func (s *SE) ReadFrom(r io.Reader) (int64, error) { - var totalN int64 - - err := binary.Read(r, binary.LittleEndian, &s.StructInfo) - if err != nil { - return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) - } - totalN += int64(binary.Size(s.StructInfo)) - - n, err := s.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read data: %w", err) - } - totalN += n - - return totalN, nil -} - -// ReadDataFrom reads the SE from 'r' excluding StructInfo, -// in format defined in the document #575623. -func (s *SE) ReadDataFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // StructInfo (ManifestFieldType: structInfo) - { - // ReadDataFrom does not read Struct, use ReadFrom for that. - } - - // Reserved0 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Read(r, binary.LittleEndian, s.Reserved0[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved0': %w", err) - } - totalN += int64(n) - } - - // SetNumber (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.SetNumber) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'SetNumber': %w", err) - } - totalN += int64(n) - } - - // Reserved1 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Read(r, binary.LittleEndian, s.Reserved1[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved1': %w", err) - } - totalN += int64(n) - } - - // PBETValue (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.PBETValue) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'PBETValue': %w", err) - } - totalN += int64(n) - } - - // Flags (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.Flags) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Flags': %w", err) - } - totalN += int64(n) - } - - // IBBMCHBAR (ManifestFieldType: endValue) - { - n, err := 8, binary.Read(r, binary.LittleEndian, &s.IBBMCHBAR) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'IBBMCHBAR': %w", err) - } - totalN += int64(n) - } - - // VTdBAR (ManifestFieldType: endValue) - { - n, err := 8, binary.Read(r, binary.LittleEndian, &s.VTdBAR) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'VTdBAR': %w", err) - } - totalN += int64(n) - } - - // DMAProtBase0 (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.DMAProtBase0) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'DMAProtBase0': %w", err) - } - totalN += int64(n) - } - - // DMAProtLimit0 (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.DMAProtLimit0) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'DMAProtLimit0': %w", err) - } - totalN += int64(n) - } - - // DMAProtBase1 (ManifestFieldType: endValue) - { - n, err := 8, binary.Read(r, binary.LittleEndian, &s.DMAProtBase1) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'DMAProtBase1': %w", err) - } - totalN += int64(n) - } - - // DMAProtLimit1 (ManifestFieldType: endValue) - { - n, err := 8, binary.Read(r, binary.LittleEndian, &s.DMAProtLimit1) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'DMAProtLimit1': %w", err) - } - totalN += int64(n) - } - - // PostIBBHash (ManifestFieldType: subStruct) - { - n, err := s.PostIBBHash.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'PostIBBHash': %w", err) - } - totalN += int64(n) - } - - // IBBEntryPoint (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.IBBEntryPoint) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'IBBEntryPoint': %w", err) - } - totalN += int64(n) - } - - // DigestList (ManifestFieldType: subStruct) - { - n, err := s.DigestList.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'DigestList': %w", err) - } - totalN += int64(n) - } - - // OBBHash (ManifestFieldType: subStruct) - { - n, err := s.OBBHash.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'OBBHash': %w", err) - } - totalN += int64(n) - } - - // Reserved2 (ManifestFieldType: arrayStatic) - { - n, err := 3, binary.Read(r, binary.LittleEndian, s.Reserved2[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved2': %w", err) - } - totalN += int64(n) - } - - // IBBSegments (ManifestFieldType: list) - { - var count uint8 - err := binary.Read(r, binary.LittleEndian, &count) - if err != nil { - return totalN, fmt.Errorf("unable to read the count for field 'IBBSegments': %w", err) - } - totalN += int64(binary.Size(count)) - s.IBBSegments = make([]IBBSegment, count) - - for idx := range s.IBBSegments { - n, err := s.IBBSegments[idx].ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'IBBSegments[%d]': %w", idx, err) - } - totalN += int64(n) - } - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *SE) RehashRecursive() { - s.StructInfo.Rehash() - s.PostIBBHash.Rehash() - s.DigestList.Rehash() - s.OBBHash.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *SE) Rehash() { - s.Variable0 = 0 - s.ElementSize = uint16(s.TotalSize()) -} - -// WriteTo writes the SE into 'w' in format defined in -// the document #575623. -func (s *SE) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // StructInfo (ManifestFieldType: structInfo) - { - n, err := s.StructInfo.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'StructInfo': %w", err) - } - totalN += int64(n) - } - - // Reserved0 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Write(w, binary.LittleEndian, s.Reserved0[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved0': %w", err) - } - totalN += int64(n) - } - - // SetNumber (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.SetNumber) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'SetNumber': %w", err) - } - totalN += int64(n) - } - - // Reserved1 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Write(w, binary.LittleEndian, s.Reserved1[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved1': %w", err) - } - totalN += int64(n) - } - - // PBETValue (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.PBETValue) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PBETValue': %w", err) - } - totalN += int64(n) - } - - // Flags (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.Flags) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Flags': %w", err) - } - totalN += int64(n) - } - - // IBBMCHBAR (ManifestFieldType: endValue) - { - n, err := 8, binary.Write(w, binary.LittleEndian, &s.IBBMCHBAR) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'IBBMCHBAR': %w", err) - } - totalN += int64(n) - } - - // VTdBAR (ManifestFieldType: endValue) - { - n, err := 8, binary.Write(w, binary.LittleEndian, &s.VTdBAR) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'VTdBAR': %w", err) - } - totalN += int64(n) - } - - // DMAProtBase0 (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.DMAProtBase0) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'DMAProtBase0': %w", err) - } - totalN += int64(n) - } - - // DMAProtLimit0 (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.DMAProtLimit0) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'DMAProtLimit0': %w", err) - } - totalN += int64(n) - } - - // DMAProtBase1 (ManifestFieldType: endValue) - { - n, err := 8, binary.Write(w, binary.LittleEndian, &s.DMAProtBase1) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'DMAProtBase1': %w", err) - } - totalN += int64(n) - } - - // DMAProtLimit1 (ManifestFieldType: endValue) - { - n, err := 8, binary.Write(w, binary.LittleEndian, &s.DMAProtLimit1) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'DMAProtLimit1': %w", err) - } - totalN += int64(n) - } - - // PostIBBHash (ManifestFieldType: subStruct) - { - n, err := s.PostIBBHash.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PostIBBHash': %w", err) - } - totalN += int64(n) - } - - // IBBEntryPoint (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.IBBEntryPoint) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'IBBEntryPoint': %w", err) - } - totalN += int64(n) - } - - // DigestList (ManifestFieldType: subStruct) - { - n, err := s.DigestList.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'DigestList': %w", err) - } - totalN += int64(n) - } - - // OBBHash (ManifestFieldType: subStruct) - { - n, err := s.OBBHash.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'OBBHash': %w", err) - } - totalN += int64(n) - } - - // Reserved2 (ManifestFieldType: arrayStatic) - { - n, err := 3, binary.Write(w, binary.LittleEndian, s.Reserved2[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved2': %w", err) - } - totalN += int64(n) - } - - // IBBSegments (ManifestFieldType: list) - { - count := uint8(len(s.IBBSegments)) - err := binary.Write(w, binary.LittleEndian, &count) - if err != nil { - return totalN, fmt.Errorf("unable to write the count for field 'IBBSegments': %w", err) - } - totalN += int64(binary.Size(count)) - for idx := range s.IBBSegments { - n, err := s.IBBSegments[idx].WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'IBBSegments[%d]': %w", idx, err) - } - totalN += int64(n) - } - } - - return totalN, nil -} - -// StructInfoSize returns the size in bytes of the value of field StructInfo -func (s *SE) StructInfoTotalSize() uint64 { - return s.StructInfo.TotalSize() -} - -// Reserved0Size returns the size in bytes of the value of field Reserved0 -func (s *SE) Reserved0TotalSize() uint64 { - return 1 -} - -// SetNumberSize returns the size in bytes of the value of field SetNumber -func (s *SE) SetNumberTotalSize() uint64 { - return 1 -} - -// Reserved1Size returns the size in bytes of the value of field Reserved1 -func (s *SE) Reserved1TotalSize() uint64 { - return 1 -} - -// PBETValueSize returns the size in bytes of the value of field PBETValue -func (s *SE) PBETValueTotalSize() uint64 { - return 1 -} - -// FlagsSize returns the size in bytes of the value of field Flags -func (s *SE) FlagsTotalSize() uint64 { - return 4 -} - -// IBBMCHBARSize returns the size in bytes of the value of field IBBMCHBAR -func (s *SE) IBBMCHBARTotalSize() uint64 { - return 8 -} - -// VTdBARSize returns the size in bytes of the value of field VTdBAR -func (s *SE) VTdBARTotalSize() uint64 { - return 8 -} - -// DMAProtBase0Size returns the size in bytes of the value of field DMAProtBase0 -func (s *SE) DMAProtBase0TotalSize() uint64 { - return 4 -} - -// DMAProtLimit0Size returns the size in bytes of the value of field DMAProtLimit0 -func (s *SE) DMAProtLimit0TotalSize() uint64 { - return 4 -} - -// DMAProtBase1Size returns the size in bytes of the value of field DMAProtBase1 -func (s *SE) DMAProtBase1TotalSize() uint64 { - return 8 -} - -// DMAProtLimit1Size returns the size in bytes of the value of field DMAProtLimit1 -func (s *SE) DMAProtLimit1TotalSize() uint64 { - return 8 -} - -// PostIBBHashSize returns the size in bytes of the value of field PostIBBHash -func (s *SE) PostIBBHashTotalSize() uint64 { - return s.PostIBBHash.TotalSize() -} - -// IBBEntryPointSize returns the size in bytes of the value of field IBBEntryPoint -func (s *SE) IBBEntryPointTotalSize() uint64 { - return 4 -} - -// DigestListSize returns the size in bytes of the value of field DigestList -func (s *SE) DigestListTotalSize() uint64 { - return s.DigestList.TotalSize() -} - -// OBBHashSize returns the size in bytes of the value of field OBBHash -func (s *SE) OBBHashTotalSize() uint64 { - return s.OBBHash.TotalSize() -} - -// Reserved2Size returns the size in bytes of the value of field Reserved2 -func (s *SE) Reserved2TotalSize() uint64 { - return 3 -} - -// IBBSegmentsSize returns the size in bytes of the value of field IBBSegments -func (s *SE) IBBSegmentsTotalSize() uint64 { - var size uint64 - size += uint64(binary.Size(uint8(0))) - for idx := range s.IBBSegments { - size += s.IBBSegments[idx].TotalSize() - } - return size -} - -// StructInfoOffset returns the offset in bytes of field StructInfo -func (s *SE) StructInfoOffset() uint64 { - return 0 -} - -// Reserved0Offset returns the offset in bytes of field Reserved0 -func (s *SE) Reserved0Offset() uint64 { - return s.StructInfoOffset() + s.StructInfoTotalSize() -} - -// SetNumberOffset returns the offset in bytes of field SetNumber -func (s *SE) SetNumberOffset() uint64 { - return s.Reserved0Offset() + s.Reserved0TotalSize() -} - -// Reserved1Offset returns the offset in bytes of field Reserved1 -func (s *SE) Reserved1Offset() uint64 { - return s.SetNumberOffset() + s.SetNumberTotalSize() -} - -// PBETValueOffset returns the offset in bytes of field PBETValue -func (s *SE) PBETValueOffset() uint64 { - return s.Reserved1Offset() + s.Reserved1TotalSize() -} - -// FlagsOffset returns the offset in bytes of field Flags -func (s *SE) FlagsOffset() uint64 { - return s.PBETValueOffset() + s.PBETValueTotalSize() -} - -// IBBMCHBAROffset returns the offset in bytes of field IBBMCHBAR -func (s *SE) IBBMCHBAROffset() uint64 { - return s.FlagsOffset() + s.FlagsTotalSize() -} - -// VTdBAROffset returns the offset in bytes of field VTdBAR -func (s *SE) VTdBAROffset() uint64 { - return s.IBBMCHBAROffset() + s.IBBMCHBARTotalSize() -} - -// DMAProtBase0Offset returns the offset in bytes of field DMAProtBase0 -func (s *SE) DMAProtBase0Offset() uint64 { - return s.VTdBAROffset() + s.VTdBARTotalSize() -} - -// DMAProtLimit0Offset returns the offset in bytes of field DMAProtLimit0 -func (s *SE) DMAProtLimit0Offset() uint64 { - return s.DMAProtBase0Offset() + s.DMAProtBase0TotalSize() -} - -// DMAProtBase1Offset returns the offset in bytes of field DMAProtBase1 -func (s *SE) DMAProtBase1Offset() uint64 { - return s.DMAProtLimit0Offset() + s.DMAProtLimit0TotalSize() -} - -// DMAProtLimit1Offset returns the offset in bytes of field DMAProtLimit1 -func (s *SE) DMAProtLimit1Offset() uint64 { - return s.DMAProtBase1Offset() + s.DMAProtBase1TotalSize() -} - -// PostIBBHashOffset returns the offset in bytes of field PostIBBHash -func (s *SE) PostIBBHashOffset() uint64 { - return s.DMAProtLimit1Offset() + s.DMAProtLimit1TotalSize() -} - -// IBBEntryPointOffset returns the offset in bytes of field IBBEntryPoint -func (s *SE) IBBEntryPointOffset() uint64 { - return s.PostIBBHashOffset() + s.PostIBBHashTotalSize() -} - -// DigestListOffset returns the offset in bytes of field DigestList -func (s *SE) DigestListOffset() uint64 { - return s.IBBEntryPointOffset() + s.IBBEntryPointTotalSize() -} - -// OBBHashOffset returns the offset in bytes of field OBBHash -func (s *SE) OBBHashOffset() uint64 { - return s.DigestListOffset() + s.DigestListTotalSize() -} - -// Reserved2Offset returns the offset in bytes of field Reserved2 -func (s *SE) Reserved2Offset() uint64 { - return s.OBBHashOffset() + s.OBBHashTotalSize() -} - -// IBBSegmentsOffset returns the offset in bytes of field IBBSegments -func (s *SE) IBBSegmentsOffset() uint64 { - return s.Reserved2Offset() + s.Reserved2TotalSize() -} - -// Size returns the total size of the SE. -func (s *SE) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.StructInfoTotalSize() - size += s.Reserved0TotalSize() - size += s.SetNumberTotalSize() - size += s.Reserved1TotalSize() - size += s.PBETValueTotalSize() - size += s.FlagsTotalSize() - size += s.IBBMCHBARTotalSize() - size += s.VTdBARTotalSize() - size += s.DMAProtBase0TotalSize() - size += s.DMAProtLimit0TotalSize() - size += s.DMAProtBase1TotalSize() - size += s.DMAProtLimit1TotalSize() - size += s.PostIBBHashTotalSize() - size += s.IBBEntryPointTotalSize() - size += s.DigestListTotalSize() - size += s.OBBHashTotalSize() - size += s.Reserved2TotalSize() - size += s.IBBSegmentsTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *SE) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "IBB Segments Element", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is structInfo - lines = append(lines, pretty.SubValue(depth+1, "Struct Info", "", &s.StructInfo, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved 0", "", &s.Reserved0, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Set Number", "", &s.SetNumber, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved 1", "", &s.Reserved1, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "PBET Value", "", &s.PBETValue, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Flags", "", &s.Flags, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "IBB MCHBAR", "", &s.IBBMCHBAR, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "VT-d BAR", "", &s.VTdBAR, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "DMA Protection 0 Base Address", "", &s.DMAProtBase0, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "DMA Protection 0 Limit Address", "", &s.DMAProtLimit0, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "DMA Protection 1 Base Address", "", &s.DMAProtBase1, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "DMA Protection 2 Limit Address", "", &s.DMAProtLimit1, opts...)...) - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "Post IBB Hash", "", &s.PostIBBHash, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "IBB Entry Point", "", &s.IBBEntryPoint, opts...)...) - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "Digest List", "", &s.DigestList, opts...)...) - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "OBB Hash", "", &s.OBBHash, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved 2", "", &s.Reserved2, opts...)...) - // ManifestFieldType is list - lines = append(lines, pretty.Header(depth+1, fmt.Sprintf("IBBSegments: Array of \"IBB Segments Element\" of length %d", len(s.IBBSegments)), s.IBBSegments)) - for i := 0; i < len(s.IBBSegments); i++ { - lines = append(lines, fmt.Sprintf("%sitem #%d: ", strings.Repeat(" ", int(depth+2)), i)+strings.TrimSpace(s.IBBSegments[i].PrettyString(depth+2, true))) - } - if depth < 1 { - lines = append(lines, "") - } - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v CachingType) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - return v.String() -} - -// TotalSize returns the total size measured through binary.Size. -func (v CachingType) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the CachingType into 'w' in binary format. -func (v CachingType) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the CachingType from 'r' in binary format. -func (v CachingType) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v PBETValue) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "PBET Value", v)) - } - lines = append(lines, pretty.SubValue(depth+1, "PBET Value", "", v.PBETValue(), opts...)...) - return strings.Join(lines, "\n") -} - -// TotalSize returns the total size measured through binary.Size. -func (v PBETValue) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the PBETValue into 'w' in binary format. -func (v PBETValue) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the PBETValue from 'r' in binary format. -func (v PBETValue) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v SEFlags) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "SE Flags", v)) - } - lines = append(lines, pretty.SubValue(depth+1, "Reserved 0", "", v.Reserved0(), opts...)...) - if v.SupportsTopSwapRemediation() { - lines = append(lines, pretty.SubValue(depth+1, "Supports Top Swap Remediation", "BIOS supports Top Swap remediation action", true, opts...)...) - } else { - lines = append(lines, pretty.SubValue(depth+1, "Supports Top Swap Remediation", "BIOS does not support Top Swap remediation action", false, opts...)...) - } - if v.TPMFailureLeavesHierarchiesEnabled() { - lines = append(lines, pretty.SubValue(depth+1, "TPM Failure Leaves Hierarchies Enabled", "Leave Hierarchies enabled. Cap all PCRs on failure.", true, opts...)...) - } else { - lines = append(lines, pretty.SubValue(depth+1, "TPM Failure Leaves Hierarchies Enabled", "Do not leave enabled. Disable all Hierarchies or deactivate on failure.", false, opts...)...) - } - if v.AuthorityMeasure() { - lines = append(lines, pretty.SubValue(depth+1, "Authority Measure", "Extend Authority Measurements into the Authority PCR 7", true, opts...)...) - } else { - lines = append(lines, pretty.SubValue(depth+1, "Authority Measure", "Do not extend into the Authority PCR 7", false, opts...)...) - } - if v.Locality3Startup() { - lines = append(lines, pretty.SubValue(depth+1, "Locality 3 Startup", "Issue TPM Start-up from Locality 3", true, opts...)...) - } else { - lines = append(lines, pretty.SubValue(depth+1, "Locality 3 Startup", "Disabled", false, opts...)...) - } - if v.DMAProtection() { - lines = append(lines, pretty.SubValue(depth+1, "DMA Protection", "Enable DMA Protection", true, opts...)...) - } else { - lines = append(lines, pretty.SubValue(depth+1, "DMA Protection", "Disable DMA Protection", false, opts...)...) - } - return strings.Join(lines, "\n") -} - -// TotalSize returns the total size measured through binary.Size. -func (v SEFlags) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the SEFlags into 'w' in binary format. -func (v SEFlags) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the SEFlags from 'r' in binary format. -func (v SEFlags) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/signature_manifestcodegen.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/signature_manifestcodegen.go deleted file mode 100644 index a043fd83..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/signature_manifestcodegen.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy - -package cbntbootpolicy - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = cbnt.StructInfo{} -) - -// NewSignature returns a new instance of Signature with -// all default values set. -func NewSignature() *Signature { - s := &Signature{} - copy(s.StructInfo.ID[:], []byte(StructureIDSignature)) - s.StructInfo.Version = 0x20 - // Recursively initializing a child structure: - s.KeySignature = *cbnt.NewKeySignature() - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *Signature) Validate() error { - // Recursively validating a child structure: - if err := s.KeySignature.Validate(); err != nil { - return fmt.Errorf("error on field 'KeySignature': %w", err) - } - - return nil -} - -// StructureIDSignature is the StructureID (in terms of -// the document #575623) of element 'Signature'. -const StructureIDSignature = "__PMSG__" - -// GetStructInfo returns current value of StructInfo of the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *Signature) GetStructInfo() cbnt.StructInfo { - return s.StructInfo -} - -// SetStructInfo sets new value of StructInfo to the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *Signature) SetStructInfo(newStructInfo cbnt.StructInfo) { - s.StructInfo = newStructInfo -} - -// ReadFrom reads the Signature from 'r' in format defined in the document #575623. -func (s *Signature) ReadFrom(r io.Reader) (int64, error) { - var totalN int64 - - err := binary.Read(r, binary.LittleEndian, &s.StructInfo) - if err != nil { - return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) - } - totalN += int64(binary.Size(s.StructInfo)) - - n, err := s.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read data: %w", err) - } - totalN += n - - return totalN, nil -} - -// ReadDataFrom reads the Signature from 'r' excluding StructInfo, -// in format defined in the document #575623. -func (s *Signature) ReadDataFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // StructInfo (ManifestFieldType: structInfo) - { - // ReadDataFrom does not read Struct, use ReadFrom for that. - } - - // KeySignature (ManifestFieldType: subStruct) - { - n, err := s.KeySignature.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'KeySignature': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *Signature) RehashRecursive() { - s.StructInfo.Rehash() - s.KeySignature.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *Signature) Rehash() { - s.Variable0 = 0 - s.ElementSize = 0 -} - -// WriteTo writes the Signature into 'w' in format defined in -// the document #575623. -func (s *Signature) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // StructInfo (ManifestFieldType: structInfo) - { - n, err := s.StructInfo.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'StructInfo': %w", err) - } - totalN += int64(n) - } - - // KeySignature (ManifestFieldType: subStruct) - { - n, err := s.KeySignature.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'KeySignature': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// StructInfoSize returns the size in bytes of the value of field StructInfo -func (s *Signature) StructInfoTotalSize() uint64 { - return s.StructInfo.TotalSize() -} - -// KeySignatureSize returns the size in bytes of the value of field KeySignature -func (s *Signature) KeySignatureTotalSize() uint64 { - return s.KeySignature.TotalSize() -} - -// StructInfoOffset returns the offset in bytes of field StructInfo -func (s *Signature) StructInfoOffset() uint64 { - return 0 -} - -// KeySignatureOffset returns the offset in bytes of field KeySignature -func (s *Signature) KeySignatureOffset() uint64 { - return s.StructInfoOffset() + s.StructInfoTotalSize() -} - -// Size returns the total size of the Signature. -func (s *Signature) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.StructInfoTotalSize() - size += s.KeySignatureTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *Signature) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Signature", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is structInfo - lines = append(lines, pretty.SubValue(depth+1, "Struct Info", "", &s.StructInfo, opts...)...) - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "Key Signature", "", &s.KeySignature, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/txt_control_flags_manifestcodegen.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/txt_control_flags_manifestcodegen.go deleted file mode 100644 index 89b2361b..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/txt_control_flags_manifestcodegen.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy - -package cbntbootpolicy - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = cbnt.StructInfo{} -) - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v BackupActionPolicy) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - return v.String() -} - -// TotalSize returns the total size measured through binary.Size. -func (v BackupActionPolicy) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the BackupActionPolicy into 'w' in binary format. -func (v BackupActionPolicy) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the BackupActionPolicy from 'r' in binary format. -func (v BackupActionPolicy) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v ExecutionProfile) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - return v.String() -} - -// TotalSize returns the total size measured through binary.Size. -func (v ExecutionProfile) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the ExecutionProfile into 'w' in binary format. -func (v ExecutionProfile) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the ExecutionProfile from 'r' in binary format. -func (v ExecutionProfile) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v MemoryScrubbingPolicy) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - return v.String() -} - -// TotalSize returns the total size measured through binary.Size. -func (v MemoryScrubbingPolicy) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the MemoryScrubbingPolicy into 'w' in binary format. -func (v MemoryScrubbingPolicy) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the MemoryScrubbingPolicy from 'r' in binary format. -func (v MemoryScrubbingPolicy) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v ResetAUXControl) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - return v.String() -} - -// TotalSize returns the total size measured through binary.Size. -func (v ResetAUXControl) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the ResetAUXControl into 'w' in binary format. -func (v ResetAUXControl) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the ResetAUXControl from 'r' in binary format. -func (v ResetAUXControl) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v TXTControlFlags) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "TXT Control Flags", v)) - } - lines = append(lines, pretty.SubValue(depth+1, "Execution Profile", "", v.ExecutionProfile(), opts...)...) - lines = append(lines, pretty.SubValue(depth+1, "Memory Scrubbing Policy", "", v.MemoryScrubbingPolicy(), opts...)...) - lines = append(lines, pretty.SubValue(depth+1, "Backup Action Policy", "", v.BackupActionPolicy(), opts...)...) - if v.IsSACMRequestedToExtendStaticPCRs() { - lines = append(lines, pretty.SubValue(depth+1, "Is SACM Requested To Extend Static PC Rs", "Default setting. S-ACM is requested to extend static PCRs", true, opts...)...) - } else { - lines = append(lines, pretty.SubValue(depth+1, "Is SACM Requested To Extend Static PC Rs", "S-ACM is not requested to extend static PCRs", false, opts...)...) - } - lines = append(lines, pretty.SubValue(depth+1, "Reset AUX Control", "", v.ResetAUXControl(), opts...)...) - return strings.Join(lines, "\n") -} - -// TotalSize returns the total size measured through binary.Size. -func (v TXTControlFlags) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the TXTControlFlags into 'w' in binary format. -func (v TXTControlFlags) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the TXTControlFlags from 'r' in binary format. -func (v TXTControlFlags) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/txt_manifestcodegen.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/txt_manifestcodegen.go deleted file mode 100644 index 29a08e5e..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/txt_manifestcodegen.go +++ /dev/null @@ -1,670 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy - -package cbntbootpolicy - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = cbnt.StructInfo{} -) - -// NewTXT returns a new instance of TXT with -// all default values set. -func NewTXT() *TXT { - s := &TXT{} - copy(s.StructInfo.ID[:], []byte(StructureIDTXT)) - s.StructInfo.Version = 0x21 - // Set through tag "default": - s.SInitMinSVNAuth = 0 - // Set through tag "default": - s.PTTCMOSOffset0 = 126 - // Set through tag "default": - s.PTTCMOSOffset1 = 127 - // Set through tag "default": - s.ACPIBaseOffset = 0x400 - // Set through tag "default": - s.PwrMBaseOffset = 0xFE000000 - // Recursively initializing a child structure: - s.DigestList = *cbnt.NewHashList() - // Set through tag "required": - s.SegmentCount = 0 - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *TXT) Validate() error { - // See tag "require" - for idx := range s.Reserved0 { - if s.Reserved0[idx] != 0 { - return fmt.Errorf("'Reserved0[%d]' is expected to be 0, but it is %v", idx, s.Reserved0[idx]) - } - } - // See tag "require" - for idx := range s.SetNumber { - if s.SetNumber[idx] != 0 { - return fmt.Errorf("'SetNumber[%d]' is expected to be 0, but it is %v", idx, s.SetNumber[idx]) - } - } - // See tag "require" - for idx := range s.Reserved1 { - if s.Reserved1[idx] != 0 { - return fmt.Errorf("'Reserved1[%d]' is expected to be 0, but it is %v", idx, s.Reserved1[idx]) - } - } - // Recursively validating a child structure: - if err := s.DigestList.Validate(); err != nil { - return fmt.Errorf("error on field 'DigestList': %w", err) - } - // See tag "require" - for idx := range s.Reserved3 { - if s.Reserved3[idx] != 0 { - return fmt.Errorf("'Reserved3[%d]' is expected to be 0, but it is %v", idx, s.Reserved3[idx]) - } - } - // See tag "require" - if s.SegmentCount != 0 { - return fmt.Errorf("field 'SegmentCount' expects value '0', but has %v", s.SegmentCount) - } - - return nil -} - -// StructureIDTXT is the StructureID (in terms of -// the document #575623) of element 'TXT'. -const StructureIDTXT = "__TXTS__" - -// GetStructInfo returns current value of StructInfo of the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *TXT) GetStructInfo() cbnt.StructInfo { - return s.StructInfo -} - -// SetStructInfo sets new value of StructInfo to the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *TXT) SetStructInfo(newStructInfo cbnt.StructInfo) { - s.StructInfo = newStructInfo -} - -// ReadFrom reads the TXT from 'r' in format defined in the document #575623. -func (s *TXT) ReadFrom(r io.Reader) (int64, error) { - var totalN int64 - - err := binary.Read(r, binary.LittleEndian, &s.StructInfo) - if err != nil { - return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) - } - totalN += int64(binary.Size(s.StructInfo)) - - n, err := s.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read data: %w", err) - } - totalN += n - - return totalN, nil -} - -// ReadDataFrom reads the TXT from 'r' excluding StructInfo, -// in format defined in the document #575623. -func (s *TXT) ReadDataFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // StructInfo (ManifestFieldType: structInfo) - { - // ReadDataFrom does not read Struct, use ReadFrom for that. - } - - // Reserved0 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Read(r, binary.LittleEndian, s.Reserved0[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved0': %w", err) - } - totalN += int64(n) - } - - // SetNumber (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Read(r, binary.LittleEndian, s.SetNumber[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'SetNumber': %w", err) - } - totalN += int64(n) - } - - // SInitMinSVNAuth (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.SInitMinSVNAuth) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'SInitMinSVNAuth': %w", err) - } - totalN += int64(n) - } - - // Reserved1 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Read(r, binary.LittleEndian, s.Reserved1[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved1': %w", err) - } - totalN += int64(n) - } - - // ControlFlags (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.ControlFlags) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'ControlFlags': %w", err) - } - totalN += int64(n) - } - - // PwrDownInterval (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.PwrDownInterval) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'PwrDownInterval': %w", err) - } - totalN += int64(n) - } - - // PTTCMOSOffset0 (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.PTTCMOSOffset0) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'PTTCMOSOffset0': %w", err) - } - totalN += int64(n) - } - - // PTTCMOSOffset1 (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.PTTCMOSOffset1) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'PTTCMOSOffset1': %w", err) - } - totalN += int64(n) - } - - // ACPIBaseOffset (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.ACPIBaseOffset) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'ACPIBaseOffset': %w", err) - } - totalN += int64(n) - } - - // Reserved2 (ManifestFieldType: arrayStatic) - { - n, err := 2, binary.Read(r, binary.LittleEndian, s.Reserved2[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved2': %w", err) - } - totalN += int64(n) - } - - // PwrMBaseOffset (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.PwrMBaseOffset) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'PwrMBaseOffset': %w", err) - } - totalN += int64(n) - } - - // DigestList (ManifestFieldType: subStruct) - { - n, err := s.DigestList.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'DigestList': %w", err) - } - totalN += int64(n) - } - - // Reserved3 (ManifestFieldType: arrayStatic) - { - n, err := 3, binary.Read(r, binary.LittleEndian, s.Reserved3[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved3': %w", err) - } - totalN += int64(n) - } - - // SegmentCount (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.SegmentCount) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'SegmentCount': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *TXT) RehashRecursive() { - s.StructInfo.Rehash() - s.DigestList.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *TXT) Rehash() { - s.Variable0 = 0 - s.ElementSize = uint16(s.TotalSize()) -} - -// WriteTo writes the TXT into 'w' in format defined in -// the document #575623. -func (s *TXT) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // StructInfo (ManifestFieldType: structInfo) - { - n, err := s.StructInfo.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'StructInfo': %w", err) - } - totalN += int64(n) - } - - // Reserved0 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Write(w, binary.LittleEndian, s.Reserved0[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved0': %w", err) - } - totalN += int64(n) - } - - // SetNumber (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Write(w, binary.LittleEndian, s.SetNumber[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'SetNumber': %w", err) - } - totalN += int64(n) - } - - // SInitMinSVNAuth (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.SInitMinSVNAuth) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'SInitMinSVNAuth': %w", err) - } - totalN += int64(n) - } - - // Reserved1 (ManifestFieldType: arrayStatic) - { - n, err := 1, binary.Write(w, binary.LittleEndian, s.Reserved1[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved1': %w", err) - } - totalN += int64(n) - } - - // ControlFlags (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.ControlFlags) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'ControlFlags': %w", err) - } - totalN += int64(n) - } - - // PwrDownInterval (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.PwrDownInterval) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PwrDownInterval': %w", err) - } - totalN += int64(n) - } - - // PTTCMOSOffset0 (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.PTTCMOSOffset0) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PTTCMOSOffset0': %w", err) - } - totalN += int64(n) - } - - // PTTCMOSOffset1 (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.PTTCMOSOffset1) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PTTCMOSOffset1': %w", err) - } - totalN += int64(n) - } - - // ACPIBaseOffset (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.ACPIBaseOffset) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'ACPIBaseOffset': %w", err) - } - totalN += int64(n) - } - - // Reserved2 (ManifestFieldType: arrayStatic) - { - n, err := 2, binary.Write(w, binary.LittleEndian, s.Reserved2[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved2': %w", err) - } - totalN += int64(n) - } - - // PwrMBaseOffset (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.PwrMBaseOffset) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PwrMBaseOffset': %w", err) - } - totalN += int64(n) - } - - // DigestList (ManifestFieldType: subStruct) - { - n, err := s.DigestList.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'DigestList': %w", err) - } - totalN += int64(n) - } - - // Reserved3 (ManifestFieldType: arrayStatic) - { - n, err := 3, binary.Write(w, binary.LittleEndian, s.Reserved3[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved3': %w", err) - } - totalN += int64(n) - } - - // SegmentCount (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.SegmentCount) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'SegmentCount': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// StructInfoSize returns the size in bytes of the value of field StructInfo -func (s *TXT) StructInfoTotalSize() uint64 { - return s.StructInfo.TotalSize() -} - -// Reserved0Size returns the size in bytes of the value of field Reserved0 -func (s *TXT) Reserved0TotalSize() uint64 { - return 1 -} - -// SetNumberSize returns the size in bytes of the value of field SetNumber -func (s *TXT) SetNumberTotalSize() uint64 { - return 1 -} - -// SInitMinSVNAuthSize returns the size in bytes of the value of field SInitMinSVNAuth -func (s *TXT) SInitMinSVNAuthTotalSize() uint64 { - return 1 -} - -// Reserved1Size returns the size in bytes of the value of field Reserved1 -func (s *TXT) Reserved1TotalSize() uint64 { - return 1 -} - -// ControlFlagsSize returns the size in bytes of the value of field ControlFlags -func (s *TXT) ControlFlagsTotalSize() uint64 { - return 4 -} - -// PwrDownIntervalSize returns the size in bytes of the value of field PwrDownInterval -func (s *TXT) PwrDownIntervalTotalSize() uint64 { - return 2 -} - -// PTTCMOSOffset0Size returns the size in bytes of the value of field PTTCMOSOffset0 -func (s *TXT) PTTCMOSOffset0TotalSize() uint64 { - return 1 -} - -// PTTCMOSOffset1Size returns the size in bytes of the value of field PTTCMOSOffset1 -func (s *TXT) PTTCMOSOffset1TotalSize() uint64 { - return 1 -} - -// ACPIBaseOffsetSize returns the size in bytes of the value of field ACPIBaseOffset -func (s *TXT) ACPIBaseOffsetTotalSize() uint64 { - return 2 -} - -// Reserved2Size returns the size in bytes of the value of field Reserved2 -func (s *TXT) Reserved2TotalSize() uint64 { - return 2 -} - -// PwrMBaseOffsetSize returns the size in bytes of the value of field PwrMBaseOffset -func (s *TXT) PwrMBaseOffsetTotalSize() uint64 { - return 4 -} - -// DigestListSize returns the size in bytes of the value of field DigestList -func (s *TXT) DigestListTotalSize() uint64 { - return s.DigestList.TotalSize() -} - -// Reserved3Size returns the size in bytes of the value of field Reserved3 -func (s *TXT) Reserved3TotalSize() uint64 { - return 3 -} - -// SegmentCountSize returns the size in bytes of the value of field SegmentCount -func (s *TXT) SegmentCountTotalSize() uint64 { - return 1 -} - -// StructInfoOffset returns the offset in bytes of field StructInfo -func (s *TXT) StructInfoOffset() uint64 { - return 0 -} - -// Reserved0Offset returns the offset in bytes of field Reserved0 -func (s *TXT) Reserved0Offset() uint64 { - return s.StructInfoOffset() + s.StructInfoTotalSize() -} - -// SetNumberOffset returns the offset in bytes of field SetNumber -func (s *TXT) SetNumberOffset() uint64 { - return s.Reserved0Offset() + s.Reserved0TotalSize() -} - -// SInitMinSVNAuthOffset returns the offset in bytes of field SInitMinSVNAuth -func (s *TXT) SInitMinSVNAuthOffset() uint64 { - return s.SetNumberOffset() + s.SetNumberTotalSize() -} - -// Reserved1Offset returns the offset in bytes of field Reserved1 -func (s *TXT) Reserved1Offset() uint64 { - return s.SInitMinSVNAuthOffset() + s.SInitMinSVNAuthTotalSize() -} - -// ControlFlagsOffset returns the offset in bytes of field ControlFlags -func (s *TXT) ControlFlagsOffset() uint64 { - return s.Reserved1Offset() + s.Reserved1TotalSize() -} - -// PwrDownIntervalOffset returns the offset in bytes of field PwrDownInterval -func (s *TXT) PwrDownIntervalOffset() uint64 { - return s.ControlFlagsOffset() + s.ControlFlagsTotalSize() -} - -// PTTCMOSOffset0Offset returns the offset in bytes of field PTTCMOSOffset0 -func (s *TXT) PTTCMOSOffset0Offset() uint64 { - return s.PwrDownIntervalOffset() + s.PwrDownIntervalTotalSize() -} - -// PTTCMOSOffset1Offset returns the offset in bytes of field PTTCMOSOffset1 -func (s *TXT) PTTCMOSOffset1Offset() uint64 { - return s.PTTCMOSOffset0Offset() + s.PTTCMOSOffset0TotalSize() -} - -// ACPIBaseOffsetOffset returns the offset in bytes of field ACPIBaseOffset -func (s *TXT) ACPIBaseOffsetOffset() uint64 { - return s.PTTCMOSOffset1Offset() + s.PTTCMOSOffset1TotalSize() -} - -// Reserved2Offset returns the offset in bytes of field Reserved2 -func (s *TXT) Reserved2Offset() uint64 { - return s.ACPIBaseOffsetOffset() + s.ACPIBaseOffsetTotalSize() -} - -// PwrMBaseOffsetOffset returns the offset in bytes of field PwrMBaseOffset -func (s *TXT) PwrMBaseOffsetOffset() uint64 { - return s.Reserved2Offset() + s.Reserved2TotalSize() -} - -// DigestListOffset returns the offset in bytes of field DigestList -func (s *TXT) DigestListOffset() uint64 { - return s.PwrMBaseOffsetOffset() + s.PwrMBaseOffsetTotalSize() -} - -// Reserved3Offset returns the offset in bytes of field Reserved3 -func (s *TXT) Reserved3Offset() uint64 { - return s.DigestListOffset() + s.DigestListTotalSize() -} - -// SegmentCountOffset returns the offset in bytes of field SegmentCount -func (s *TXT) SegmentCountOffset() uint64 { - return s.Reserved3Offset() + s.Reserved3TotalSize() -} - -// Size returns the total size of the TXT. -func (s *TXT) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.StructInfoTotalSize() - size += s.Reserved0TotalSize() - size += s.SetNumberTotalSize() - size += s.SInitMinSVNAuthTotalSize() - size += s.Reserved1TotalSize() - size += s.ControlFlagsTotalSize() - size += s.PwrDownIntervalTotalSize() - size += s.PTTCMOSOffset0TotalSize() - size += s.PTTCMOSOffset1TotalSize() - size += s.ACPIBaseOffsetTotalSize() - size += s.Reserved2TotalSize() - size += s.PwrMBaseOffsetTotalSize() - size += s.DigestListTotalSize() - size += s.Reserved3TotalSize() - size += s.SegmentCountTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *TXT) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "TXT", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is structInfo - lines = append(lines, pretty.SubValue(depth+1, "Struct Info", "", &s.StructInfo, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved 0", "", &s.Reserved0, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Set Number", "", &s.SetNumber, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "S Init Min SVN Auth", "", &s.SInitMinSVNAuth, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved 1", "", &s.Reserved1, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Control Flags", "", &s.ControlFlags, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Pwr Down Interval", "", &s.PwrDownInterval, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "PTT CMOS Offset 0", "", &s.PTTCMOSOffset0, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "PTT CMOS Offset 1", "", &s.PTTCMOSOffset1, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "ACPI Base Offset", "", &s.ACPIBaseOffset, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved 2", "", &s.Reserved2, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "ACPI MMIO Offset", "", &s.PwrMBaseOffset, opts...)...) - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "Digest List", "", &s.DigestList, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved 3", "", &s.Reserved3, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Segment Count", "", &s.SegmentCount, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v Duration16In5Sec) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - return v.String() -} - -// TotalSize returns the total size measured through binary.Size. -func (v Duration16In5Sec) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the Duration16In5Sec into 'w' in binary format. -func (v Duration16In5Sec) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the Duration16In5Sec from 'r' in binary format. -func (v Duration16In5Sec) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} diff --git a/pkg/intel/metadata/cbnt/cbntkey/hash_manifestcodegen.go b/pkg/intel/metadata/cbnt/cbntkey/hash_manifestcodegen.go deleted file mode 100644 index f7a2c50a..00000000 --- a/pkg/intel/metadata/cbnt/cbntkey/hash_manifestcodegen.go +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntkey - -package cbntkey - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = cbnt.StructInfo{} -) - -// NewHash returns a new instance of Hash with -// all default values set. -func NewHash() *Hash { - s := &Hash{} - // Recursively initializing a child structure: - s.Digest = *cbnt.NewHashStructure() - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *Hash) Validate() error { - // Recursively validating a child structure: - if err := s.Digest.Validate(); err != nil { - return fmt.Errorf("error on field 'Digest': %w", err) - } - - return nil -} - -// ReadFrom reads the Hash from 'r' in format defined in the document #575623. -func (s *Hash) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // Usage (ManifestFieldType: endValue) - { - n, err := 8, binary.Read(r, binary.LittleEndian, &s.Usage) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Usage': %w", err) - } - totalN += int64(n) - } - - // Digest (ManifestFieldType: subStruct) - { - n, err := s.Digest.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Digest': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *Hash) RehashRecursive() { - s.Digest.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *Hash) Rehash() { -} - -// WriteTo writes the Hash into 'w' in format defined in -// the document #575623. -func (s *Hash) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // Usage (ManifestFieldType: endValue) - { - n, err := 8, binary.Write(w, binary.LittleEndian, &s.Usage) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Usage': %w", err) - } - totalN += int64(n) - } - - // Digest (ManifestFieldType: subStruct) - { - n, err := s.Digest.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Digest': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// UsageSize returns the size in bytes of the value of field Usage -func (s *Hash) UsageTotalSize() uint64 { - return 8 -} - -// DigestSize returns the size in bytes of the value of field Digest -func (s *Hash) DigestTotalSize() uint64 { - return s.Digest.TotalSize() -} - -// UsageOffset returns the offset in bytes of field Usage -func (s *Hash) UsageOffset() uint64 { - return 0 -} - -// DigestOffset returns the offset in bytes of field Digest -func (s *Hash) DigestOffset() uint64 { - return s.UsageOffset() + s.UsageTotalSize() -} - -// Size returns the total size of the Hash. -func (s *Hash) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.UsageTotalSize() - size += s.DigestTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *Hash) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Hash", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Usage", "", &s.Usage, opts...)...) - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "Digest", "", &s.Digest, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v Usage) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - return v.String() -} - -// TotalSize returns the total size measured through binary.Size. -func (v Usage) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the Usage into 'w' in binary format. -func (v Usage) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the Usage from 'r' in binary format. -func (v Usage) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} diff --git a/pkg/intel/metadata/cbnt/cbntkey/manifest_manifestcodegen.go b/pkg/intel/metadata/cbnt/cbntkey/manifest_manifestcodegen.go deleted file mode 100644 index 9dc88db9..00000000 --- a/pkg/intel/metadata/cbnt/cbntkey/manifest_manifestcodegen.go +++ /dev/null @@ -1,461 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntkey - -package cbntkey - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join - _ = cbnt.StructInfo{} -) - -// NewManifest returns a new instance of Manifest with -// all default values set. -func NewManifest() *Manifest { - s := &Manifest{} - copy(s.StructInfo.ID[:], []byte(StructureIDManifest)) - s.StructInfo.Version = 0x21 - // Recursively initializing a child structure: - s.KeyAndSignature = *cbnt.NewKeySignature() - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *Manifest) Validate() error { - // See tag "rehashValue" - { - expectedValue := uint16(s.KeyAndSignatureOffset()) - if s.KeyManifestSignatureOffset != expectedValue { - return fmt.Errorf("field 'KeyManifestSignatureOffset' expects write-value '%v', but has %v", expectedValue, s.KeyManifestSignatureOffset) - } - } - // Recursively validating a child structure: - if err := s.KeyAndSignature.Validate(); err != nil { - return fmt.Errorf("error on field 'KeyAndSignature': %w", err) - } - - return nil -} - -// StructureIDManifest is the StructureID (in terms of -// the document #575623) of element 'Manifest'. -const StructureIDManifest = "__KEYM__" - -// GetStructInfo returns current value of StructInfo of the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *Manifest) GetStructInfo() cbnt.StructInfo { - return s.StructInfo -} - -// SetStructInfo sets new value of StructInfo to the structure. -// -// StructInfo is a set of standard fields with presented in any element -// ("element" in terms of document #575623). -func (s *Manifest) SetStructInfo(newStructInfo cbnt.StructInfo) { - s.StructInfo = newStructInfo -} - -// ReadFrom reads the Manifest from 'r' in format defined in the document #575623. -func (s *Manifest) ReadFrom(r io.Reader) (int64, error) { - var totalN int64 - - err := binary.Read(r, binary.LittleEndian, &s.StructInfo) - if err != nil { - return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) - } - totalN += int64(binary.Size(s.StructInfo)) - - n, err := s.ReadDataFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read data: %w", err) - } - totalN += n - - return totalN, nil -} - -// ReadDataFrom reads the Manifest from 'r' excluding StructInfo, -// in format defined in the document #575623. -func (s *Manifest) ReadDataFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // StructInfo (ManifestFieldType: structInfo) - { - // ReadDataFrom does not read Struct, use ReadFrom for that. - } - - // KeyManifestSignatureOffset (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.KeyManifestSignatureOffset) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'KeyManifestSignatureOffset': %w", err) - } - totalN += int64(n) - } - - // Reserved2 (ManifestFieldType: arrayStatic) - { - n, err := 3, binary.Read(r, binary.LittleEndian, s.Reserved2[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Reserved2': %w", err) - } - totalN += int64(n) - } - - // Revision (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.Revision) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Revision': %w", err) - } - totalN += int64(n) - } - - // KMSVN (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.KMSVN) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'KMSVN': %w", err) - } - totalN += int64(n) - } - - // KMID (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.KMID) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'KMID': %w", err) - } - totalN += int64(n) - } - - // PubKeyHashAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.PubKeyHashAlg) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'PubKeyHashAlg': %w", err) - } - totalN += int64(n) - } - - // Hash (ManifestFieldType: list) - { - var count uint16 - err := binary.Read(r, binary.LittleEndian, &count) - if err != nil { - return totalN, fmt.Errorf("unable to read the count for field 'Hash': %w", err) - } - totalN += int64(binary.Size(count)) - s.Hash = make([]Hash, count) - - for idx := range s.Hash { - n, err := s.Hash[idx].ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Hash[%d]': %w", idx, err) - } - totalN += int64(n) - } - } - - // KeyAndSignature (ManifestFieldType: subStruct) - { - n, err := s.KeyAndSignature.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'KeyAndSignature': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *Manifest) RehashRecursive() { - s.StructInfo.Rehash() - s.KeyAndSignature.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *Manifest) Rehash() { - s.Variable0 = 0 - s.ElementSize = 0 - s.KeyManifestSignatureOffset = uint16(s.KeyAndSignatureOffset()) -} - -// WriteTo writes the Manifest into 'w' in format defined in -// the document #575623. -func (s *Manifest) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // StructInfo (ManifestFieldType: structInfo) - { - n, err := s.StructInfo.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'StructInfo': %w", err) - } - totalN += int64(n) - } - - // KeyManifestSignatureOffset (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.KeyManifestSignatureOffset) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'KeyManifestSignatureOffset': %w", err) - } - totalN += int64(n) - } - - // Reserved2 (ManifestFieldType: arrayStatic) - { - n, err := 3, binary.Write(w, binary.LittleEndian, s.Reserved2[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Reserved2': %w", err) - } - totalN += int64(n) - } - - // Revision (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.Revision) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Revision': %w", err) - } - totalN += int64(n) - } - - // KMSVN (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.KMSVN) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'KMSVN': %w", err) - } - totalN += int64(n) - } - - // KMID (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.KMID) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'KMID': %w", err) - } - totalN += int64(n) - } - - // PubKeyHashAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.PubKeyHashAlg) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'PubKeyHashAlg': %w", err) - } - totalN += int64(n) - } - - // Hash (ManifestFieldType: list) - { - count := uint16(len(s.Hash)) - err := binary.Write(w, binary.LittleEndian, &count) - if err != nil { - return totalN, fmt.Errorf("unable to write the count for field 'Hash': %w", err) - } - totalN += int64(binary.Size(count)) - for idx := range s.Hash { - n, err := s.Hash[idx].WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Hash[%d]': %w", idx, err) - } - totalN += int64(n) - } - } - - // KeyAndSignature (ManifestFieldType: subStruct) - { - n, err := s.KeyAndSignature.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'KeyAndSignature': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// StructInfoSize returns the size in bytes of the value of field StructInfo -func (s *Manifest) StructInfoTotalSize() uint64 { - return s.StructInfo.TotalSize() -} - -// KeyManifestSignatureOffsetSize returns the size in bytes of the value of field KeyManifestSignatureOffset -func (s *Manifest) KeyManifestSignatureOffsetTotalSize() uint64 { - return 2 -} - -// Reserved2Size returns the size in bytes of the value of field Reserved2 -func (s *Manifest) Reserved2TotalSize() uint64 { - return 3 -} - -// RevisionSize returns the size in bytes of the value of field Revision -func (s *Manifest) RevisionTotalSize() uint64 { - return 1 -} - -// KMSVNSize returns the size in bytes of the value of field KMSVN -func (s *Manifest) KMSVNTotalSize() uint64 { - return 1 -} - -// KMIDSize returns the size in bytes of the value of field KMID -func (s *Manifest) KMIDTotalSize() uint64 { - return 1 -} - -// PubKeyHashAlgSize returns the size in bytes of the value of field PubKeyHashAlg -func (s *Manifest) PubKeyHashAlgTotalSize() uint64 { - return 2 -} - -// HashSize returns the size in bytes of the value of field Hash -func (s *Manifest) HashTotalSize() uint64 { - var size uint64 - size += uint64(binary.Size(uint16(0))) - for idx := range s.Hash { - size += s.Hash[idx].TotalSize() - } - return size -} - -// KeyAndSignatureSize returns the size in bytes of the value of field KeyAndSignature -func (s *Manifest) KeyAndSignatureTotalSize() uint64 { - return s.KeyAndSignature.TotalSize() -} - -// StructInfoOffset returns the offset in bytes of field StructInfo -func (s *Manifest) StructInfoOffset() uint64 { - return 0 -} - -// KeyManifestSignatureOffsetOffset returns the offset in bytes of field KeyManifestSignatureOffset -func (s *Manifest) KeyManifestSignatureOffsetOffset() uint64 { - return s.StructInfoOffset() + s.StructInfoTotalSize() -} - -// Reserved2Offset returns the offset in bytes of field Reserved2 -func (s *Manifest) Reserved2Offset() uint64 { - return s.KeyManifestSignatureOffsetOffset() + s.KeyManifestSignatureOffsetTotalSize() -} - -// RevisionOffset returns the offset in bytes of field Revision -func (s *Manifest) RevisionOffset() uint64 { - return s.Reserved2Offset() + s.Reserved2TotalSize() -} - -// KMSVNOffset returns the offset in bytes of field KMSVN -func (s *Manifest) KMSVNOffset() uint64 { - return s.RevisionOffset() + s.RevisionTotalSize() -} - -// KMIDOffset returns the offset in bytes of field KMID -func (s *Manifest) KMIDOffset() uint64 { - return s.KMSVNOffset() + s.KMSVNTotalSize() -} - -// PubKeyHashAlgOffset returns the offset in bytes of field PubKeyHashAlg -func (s *Manifest) PubKeyHashAlgOffset() uint64 { - return s.KMIDOffset() + s.KMIDTotalSize() -} - -// HashOffset returns the offset in bytes of field Hash -func (s *Manifest) HashOffset() uint64 { - return s.PubKeyHashAlgOffset() + s.PubKeyHashAlgTotalSize() -} - -// KeyAndSignatureOffset returns the offset in bytes of field KeyAndSignature -func (s *Manifest) KeyAndSignatureOffset() uint64 { - return s.HashOffset() + s.HashTotalSize() -} - -// Size returns the total size of the Manifest. -func (s *Manifest) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.StructInfoTotalSize() - size += s.KeyManifestSignatureOffsetTotalSize() - size += s.Reserved2TotalSize() - size += s.RevisionTotalSize() - size += s.KMSVNTotalSize() - size += s.KMIDTotalSize() - size += s.PubKeyHashAlgTotalSize() - size += s.HashTotalSize() - size += s.KeyAndSignatureTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *Manifest) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "CBnT Key Manifest", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is structInfo - lines = append(lines, pretty.SubValue(depth+1, "Struct Info", "", &s.StructInfo, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Key Manifest Signature Offset", "", &s.KeyManifestSignatureOffset, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Reserved 2", "", &s.Reserved2, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Revision", "", &s.Revision, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "KMSVN", "", &s.KMSVN, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "KMID", "", &s.KMID, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Pub Key Hash Alg", "", &s.PubKeyHashAlg, opts...)...) - // ManifestFieldType is list - lines = append(lines, pretty.Header(depth+1, fmt.Sprintf("Hash: Array of \"Key Manifest\" of length %d", len(s.Hash)), s.Hash)) - for i := 0; i < len(s.Hash); i++ { - lines = append(lines, fmt.Sprintf("%sitem #%d: ", strings.Repeat(" ", int(depth+2)), i)+strings.TrimSpace(s.Hash[i].PrettyString(depth+2, true))) - } - if depth < 1 { - lines = append(lines, "") - } - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "Key And Signature", "", &s.KeyAndSignature, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/cbnt/chipset_ac_module_information_manifestcodegen.go b/pkg/intel/metadata/cbnt/chipset_ac_module_information_manifestcodegen.go deleted file mode 100644 index 6c3f1375..00000000 --- a/pkg/intel/metadata/cbnt/chipset_ac_module_information_manifestcodegen.go +++ /dev/null @@ -1,571 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt - -package cbnt - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// NewChipsetACModuleInformation returns a new instance of ChipsetACModuleInformation with -// all default values set. -func NewChipsetACModuleInformation() *ChipsetACModuleInformation { - s := &ChipsetACModuleInformation{} - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *ChipsetACModuleInformation) Validate() error { - - return nil -} - -// ReadFrom reads the ChipsetACModuleInformation from 'r' in format defined in the document #575623. -func (s *ChipsetACModuleInformation) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // UUID (ManifestFieldType: arrayStatic) - { - n, err := 16, binary.Read(r, binary.LittleEndian, s.UUID[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'UUID': %w", err) - } - totalN += int64(n) - } - - // ChipsetACMType (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.ChipsetACMType) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'ChipsetACMType': %w", err) - } - totalN += int64(n) - } - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Version': %w", err) - } - totalN += int64(n) - } - - // Length (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.Length) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Length': %w", err) - } - totalN += int64(n) - } - - // ChipsetIDList (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.ChipsetIDList) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'ChipsetIDList': %w", err) - } - totalN += int64(n) - } - - // OsSinitDataVer (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.OsSinitDataVer) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'OsSinitDataVer': %w", err) - } - totalN += int64(n) - } - - // MinMleHeaderVer (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.MinMleHeaderVer) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'MinMleHeaderVer': %w", err) - } - totalN += int64(n) - } - - // Capabilities (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.Capabilities) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Capabilities': %w", err) - } - totalN += int64(n) - } - - // AcmVersion (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.AcmVersion) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'AcmVersion': %w", err) - } - totalN += int64(n) - } - - // AcmRevision (ManifestFieldType: arrayStatic) - { - n, err := 3, binary.Read(r, binary.LittleEndian, s.AcmRevision[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'AcmRevision': %w", err) - } - totalN += int64(n) - } - - // ProcessorIDList (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.ProcessorIDList) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'ProcessorIDList': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *ChipsetACModuleInformation) RehashRecursive() { - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *ChipsetACModuleInformation) Rehash() { -} - -// WriteTo writes the ChipsetACModuleInformation into 'w' in format defined in -// the document #575623. -func (s *ChipsetACModuleInformation) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // UUID (ManifestFieldType: arrayStatic) - { - n, err := 16, binary.Write(w, binary.LittleEndian, s.UUID[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'UUID': %w", err) - } - totalN += int64(n) - } - - // ChipsetACMType (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.ChipsetACMType) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'ChipsetACMType': %w", err) - } - totalN += int64(n) - } - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Version': %w", err) - } - totalN += int64(n) - } - - // Length (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.Length) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Length': %w", err) - } - totalN += int64(n) - } - - // ChipsetIDList (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.ChipsetIDList) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'ChipsetIDList': %w", err) - } - totalN += int64(n) - } - - // OsSinitDataVer (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.OsSinitDataVer) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'OsSinitDataVer': %w", err) - } - totalN += int64(n) - } - - // MinMleHeaderVer (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.MinMleHeaderVer) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'MinMleHeaderVer': %w", err) - } - totalN += int64(n) - } - - // Capabilities (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.Capabilities) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Capabilities': %w", err) - } - totalN += int64(n) - } - - // AcmVersion (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.AcmVersion) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'AcmVersion': %w", err) - } - totalN += int64(n) - } - - // AcmRevision (ManifestFieldType: arrayStatic) - { - n, err := 3, binary.Write(w, binary.LittleEndian, s.AcmRevision[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'AcmRevision': %w", err) - } - totalN += int64(n) - } - - // ProcessorIDList (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.ProcessorIDList) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'ProcessorIDList': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// UUIDSize returns the size in bytes of the value of field UUID -func (s *ChipsetACModuleInformation) UUIDTotalSize() uint64 { - return 16 -} - -// ChipsetACMTypeSize returns the size in bytes of the value of field ChipsetACMType -func (s *ChipsetACModuleInformation) ChipsetACMTypeTotalSize() uint64 { - return 1 -} - -// VersionSize returns the size in bytes of the value of field Version -func (s *ChipsetACModuleInformation) VersionTotalSize() uint64 { - return 1 -} - -// LengthSize returns the size in bytes of the value of field Length -func (s *ChipsetACModuleInformation) LengthTotalSize() uint64 { - return 2 -} - -// ChipsetIDListSize returns the size in bytes of the value of field ChipsetIDList -func (s *ChipsetACModuleInformation) ChipsetIDListTotalSize() uint64 { - return 4 -} - -// OsSinitDataVerSize returns the size in bytes of the value of field OsSinitDataVer -func (s *ChipsetACModuleInformation) OsSinitDataVerTotalSize() uint64 { - return 4 -} - -// MinMleHeaderVerSize returns the size in bytes of the value of field MinMleHeaderVer -func (s *ChipsetACModuleInformation) MinMleHeaderVerTotalSize() uint64 { - return 4 -} - -// CapabilitiesSize returns the size in bytes of the value of field Capabilities -func (s *ChipsetACModuleInformation) CapabilitiesTotalSize() uint64 { - return 4 -} - -// AcmVersionSize returns the size in bytes of the value of field AcmVersion -func (s *ChipsetACModuleInformation) AcmVersionTotalSize() uint64 { - return 1 -} - -// AcmRevisionSize returns the size in bytes of the value of field AcmRevision -func (s *ChipsetACModuleInformation) AcmRevisionTotalSize() uint64 { - return 3 -} - -// ProcessorIDListSize returns the size in bytes of the value of field ProcessorIDList -func (s *ChipsetACModuleInformation) ProcessorIDListTotalSize() uint64 { - return 4 -} - -// UUIDOffset returns the offset in bytes of field UUID -func (s *ChipsetACModuleInformation) UUIDOffset() uint64 { - return 0 -} - -// ChipsetACMTypeOffset returns the offset in bytes of field ChipsetACMType -func (s *ChipsetACModuleInformation) ChipsetACMTypeOffset() uint64 { - return s.UUIDOffset() + s.UUIDTotalSize() -} - -// VersionOffset returns the offset in bytes of field Version -func (s *ChipsetACModuleInformation) VersionOffset() uint64 { - return s.ChipsetACMTypeOffset() + s.ChipsetACMTypeTotalSize() -} - -// LengthOffset returns the offset in bytes of field Length -func (s *ChipsetACModuleInformation) LengthOffset() uint64 { - return s.VersionOffset() + s.VersionTotalSize() -} - -// ChipsetIDListOffset returns the offset in bytes of field ChipsetIDList -func (s *ChipsetACModuleInformation) ChipsetIDListOffset() uint64 { - return s.LengthOffset() + s.LengthTotalSize() -} - -// OsSinitDataVerOffset returns the offset in bytes of field OsSinitDataVer -func (s *ChipsetACModuleInformation) OsSinitDataVerOffset() uint64 { - return s.ChipsetIDListOffset() + s.ChipsetIDListTotalSize() -} - -// MinMleHeaderVerOffset returns the offset in bytes of field MinMleHeaderVer -func (s *ChipsetACModuleInformation) MinMleHeaderVerOffset() uint64 { - return s.OsSinitDataVerOffset() + s.OsSinitDataVerTotalSize() -} - -// CapabilitiesOffset returns the offset in bytes of field Capabilities -func (s *ChipsetACModuleInformation) CapabilitiesOffset() uint64 { - return s.MinMleHeaderVerOffset() + s.MinMleHeaderVerTotalSize() -} - -// AcmVersionOffset returns the offset in bytes of field AcmVersion -func (s *ChipsetACModuleInformation) AcmVersionOffset() uint64 { - return s.CapabilitiesOffset() + s.CapabilitiesTotalSize() -} - -// AcmRevisionOffset returns the offset in bytes of field AcmRevision -func (s *ChipsetACModuleInformation) AcmRevisionOffset() uint64 { - return s.AcmVersionOffset() + s.AcmVersionTotalSize() -} - -// ProcessorIDListOffset returns the offset in bytes of field ProcessorIDList -func (s *ChipsetACModuleInformation) ProcessorIDListOffset() uint64 { - return s.AcmRevisionOffset() + s.AcmRevisionTotalSize() -} - -// Size returns the total size of the ChipsetACModuleInformation. -func (s *ChipsetACModuleInformation) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.UUIDTotalSize() - size += s.ChipsetACMTypeTotalSize() - size += s.VersionTotalSize() - size += s.LengthTotalSize() - size += s.ChipsetIDListTotalSize() - size += s.OsSinitDataVerTotalSize() - size += s.MinMleHeaderVerTotalSize() - size += s.CapabilitiesTotalSize() - size += s.AcmVersionTotalSize() - size += s.AcmRevisionTotalSize() - size += s.ProcessorIDListTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *ChipsetACModuleInformation) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Chipset AC Module Information", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "UUID", "", &s.UUID, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Chipset ACM Type", "", &s.ChipsetACMType, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Version", "", &s.Version, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Length", "", &s.Length, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Chipset ID List", "", &s.ChipsetIDList, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Os Sinit Data Ver", "", &s.OsSinitDataVer, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Min Mle Header Ver", "", &s.MinMleHeaderVer, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Capabilities", "", &s.Capabilities, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Acm Version", "", &s.AcmVersion, opts...)...) - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "Acm Revision", "", &s.AcmRevision, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Processor ID List", "", &s.ProcessorIDList, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} - -// NewChipsetACModuleInformationV5 returns a new instance of ChipsetACModuleInformationV5 with -// all default values set. -func NewChipsetACModuleInformationV5() *ChipsetACModuleInformationV5 { - s := &ChipsetACModuleInformationV5{} - // Recursively initializing a child structure: - s.Base = *NewChipsetACModuleInformation() - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *ChipsetACModuleInformationV5) Validate() error { - // Recursively validating a child structure: - if err := s.Base.Validate(); err != nil { - return fmt.Errorf("error on field 'Base': %w", err) - } - - return nil -} - -// ReadFrom reads the ChipsetACModuleInformationV5 from 'r' in format defined in the document #575623. -func (s *ChipsetACModuleInformationV5) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // Base (ManifestFieldType: subStruct) - { - n, err := s.Base.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Base': %w", err) - } - totalN += int64(n) - } - - // TPMInfoList (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.TPMInfoList) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'TPMInfoList': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *ChipsetACModuleInformationV5) RehashRecursive() { - s.Base.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *ChipsetACModuleInformationV5) Rehash() { -} - -// WriteTo writes the ChipsetACModuleInformationV5 into 'w' in format defined in -// the document #575623. -func (s *ChipsetACModuleInformationV5) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // Base (ManifestFieldType: subStruct) - { - n, err := s.Base.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Base': %w", err) - } - totalN += int64(n) - } - - // TPMInfoList (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.TPMInfoList) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'TPMInfoList': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// BaseSize returns the size in bytes of the value of field Base -func (s *ChipsetACModuleInformationV5) BaseTotalSize() uint64 { - return s.Base.TotalSize() -} - -// TPMInfoListSize returns the size in bytes of the value of field TPMInfoList -func (s *ChipsetACModuleInformationV5) TPMInfoListTotalSize() uint64 { - return 4 -} - -// BaseOffset returns the offset in bytes of field Base -func (s *ChipsetACModuleInformationV5) BaseOffset() uint64 { - return 0 -} - -// TPMInfoListOffset returns the offset in bytes of field TPMInfoList -func (s *ChipsetACModuleInformationV5) TPMInfoListOffset() uint64 { - return s.BaseOffset() + s.BaseTotalSize() -} - -// Size returns the total size of the ChipsetACModuleInformationV5. -func (s *ChipsetACModuleInformationV5) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.BaseTotalSize() - size += s.TPMInfoListTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *ChipsetACModuleInformationV5) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Chipset AC Module Information V 5", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "Base", "", &s.Base, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "TPM Info List", "", &s.TPMInfoList, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/cbnt/crypto_routines_manifestcodegen.go b/pkg/intel/metadata/cbnt/crypto_routines_manifestcodegen.go deleted file mode 100644 index 0a1aca6c..00000000 --- a/pkg/intel/metadata/cbnt/crypto_routines_manifestcodegen.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt - -package cbnt - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v Algorithm) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - return v.String() -} - -// TotalSize returns the total size measured through binary.Size. -func (v Algorithm) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the Algorithm into 'w' in binary format. -func (v Algorithm) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the Algorithm from 'r' in binary format. -func (v Algorithm) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} diff --git a/pkg/intel/metadata/cbnt/hash_manifestcodegen.go b/pkg/intel/metadata/cbnt/hash_manifestcodegen.go deleted file mode 100644 index 8cee6b3a..00000000 --- a/pkg/intel/metadata/cbnt/hash_manifestcodegen.go +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt - -package cbnt - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// NewHashList returns a new instance of HashList with -// all default values set. -func NewHashList() *HashList { - s := &HashList{} - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *HashList) Validate() error { - // See tag "rehashValue" - { - expectedValue := uint16(s.TotalSize()) - if s.Size != expectedValue { - return fmt.Errorf("field 'Size' expects write-value '%v', but has %v", expectedValue, s.Size) - } - } - - return nil -} - -// ReadFrom reads the HashList from 'r' in format defined in the document #575623. -func (s *HashList) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // Size (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.Size) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Size': %w", err) - } - totalN += int64(n) - } - - // List (ManifestFieldType: list) - { - var count uint16 - err := binary.Read(r, binary.LittleEndian, &count) - if err != nil { - return totalN, fmt.Errorf("unable to read the count for field 'List': %w", err) - } - totalN += int64(binary.Size(count)) - s.List = make([]HashStructure, count) - - for idx := range s.List { - n, err := s.List[idx].ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'List[%d]': %w", idx, err) - } - totalN += int64(n) - } - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *HashList) RehashRecursive() { - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *HashList) Rehash() { - s.Size = uint16(s.TotalSize()) -} - -// WriteTo writes the HashList into 'w' in format defined in -// the document #575623. -func (s *HashList) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // Size (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.Size) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Size': %w", err) - } - totalN += int64(n) - } - - // List (ManifestFieldType: list) - { - count := uint16(len(s.List)) - err := binary.Write(w, binary.LittleEndian, &count) - if err != nil { - return totalN, fmt.Errorf("unable to write the count for field 'List': %w", err) - } - totalN += int64(binary.Size(count)) - for idx := range s.List { - n, err := s.List[idx].WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'List[%d]': %w", idx, err) - } - totalN += int64(n) - } - } - - return totalN, nil -} - -// SizeSize returns the size in bytes of the value of field Size -func (s *HashList) SizeTotalSize() uint64 { - return 2 -} - -// ListSize returns the size in bytes of the value of field List -func (s *HashList) ListTotalSize() uint64 { - var size uint64 - size += uint64(binary.Size(uint16(0))) - for idx := range s.List { - size += s.List[idx].TotalSize() - } - return size -} - -// SizeOffset returns the offset in bytes of field Size -func (s *HashList) SizeOffset() uint64 { - return 0 -} - -// ListOffset returns the offset in bytes of field List -func (s *HashList) ListOffset() uint64 { - return s.SizeOffset() + s.SizeTotalSize() -} - -// Size returns the total size of the HashList. -func (s *HashList) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.SizeTotalSize() - size += s.ListTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *HashList) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Hash List", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Size", "", &s.Size, opts...)...) - // ManifestFieldType is list - lines = append(lines, pretty.Header(depth+1, fmt.Sprintf("List: Array of \"Hash List\" of length %d", len(s.List)), s.List)) - for i := 0; i < len(s.List); i++ { - lines = append(lines, fmt.Sprintf("%sitem #%d: ", strings.Repeat(" ", int(depth+2)), i)+strings.TrimSpace(s.List[i].PrettyString(depth+2, true))) - } - if depth < 1 { - lines = append(lines, "") - } - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} - -// NewHashStructure returns a new instance of HashStructure with -// all default values set. -func NewHashStructure() *HashStructure { - s := &HashStructure{} - // Set through tag "default": - s.HashAlg = 0x10 - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *HashStructure) Validate() error { - - return nil -} - -// ReadFrom reads the HashStructure from 'r' in format defined in the document #575623. -func (s *HashStructure) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // HashAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.HashAlg) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'HashAlg': %w", err) - } - totalN += int64(n) - } - - // HashBuffer (ManifestFieldType: arrayDynamic) - { - var size uint16 - err := binary.Read(r, binary.LittleEndian, &size) - if err != nil { - return totalN, fmt.Errorf("unable to the read size of field 'HashBuffer': %w", err) - } - totalN += int64(binary.Size(size)) - s.HashBuffer = make([]byte, size) - n, err := len(s.HashBuffer), binary.Read(r, binary.LittleEndian, s.HashBuffer) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'HashBuffer': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *HashStructure) RehashRecursive() { - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *HashStructure) Rehash() { -} - -// WriteTo writes the HashStructure into 'w' in format defined in -// the document #575623. -func (s *HashStructure) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // HashAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.HashAlg) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'HashAlg': %w", err) - } - totalN += int64(n) - } - - // HashBuffer (ManifestFieldType: arrayDynamic) - { - size := uint16(len(s.HashBuffer)) - err := binary.Write(w, binary.LittleEndian, size) - if err != nil { - return totalN, fmt.Errorf("unable to write the size of field 'HashBuffer': %w", err) - } - totalN += int64(binary.Size(size)) - n, err := len(s.HashBuffer), binary.Write(w, binary.LittleEndian, s.HashBuffer) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'HashBuffer': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// HashAlgSize returns the size in bytes of the value of field HashAlg -func (s *HashStructure) HashAlgTotalSize() uint64 { - return 2 -} - -// HashBufferSize returns the size in bytes of the value of field HashBuffer -func (s *HashStructure) HashBufferTotalSize() uint64 { - size := uint64(binary.Size(uint16(0))) - size += uint64(len(s.HashBuffer)) - return size -} - -// HashAlgOffset returns the offset in bytes of field HashAlg -func (s *HashStructure) HashAlgOffset() uint64 { - return 0 -} - -// HashBufferOffset returns the offset in bytes of field HashBuffer -func (s *HashStructure) HashBufferOffset() uint64 { - return s.HashAlgOffset() + s.HashAlgTotalSize() -} - -// Size returns the total size of the HashStructure. -func (s *HashStructure) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.HashAlgTotalSize() - size += s.HashBufferTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *HashStructure) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Hash Structure", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Hash Alg", "", &s.HashAlg, opts...)...) - // ManifestFieldType is arrayDynamic - lines = append(lines, pretty.SubValue(depth+1, "Hash Buffer", "", &s.HashBuffer, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/cbnt/key_manifestcodegen.go b/pkg/intel/metadata/cbnt/key_manifestcodegen.go deleted file mode 100644 index 21a85c0f..00000000 --- a/pkg/intel/metadata/cbnt/key_manifestcodegen.go +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt - -package cbnt - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// NewKey returns a new instance of Key with -// all default values set. -func NewKey() *Key { - s := &Key{} - // Set through tag "required": - s.Version = 0x10 - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *Key) Validate() error { - // See tag "require" - if s.Version != 0x10 { - return fmt.Errorf("field 'Version' expects value '0x10', but has %v", s.Version) - } - - return nil -} - -// ReadFrom reads the Key from 'r' in format defined in the document #575623. -func (s *Key) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // KeyAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.KeyAlg) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'KeyAlg': %w", err) - } - totalN += int64(n) - } - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Version': %w", err) - } - totalN += int64(n) - } - - // KeySize (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.KeySize) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'KeySize': %w", err) - } - totalN += int64(n) - } - - // Data (ManifestFieldType: arrayDynamic) - { - size := uint16(s.keyDataSize()) - s.Data = make([]byte, size) - n, err := len(s.Data), binary.Read(r, binary.LittleEndian, s.Data) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Data': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *Key) RehashRecursive() { - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *Key) Rehash() { -} - -// WriteTo writes the Key into 'w' in format defined in -// the document #575623. -func (s *Key) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // KeyAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.KeyAlg) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'KeyAlg': %w", err) - } - totalN += int64(n) - } - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Version': %w", err) - } - totalN += int64(n) - } - - // KeySize (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.KeySize) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'KeySize': %w", err) - } - totalN += int64(n) - } - - // Data (ManifestFieldType: arrayDynamic) - { - n, err := len(s.Data), binary.Write(w, binary.LittleEndian, s.Data) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Data': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// KeyAlgSize returns the size in bytes of the value of field KeyAlg -func (s *Key) KeyAlgTotalSize() uint64 { - return 2 -} - -// VersionSize returns the size in bytes of the value of field Version -func (s *Key) VersionTotalSize() uint64 { - return 1 -} - -// KeySizeSize returns the size in bytes of the value of field KeySize -func (s *Key) KeySizeTotalSize() uint64 { - return 2 -} - -// DataSize returns the size in bytes of the value of field Data -func (s *Key) DataTotalSize() uint64 { - return uint64(len(s.Data)) -} - -// KeyAlgOffset returns the offset in bytes of field KeyAlg -func (s *Key) KeyAlgOffset() uint64 { - return 0 -} - -// VersionOffset returns the offset in bytes of field Version -func (s *Key) VersionOffset() uint64 { - return s.KeyAlgOffset() + s.KeyAlgTotalSize() -} - -// KeySizeOffset returns the offset in bytes of field KeySize -func (s *Key) KeySizeOffset() uint64 { - return s.VersionOffset() + s.VersionTotalSize() -} - -// DataOffset returns the offset in bytes of field Data -func (s *Key) DataOffset() uint64 { - return s.KeySizeOffset() + s.KeySizeTotalSize() -} - -// Size returns the total size of the Key. -func (s *Key) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.KeyAlgTotalSize() - size += s.VersionTotalSize() - size += s.KeySizeTotalSize() - size += s.DataTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *Key) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Key", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Key Alg", "", &s.KeyAlg, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Version", "", &s.Version, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Key Size", "", &s.KeySize, opts...)...) - // ManifestFieldType is arrayDynamic - lines = append(lines, pretty.SubValue(depth+1, "Data", "", &s.Data, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v BitSize) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Bit Size", v)) - } - lines = append(lines, pretty.SubValue(depth+1, "In Bits", "", v.InBits(), opts...)...) - lines = append(lines, pretty.SubValue(depth+1, "In Bytes", "", v.InBytes(), opts...)...) - return strings.Join(lines, "\n") -} - -// TotalSize returns the total size measured through binary.Size. -func (v BitSize) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the BitSize into 'w' in binary format. -func (v BitSize) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the BitSize from 'r' in binary format. -func (v BitSize) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} diff --git a/pkg/intel/metadata/cbnt/key_signature_manifestcodegen.go b/pkg/intel/metadata/cbnt/key_signature_manifestcodegen.go deleted file mode 100644 index 68b23ba1..00000000 --- a/pkg/intel/metadata/cbnt/key_signature_manifestcodegen.go +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt - -package cbnt - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// NewKeySignature returns a new instance of KeySignature with -// all default values set. -func NewKeySignature() *KeySignature { - s := &KeySignature{} - // Set through tag "required": - s.Version = 0x10 - // Recursively initializing a child structure: - s.Key = *NewKey() - // Recursively initializing a child structure: - s.Signature = *NewSignature() - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *KeySignature) Validate() error { - // See tag "require" - if s.Version != 0x10 { - return fmt.Errorf("field 'Version' expects value '0x10', but has %v", s.Version) - } - // Recursively validating a child structure: - if err := s.Key.Validate(); err != nil { - return fmt.Errorf("error on field 'Key': %w", err) - } - // Recursively validating a child structure: - if err := s.Signature.Validate(); err != nil { - return fmt.Errorf("error on field 'Signature': %w", err) - } - - return nil -} - -// ReadFrom reads the KeySignature from 'r' in format defined in the document #575623. -func (s *KeySignature) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Version': %w", err) - } - totalN += int64(n) - } - - // Key (ManifestFieldType: subStruct) - { - n, err := s.Key.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Key': %w", err) - } - totalN += int64(n) - } - - // Signature (ManifestFieldType: subStruct) - { - n, err := s.Signature.ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Signature': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *KeySignature) RehashRecursive() { - s.Key.Rehash() - s.Signature.Rehash() - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *KeySignature) Rehash() { -} - -// WriteTo writes the KeySignature into 'w' in format defined in -// the document #575623. -func (s *KeySignature) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Version': %w", err) - } - totalN += int64(n) - } - - // Key (ManifestFieldType: subStruct) - { - n, err := s.Key.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Key': %w", err) - } - totalN += int64(n) - } - - // Signature (ManifestFieldType: subStruct) - { - n, err := s.Signature.WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Signature': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// VersionSize returns the size in bytes of the value of field Version -func (s *KeySignature) VersionTotalSize() uint64 { - return 1 -} - -// KeySize returns the size in bytes of the value of field Key -func (s *KeySignature) KeyTotalSize() uint64 { - return s.Key.TotalSize() -} - -// SignatureSize returns the size in bytes of the value of field Signature -func (s *KeySignature) SignatureTotalSize() uint64 { - return s.Signature.TotalSize() -} - -// VersionOffset returns the offset in bytes of field Version -func (s *KeySignature) VersionOffset() uint64 { - return 0 -} - -// KeyOffset returns the offset in bytes of field Key -func (s *KeySignature) KeyOffset() uint64 { - return s.VersionOffset() + s.VersionTotalSize() -} - -// SignatureOffset returns the offset in bytes of field Signature -func (s *KeySignature) SignatureOffset() uint64 { - return s.KeyOffset() + s.KeyTotalSize() -} - -// Size returns the total size of the KeySignature. -func (s *KeySignature) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.VersionTotalSize() - size += s.KeyTotalSize() - size += s.SignatureTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *KeySignature) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Key Signature", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Version", "", &s.Version, opts...)...) - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "Key", "", &s.Key, opts...)...) - // ManifestFieldType is subStruct - lines = append(lines, pretty.SubValue(depth+1, "Signature", "", &s.Signature, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/cbnt/signature_manifestcodegen.go b/pkg/intel/metadata/cbnt/signature_manifestcodegen.go deleted file mode 100644 index 143c990b..00000000 --- a/pkg/intel/metadata/cbnt/signature_manifestcodegen.go +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt - -package cbnt - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// NewSignature returns a new instance of Signature with -// all default values set. -func NewSignature() *Signature { - s := &Signature{} - // Set through tag "required": - s.Version = 0x10 - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *Signature) Validate() error { - // See tag "require" - if s.Version != 0x10 { - return fmt.Errorf("field 'Version' expects value '0x10', but has %v", s.Version) - } - - return nil -} - -// ReadFrom reads the Signature from 'r' in format defined in the document #575623. -func (s *Signature) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // SigScheme (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.SigScheme) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'SigScheme': %w", err) - } - totalN += int64(n) - } - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Version': %w", err) - } - totalN += int64(n) - } - - // KeySize (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.KeySize) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'KeySize': %w", err) - } - totalN += int64(n) - } - - // HashAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.HashAlg) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'HashAlg': %w", err) - } - totalN += int64(n) - } - - // Data (ManifestFieldType: arrayDynamic) - { - size := uint16(s.KeySize.InBytes()) - s.Data = make([]byte, size) - n, err := len(s.Data), binary.Read(r, binary.LittleEndian, s.Data) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Data': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *Signature) RehashRecursive() { - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *Signature) Rehash() { -} - -// WriteTo writes the Signature into 'w' in format defined in -// the document #575623. -func (s *Signature) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // SigScheme (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.SigScheme) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'SigScheme': %w", err) - } - totalN += int64(n) - } - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Version': %w", err) - } - totalN += int64(n) - } - - // KeySize (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.KeySize) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'KeySize': %w", err) - } - totalN += int64(n) - } - - // HashAlg (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.HashAlg) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'HashAlg': %w", err) - } - totalN += int64(n) - } - - // Data (ManifestFieldType: arrayDynamic) - { - n, err := len(s.Data), binary.Write(w, binary.LittleEndian, s.Data) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Data': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// SigSchemeSize returns the size in bytes of the value of field SigScheme -func (s *Signature) SigSchemeTotalSize() uint64 { - return 2 -} - -// VersionSize returns the size in bytes of the value of field Version -func (s *Signature) VersionTotalSize() uint64 { - return 1 -} - -// KeySizeSize returns the size in bytes of the value of field KeySize -func (s *Signature) KeySizeTotalSize() uint64 { - return 2 -} - -// HashAlgSize returns the size in bytes of the value of field HashAlg -func (s *Signature) HashAlgTotalSize() uint64 { - return 2 -} - -// DataSize returns the size in bytes of the value of field Data -func (s *Signature) DataTotalSize() uint64 { - return uint64(len(s.Data)) -} - -// SigSchemeOffset returns the offset in bytes of field SigScheme -func (s *Signature) SigSchemeOffset() uint64 { - return 0 -} - -// VersionOffset returns the offset in bytes of field Version -func (s *Signature) VersionOffset() uint64 { - return s.SigSchemeOffset() + s.SigSchemeTotalSize() -} - -// KeySizeOffset returns the offset in bytes of field KeySize -func (s *Signature) KeySizeOffset() uint64 { - return s.VersionOffset() + s.VersionTotalSize() -} - -// HashAlgOffset returns the offset in bytes of field HashAlg -func (s *Signature) HashAlgOffset() uint64 { - return s.KeySizeOffset() + s.KeySizeTotalSize() -} - -// DataOffset returns the offset in bytes of field Data -func (s *Signature) DataOffset() uint64 { - return s.HashAlgOffset() + s.HashAlgTotalSize() -} - -// Size returns the total size of the Signature. -func (s *Signature) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.SigSchemeTotalSize() - size += s.VersionTotalSize() - size += s.KeySizeTotalSize() - size += s.HashAlgTotalSize() - size += s.DataTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *Signature) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Signature", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Sig Scheme", "", &s.SigScheme, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Version", "", &s.Version, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Key Size", "", &s.KeySize, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Hash Alg", "", &s.HashAlg, opts...)...) - // ManifestFieldType is arrayDynamic - lines = append(lines, pretty.SubValue(depth+1, "Data", "", s.dataPrettyValue(), opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/cbnt/structure_manifestcodegen.go b/pkg/intel/metadata/cbnt/structure_manifestcodegen.go deleted file mode 100644 index ff575229..00000000 --- a/pkg/intel/metadata/cbnt/structure_manifestcodegen.go +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt - -package cbnt - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// NewStructInfo returns a new instance of StructInfo with -// all default values set. -func NewStructInfo() *StructInfo { - s := &StructInfo{} - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *StructInfo) Validate() error { - - return nil -} - -// ReadFrom reads the StructInfo from 'r' in format defined in the document #575623. -func (s *StructInfo) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // ID (ManifestFieldType: arrayStatic) - { - n, err := 8, binary.Read(r, binary.LittleEndian, s.ID[:]) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'ID': %w", err) - } - totalN += int64(n) - } - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Version': %w", err) - } - totalN += int64(n) - } - - // Variable0 (ManifestFieldType: endValue) - { - n, err := 1, binary.Read(r, binary.LittleEndian, &s.Variable0) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Variable0': %w", err) - } - totalN += int64(n) - } - - // ElementSize (ManifestFieldType: endValue) - { - n, err := 2, binary.Read(r, binary.LittleEndian, &s.ElementSize) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'ElementSize': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *StructInfo) RehashRecursive() { - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *StructInfo) Rehash() { -} - -// WriteTo writes the StructInfo into 'w' in format defined in -// the document #575623. -func (s *StructInfo) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // ID (ManifestFieldType: arrayStatic) - { - n, err := 8, binary.Write(w, binary.LittleEndian, s.ID[:]) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'ID': %w", err) - } - totalN += int64(n) - } - - // Version (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.Version) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Version': %w", err) - } - totalN += int64(n) - } - - // Variable0 (ManifestFieldType: endValue) - { - n, err := 1, binary.Write(w, binary.LittleEndian, &s.Variable0) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Variable0': %w", err) - } - totalN += int64(n) - } - - // ElementSize (ManifestFieldType: endValue) - { - n, err := 2, binary.Write(w, binary.LittleEndian, &s.ElementSize) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'ElementSize': %w", err) - } - totalN += int64(n) - } - - return totalN, nil -} - -// IDSize returns the size in bytes of the value of field ID -func (s *StructInfo) IDTotalSize() uint64 { - return 8 -} - -// VersionSize returns the size in bytes of the value of field Version -func (s *StructInfo) VersionTotalSize() uint64 { - return 1 -} - -// Variable0Size returns the size in bytes of the value of field Variable0 -func (s *StructInfo) Variable0TotalSize() uint64 { - return 1 -} - -// ElementSizeSize returns the size in bytes of the value of field ElementSize -func (s *StructInfo) ElementSizeTotalSize() uint64 { - return 2 -} - -// IDOffset returns the offset in bytes of field ID -func (s *StructInfo) IDOffset() uint64 { - return 0 -} - -// VersionOffset returns the offset in bytes of field Version -func (s *StructInfo) VersionOffset() uint64 { - return s.IDOffset() + s.IDTotalSize() -} - -// Variable0Offset returns the offset in bytes of field Variable0 -func (s *StructInfo) Variable0Offset() uint64 { - return s.VersionOffset() + s.VersionTotalSize() -} - -// ElementSizeOffset returns the offset in bytes of field ElementSize -func (s *StructInfo) ElementSizeOffset() uint64 { - return s.Variable0Offset() + s.Variable0TotalSize() -} - -// Size returns the total size of the StructInfo. -func (s *StructInfo) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.IDTotalSize() - size += s.VersionTotalSize() - size += s.Variable0TotalSize() - size += s.ElementSizeTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *StructInfo) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "Struct Info", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is arrayStatic - lines = append(lines, pretty.SubValue(depth+1, "ID", "", &s.ID, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Version", "", &s.Version, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Variable 0", "", &s.Variable0, opts...)...) - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Element Size", "", &s.ElementSize, opts...)...) - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} diff --git a/pkg/intel/metadata/cbnt/tpm_info_list_manifestcodegen.go b/pkg/intel/metadata/cbnt/tpm_info_list_manifestcodegen.go deleted file mode 100644 index e68bf58d..00000000 --- a/pkg/intel/metadata/cbnt/tpm_info_list_manifestcodegen.go +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// Code generated by "menifestcodegen". DO NOT EDIT. -// To reproduce: go run github.com/linuxboot/fiano/pkg/intel/metadata/common/manifestcodegen/cmd/manifestcodegen github.com/linuxboot/fiano/pkg/intel/metadata/cbnt - -package cbnt - -import ( - "encoding/binary" - "fmt" - "io" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -var ( - // Just to avoid errors in "import" above in case if it wasn't used below - _ = binary.LittleEndian - _ = (fmt.Stringer)(nil) - _ = (io.Reader)(nil) - _ = pretty.Header - _ = strings.Join -) - -// NewTPMInfoList returns a new instance of TPMInfoList with -// all default values set. -func NewTPMInfoList() *TPMInfoList { - s := &TPMInfoList{} - s.Rehash() - return s -} - -// Validate (recursively) checks the structure if there are any unexpected -// values. It returns an error if so. -func (s *TPMInfoList) Validate() error { - - return nil -} - -// ReadFrom reads the TPMInfoList from 'r' in format defined in the document #575623. -func (s *TPMInfoList) ReadFrom(r io.Reader) (int64, error) { - totalN := int64(0) - - // Capabilities (ManifestFieldType: endValue) - { - n, err := 4, binary.Read(r, binary.LittleEndian, &s.Capabilities) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Capabilities': %w", err) - } - totalN += int64(n) - } - - // Algorithms (ManifestFieldType: list) - { - var count uint16 - err := binary.Read(r, binary.LittleEndian, &count) - if err != nil { - return totalN, fmt.Errorf("unable to read the count for field 'Algorithms': %w", err) - } - totalN += int64(binary.Size(count)) - s.Algorithms = make([]Algorithm, count) - - for idx := range s.Algorithms { - n, err := s.Algorithms[idx].ReadFrom(r) - if err != nil { - return totalN, fmt.Errorf("unable to read field 'Algorithms[%d]': %w", idx, err) - } - totalN += int64(n) - } - } - - return totalN, nil -} - -// RehashRecursive calls Rehash (see below) recursively. -func (s *TPMInfoList) RehashRecursive() { - s.Rehash() -} - -// Rehash sets values which are calculated automatically depending on the rest -// data. It is usually about the total size field of an element. -func (s *TPMInfoList) Rehash() { -} - -// WriteTo writes the TPMInfoList into 'w' in format defined in -// the document #575623. -func (s *TPMInfoList) WriteTo(w io.Writer) (int64, error) { - totalN := int64(0) - s.Rehash() - - // Capabilities (ManifestFieldType: endValue) - { - n, err := 4, binary.Write(w, binary.LittleEndian, &s.Capabilities) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Capabilities': %w", err) - } - totalN += int64(n) - } - - // Algorithms (ManifestFieldType: list) - { - count := uint16(len(s.Algorithms)) - err := binary.Write(w, binary.LittleEndian, &count) - if err != nil { - return totalN, fmt.Errorf("unable to write the count for field 'Algorithms': %w", err) - } - totalN += int64(binary.Size(count)) - for idx := range s.Algorithms { - n, err := s.Algorithms[idx].WriteTo(w) - if err != nil { - return totalN, fmt.Errorf("unable to write field 'Algorithms[%d]': %w", idx, err) - } - totalN += int64(n) - } - } - - return totalN, nil -} - -// CapabilitiesSize returns the size in bytes of the value of field Capabilities -func (s *TPMInfoList) CapabilitiesTotalSize() uint64 { - return 4 -} - -// AlgorithmsSize returns the size in bytes of the value of field Algorithms -func (s *TPMInfoList) AlgorithmsTotalSize() uint64 { - var size uint64 - size += uint64(binary.Size(uint16(0))) - for idx := range s.Algorithms { - size += s.Algorithms[idx].TotalSize() - } - return size -} - -// CapabilitiesOffset returns the offset in bytes of field Capabilities -func (s *TPMInfoList) CapabilitiesOffset() uint64 { - return 0 -} - -// AlgorithmsOffset returns the offset in bytes of field Algorithms -func (s *TPMInfoList) AlgorithmsOffset() uint64 { - return s.CapabilitiesOffset() + s.CapabilitiesTotalSize() -} - -// Size returns the total size of the TPMInfoList. -func (s *TPMInfoList) TotalSize() uint64 { - if s == nil { - return 0 - } - - var size uint64 - size += s.CapabilitiesTotalSize() - size += s.AlgorithmsTotalSize() - return size -} - -// PrettyString returns the content of the structure in an easy-to-read format. -func (s *TPMInfoList) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "TPM Info List", s)) - } - if s == nil { - return strings.Join(lines, "\n") - } - // ManifestFieldType is endValue - lines = append(lines, pretty.SubValue(depth+1, "Capabilities", "", &s.Capabilities, opts...)...) - // ManifestFieldType is list - lines = append(lines, pretty.Header(depth+1, fmt.Sprintf("Algorithms: Array of \"TPM Info List\" of length %d", len(s.Algorithms)), s.Algorithms)) - for i := 0; i < len(s.Algorithms); i++ { - lines = append(lines, fmt.Sprintf("%sitem #%d: ", strings.Repeat(" ", int(depth+2)), i)+strings.TrimSpace(s.Algorithms[i].PrettyString(depth+2, true))) - } - if depth < 1 { - lines = append(lines, "") - } - if depth < 2 { - lines = append(lines, "") - } - return strings.Join(lines, "\n") -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v TPM2PCRExtendPolicySupport) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "TPM 2 PCR Extend Policy Support", v)) - } - return strings.Join(lines, "\n") -} - -// TotalSize returns the total size measured through binary.Size. -func (v TPM2PCRExtendPolicySupport) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the TPM2PCRExtendPolicySupport into 'w' in binary format. -func (v TPM2PCRExtendPolicySupport) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the TPM2PCRExtendPolicySupport from 'r' in binary format. -func (v TPM2PCRExtendPolicySupport) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v TPMCapabilities) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "TPM Capabilities", v)) - } - lines = append(lines, pretty.SubValue(depth+1, "TPM 2 PCR Extend Policy Support", "", v.TPM2PCRExtendPolicySupport(), opts...)...) - lines = append(lines, pretty.SubValue(depth+1, "TPM Family Support", "", v.TPMFamilySupport(), opts...)...) - return strings.Join(lines, "\n") -} - -// TotalSize returns the total size measured through binary.Size. -func (v TPMCapabilities) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the TPMCapabilities into 'w' in binary format. -func (v TPMCapabilities) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the TPMCapabilities from 'r' in binary format. -func (v TPMCapabilities) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} - -// PrettyString returns the bits of the flags in an easy-to-read format. -func (v TPMFamilySupport) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { - var lines []string - if withHeader { - lines = append(lines, pretty.Header(depth, "TPM Family Support", v)) - } - if v.IsDiscreteTPM12Supported() { - lines = append(lines, pretty.SubValue(depth+1, "Is Discrete TPM 12 Supported", "Discrete TPM1.2 is supported", true, opts...)...) - } else { - lines = append(lines, pretty.SubValue(depth+1, "Is Discrete TPM 12 Supported", "Discrete TPM1.2 is not supported", false, opts...)...) - } - if v.IsDiscreteTPM20Supported() { - lines = append(lines, pretty.SubValue(depth+1, "Is Discrete TPM 20 Supported", "Discrete TPM2.0 is supported", true, opts...)...) - } else { - lines = append(lines, pretty.SubValue(depth+1, "Is Discrete TPM 20 Supported", "Discrete TPM2.0 is not supported", false, opts...)...) - } - if v.IsFirmwareTPM20Supported() { - lines = append(lines, pretty.SubValue(depth+1, "Is Firmware TPM 20 Supported", "Firmware TPM2.0 is supported", true, opts...)...) - } else { - lines = append(lines, pretty.SubValue(depth+1, "Is Firmware TPM 20 Supported", "Firmware TPM2.0 is not supported", false, opts...)...) - } - return strings.Join(lines, "\n") -} - -// TotalSize returns the total size measured through binary.Size. -func (v TPMFamilySupport) TotalSize() uint64 { - return uint64(binary.Size(v)) -} - -// WriteTo writes the TPMFamilySupport into 'w' in binary format. -func (v TPMFamilySupport) WriteTo(w io.Writer) (int64, error) { - return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) -} - -// ReadFrom reads the TPMFamilySupport from 'r' in binary format. -func (v TPMFamilySupport) ReadFrom(r io.Reader) (int64, error) { - return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) -} From 5903d58b9d40ebd5befd17f24bdf0dd0f9bc55f4 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 9 Apr 2026 21:05:41 +0200 Subject: [PATCH 03/40] docs(intel/metadata): add documentation Add README describing new approach for metadata handling, and move old readme to separate place. Signed-off-by: Michal Gorlas --- pkg/intel/metadata/README.md | 550 ++++++++++++++++-- .../metadata/common/manifestcodegen/README.md | 63 ++ 2 files changed, 572 insertions(+), 41 deletions(-) create mode 100644 pkg/intel/metadata/common/manifestcodegen/README.md diff --git a/pkg/intel/metadata/README.md b/pkg/intel/metadata/README.md index 8f649092..bed105b4 100644 --- a/pkg/intel/metadata/README.md +++ b/pkg/intel/metadata/README.md @@ -1,59 +1,527 @@ -Prequesites: -Open another terminal and go get the sm2/sm3 crypto library into your gopath. -The code generator disables go modules. +# Intel BG/CBnT Metadata + + +- [Intel BG/CBnT Metadata](#intel-bgcbnt-metadata) + - [Structure](#structure) + - [cbnt](#cbnt) + - [bootpolicy](#bootpolicy) + - [keymanifest](#keymanifest) + - [Structure Modification/Extension](#structure-modificationextension) + - [Types with Static Sizes](#types-with-static-sizes) + - [Types with Dynamic Sizes](#types-with-dynamic-sizes) + - [Field Type Quick Reference](#field-type-quick-reference) + - [Adding a Structure](#adding-a-structure) + - [Extending a Structure](#extending-a-structure) + + +This directory contains reusable definitions of common BG/CBnT structures and Boot Policy and Key Manifests for Intel platforms. + +## Structure ``` -GOPATH=your/go/path go get github.com/tjfoc/gmsm/sm2 +├── cbnt # Converged Boot Guard and TXT +│   ├── bootpolicy # BG/CBnT Boot Policy Manifest +│   ├── keymanifest # BG/CBnT Key Manifest +├── common # Common elements +│   ├── examples +│   ├── manifestcodegen # Legacy code generator +│   ├── pretty # Helper for printing the structures in human readable format +│   ├── tracedbinary +│   └── unittest # +└── fit # Firmware Interface Table ``` -To generalize all the logic related to Boot Policy Manifest and Key Manifest -we use code generation. Therefore it is enough to create structure declarations -and run command from this directory: +## cbnt +The `cbnt` packages defines the structures that are used by both Boot Policy and Key Manifests. +Most of the structures are shared between Boot Guard 1.0 and CBnT, with an exception for the following: + +- Chipset AC Module Information +- TPM Info List + +## bootpolicy +The `bootpolicy` package defines the Boot Policy Manifest and its child structures. In contrast with `cbnt`, +there are more differences between Boot Guard 1.0 and CBnT. Therefore, the Manifest constructor make the distinction +between the versions and returns the versioned implementation of the Manifest interface. Similar pattern is being used for +the structures that form the Manifest. + +The users of the `bootpolicy` packages should therefore make use of type assertions. These are safe in this context provided +that the constructor is feed with the supported version, and the error is handled correctly. An example usage: +```go +bpm, err := bootpolicy.NewManifest(cbnt.Version10) +if err != nil { + return nil, err +} +bgbpm = bpm.(*bootpolicy.ManifestBG) ``` -go run ./../common/manifestcodegen/cmd/manifestcodegen/ . ./bootpolicy ./key + +From that point on, the elements of the implementation may be accessed directly, for example: +```go +flags := bgbpm.SE[0].Flags +if !flags.AuthorityMeasure() { + return false, 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") +} ``` -It will performe the code autogeneration in directories: -* Current directory (`.`), which contains common structures for different manifests; -* Boot Policy Manifest directory (`./bootpolicy`); -* and Key Manifest directory (`./key`). +## keymanifest +The `keymanifest` package defines the Key Manifest. It follows the same design as `bootpolicy`. An example usage: +```go +km, err := keymanifest.NewManifest(b.Version) +if err != nil { + return nil, err +} +cbntkm = km.(*keymanifest.CBnTManifest) -To check if the files are in the up-to-date state, one may add option `-check`: +hash := cbntkm.PubKeyHashAlg + if hash == cbnt.AlgSHA1 || hash.IsNull() { + return false, fmt.Errorf("KM signature uses insecure hash algorithm SHA1/Null") + } ``` -go run ./../common/manifestcodegen/cmd/manifestcodegen/ -check . ./bootpolicy ./key + +## Structure Modification/Extension +All the structures should implement the `Structure` interface (see [`cbnt/types.go`](cbnt/types.go)): +```go +Structure interface { + io.ReaderFrom + io.WriterTo + TotalSize() uint64 + SizeOf(id int) (uint64, error) + OffsetOf(id int) (uint64, error) + Layout() []LayoutField + Validate() error + PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string +} +``` + +The most important method of the structure is the `Layout()` as it provides the `Common.ReadFrom()`, `Common.WriteTo()`, `Common.SizeOf()` and `Common.OffsetOf()` methods +with the information of the actual type the operation is supposed to be done. The common methods are accessed by letting all types to have `Common` struct +as a field. +> [!NOTE] +> `Common` struct should never be included in the `Layout()`! Otherwise, it will be treated as the actual part of the CBnT data structure. + +### Types with Static Sizes +In most cases, that is, for the types that do not include fields that have their size determined at compile time, most of work is done in `Layout()` +method. Let's take `StructureInfoCBNT` as an example: +```go +func (s StructInfoCBNT) Layout() []LayoutField { + return []LayoutField{ + { + ID: 0, + Name: "ID", + Size: func() uint64 { return 8 }, + Value: func() any { return &s.ID }, + Type: ManifestFieldArrayStatic, + }, + { + ID: 1, + Name: "Version", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Version }, + Type: ManifestFieldEndValue, + }, + { + ID: 2, + Name: "Variable 0", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Variable0 }, + Type: ManifestFieldEndValue, + }, + { + ID: 3, + Name: "Element Size", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.ElementSize }, + Type: ManifestFieldEndValue, + }, + } +} ``` -Or if it is required to debug/trace the behavior of autogenerated code, one -may add option `-trace`: +All the values are known at compile time, and therefore the sizes defined in the specification can be filled in directly. + +### Types with Dynamic Sizes +The types that have dynamic sizes are different beasts. They should still describe all fields through `Layout()`, but the `Size` +closure is computed from runtime values. The actual implementation is left for the person introducing a new type. + +There are three "Types" of dynamic sized fields: + - `ManifestFieldArrayDynamicWithSize` for byte arrays whose length is known from context (for example another field or algorithm-dependent size). +An example can be seen in `Key` type which is declared as: +```go +type Key struct { + Common + KeyAlg Algorithm `json:"keyAlg"` + Version uint8 `require:"0x10" json:"keyVersion"` + KeySize BitSize `json:"keyBitsize"` + Data []byte `countValue:"keyDataSize()" json:"keyData"` +} ``` -go run ./../common/manifestcodegen/cmd/manifestcodegen/ -trace . ./bootpolicy ./key +The size of `Data` field is equal to the value of `KeySize` which is first determined once the structure is filled-in on a call to `Common.ReadFrom()`. +Therefore, the size closure in `Key`'s `Layout()` has to return the value of `KeySize`: +```go +{ + ID: 3, + Name: "Data", + Size: func() uint64 { return uint64(k.keyDataSize()) }, + Value: func() any { return &k.Data }, + Type: ManifestFieldArrayDynamicWithSize, +}, ``` -In this case the code will write a verbose log into stdout. +- `ManifestFieldArrayDynamicWithPrefix` for byte arrays that carry their own size prefix on the wire. An example for such case is the `HashStructure` type declared as: +```go +type HashStructure struct { + Common + HashAlg Algorithm `default:"0x10" json:"hsAlg"` + HashBuffer []byte `json:"hsBuffer"` +} +``` + +The size of `HashBuffer` is dynamic, but unlike `ManifestFieldArrayDynamicWithSize`, this encoding stores a `uint16` +length prefix before the actual bytes. Therefore, the `Size` closure includes both the prefix and the payload (which depends on the hash algorithm type): +```go +{ + ID: 1, + Name: "Hash Buffer", + Size: func() uint64 { + h, err := s.HashAlg.Hash() + if err != nil { + return uint64(binary.Size(uint16(0))) + } + return uint64(binary.Size(uint16(0))) + uint64(h.Size()) + }, + Value: func() any { return &s.HashBuffer }, + Type: ManifestFieldArrayDynamicWithPrefix, +}, +``` +Here, `binary.Size(uint16(0))` is the on-wire size prefix. + +- `ManifestFieldList` for repeated items where count and element parsing/writing are custom; this requires `ReadList` and `WriteList` handlers. An example +for such case is the `HashList` type, declared as: +```go +type HashList struct { + Common + Size uint16 `rehashValue:"TotalSize()" json:"hlSize"` + List []HashStructure `json:"hlList"` +} +``` + +Such types require addition fields to be returned in `Layout()`, and are an exception from the rule that all R/W logic is shared between the types. This is +motivated by the fact that `Common.ReadFrom()`/`Common.WriteTo()` cannot infer neither the type of the element on the list (well, it is possible with [reflection](https://go.dev/blog/laws-of-reflection), +though it would make common R/W methods look like dark magic), nor many elements should be processed and how each one should be +serialized. Therefore, `ReadList` and `WriteList` closures must be provided: +```go +{ + ReadList: func(r io.Reader) (int64, error) { + var count uint16 + if err := binary.Read(r, endianess, &count); err != nil { + return 0, fmt.Errorf("unable to read the count for field 'List': %w", err) + } + totalN := int64(binary.Size(count)) + s.List = make([]HashStructure, count) + for idx := range s.List { + n, err := s.List[idx].ReadFrom(r) + if err != nil { + return totalN, fmt.Errorf("unable to read field 'List[%d]': %w", idx, err) + } + totalN += int64(n) + } + return totalN, nil + }, + WriteList: func(w io.Writer) (int64, error) { + count := uint16(len(s.List)) + if err := binary.Write(w, binary.LittleEndian, &count); err != nil { + return 0, fmt.Errorf("unable to write the count for field 'List': %w", err) + } + totalN := int64(binary.Size(count)) + for idx := range s.List { + n, err := s.List[idx].WriteTo(w) + if err != nil { + return totalN, fmt.Errorf("unable to write field 'List[%d]': %w", idx, err) + } + totalN += int64(n) + } + return totalN, nil + }, +}, +``` +Common R/W method will then call the closures and let them do type specific work. +Similarly as with other dynamic sizes, the closure has to provide the way of the runtime calculation that can be done +after the call to `Common.ReadFrom()`. An example `HashList`: + +```go +{ + Size: func() uint64 { + size := uint64(binary.Size(uint16(0))) + for idx := range s.List { + size += s.List[idx].Common.TotalSize(&s.List[idx]) + } + return size +}, +``` + +- `ManifestFieldSubStruct` for fields that represent another type that implement `Structure` interface. An example of such case is the `KeySignature` type declared as: +```go +type KeySignature struct { + Common + Version uint8 `require:"0x10" json:"ksVersion,omitempty"` + Key Key `json:"ksKey"` + Signature Signature `json:"ksSignature"` +} +``` + +Effectively, in such case R/W and size/offsets of sub-types will be recursively determined using the common methods under the hood: +```go + { + ID: 1, + Name: "Key", + Size: func() uint64 { return s.Key.Common.TotalSize(&s.Key) }, + Value: func() any { return &s.Key }, + Type: ManifestFieldSubStruct, + }, + { + ID: 2, + Name: "Signature", + Size: func() uint64 { return s.Signature.Common.TotalSize(&s.Signature) }, + Value: func() any { return &s.Signature }, + Type: ManifestFieldSubStruct, + }, +``` +As implementing entity of a type that contains fields with sub-types, there is no need to concern about **how** sub-type will perform R/W and size/offset determination, as +long it is known that its layout is correctly defined. + +> [!NOTE] +> for all dynamic fields, keep `Size()` aligned with the exact binary representation consumed/written by that field type. + +### Field Type Quick Reference +As described above, `Common.ReadFrom()` and `Common.WriteTo()` dispatch behavior by `LayoutField.Type`: + +* `ManifestFieldEndValue`: plain fixed-size scalar value. +* `ManifestFieldArrayStatic`: fixed-size array. +* `ManifestFieldArrayDynamicWithSize`: dynamic byte array with externally defined size. +* `ManifestFieldArrayDynamicWithPrefix`: dynamic byte array with encoded size prefix. +* `ManifestFieldList`: custom list logic via `ReadList`/`WriteList`. +* `ManifestFieldSubStruct`: nested structure implementing `io.ReaderFrom`/`io.WriterTo`. + +### Adding a Structure +This will be showcased on imaginary structure, let's call it `X`. + +1. Declare the struct (in the example we will use all `ManifestFieldType` variants): +```go +// Represents X structure as defined in document #nnnnnn +type X struct { + Common + UUID [16]byte `json:"superUUIDforXstruct"` + Version uint8 `require:"0x32" json:"versionX"` + Signature Signature `json:"signatureX"` + HashList []HashStructure `json:"hlList"` + SizeOfData1 BitSize `json:"szData1X"` + Data1 []byte `json:"data1X"` + Data2 []byte `json:"data2X"` +} +``` + +2. Define `Layout()` in strict on-wire order and map each field to a `ManifestFieldType`: +```go +func (s *X) Layout() []LayoutField { + return []LayoutField{ + { + ID: 0, + Name: "UUID", + Size: func() uint64 { return 16 }, + Value: func() any { return &s.UUID }, + Type: ManifestFieldArrayStatic, + }, + { + ID: 1, + Name: "Version", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Version }, + Type: ManifestFieldEndValue, + }, + { + ID: 2, + Name: "Signature", + Size: func() uint64 { return s.Signature.Common.TotalSize(&s.Signature) }, + Value: func() any { return &s.Signature }, + Type: ManifestFieldSubStruct, + }, + { + ID: 3, + Name: fmt.Sprintf("Hash List: length %d", len(s.HashList)), + Size: func() uint64 { + size := uint64(binary.Size(uint16(0))) + for idx := range s.HashList { + size += s.HashList[idx].TotalSize() + } + return size + }, + Value: func() any { return &s.HashList }, + Type: ManifestFieldList, + ReadList: func(r io.Reader) (int64, error) { + var count uint16 + if err := binary.Read(r, endianess, &count); err != nil { + return 0, fmt.Errorf("unable to read count for field 'HashList': %w", err) + } + totalN := int64(binary.Size(count)) + s.HashList = make([]HashStructure, count) + for idx := range s.HashList { + n, err := s.HashList[idx].ReadFrom(r) + if err != nil { + return totalN, fmt.Errorf("unable to read field 'HashList[%d]': %w", idx, err) + } + totalN += n + } + return totalN, nil + }, + WriteList: func(w io.Writer) (int64, error) { + count := uint16(len(s.HashList)) + if err := binary.Write(w, endianess, &count); err != nil { + return 0, fmt.Errorf("unable to write count for field 'HashList': %w", err) + } + totalN := int64(binary.Size(count)) + for idx := range s.HashList { + n, err := s.HashList[idx].WriteTo(w) + if err != nil { + return totalN, fmt.Errorf("unable to write field 'HashList[%d]': %w", idx, err) + } + totalN += n + } + return totalN, nil + }, + }, + { + ID: 4, + Name: "SizeOfData1", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.SizeOfData1 }, + Type: ManifestFieldEndValue, + }, + { + ID: 5, + Name: "Data1", + Size: func() uint64 { return uint64(&s.SizeOfData1) }, + Value: func() any { return &s.Data1 }, + Type: ManifestFieldArrayDynamicWithSize, + }, + { + ID: 6, + Name: "Data2", + Size: func() uint64 { return uint64(binary.Size(uint16(0)) + len(s.Data2)) }, + Value: func() any { return &s.Data2 }, + Type: ManifestFieldArrayDynamicWithPrefix, + }, + } +} +``` + +3. Keep common methods delegated to `Common`: +```go +func (s *X) ReadFrom(r io.Reader) (int64, error) { return s.Common.ReadFrom(r, s) } +func (s *X) WriteTo(w io.Writer) (int64, error) { return s.Common.WriteTo(w, s) } +func (s *X) TotalSize() uint64 { return s.Common.TotalSize(s) } +func (s *X) SizeOf(id int) (uint64, error) { return s.Common.SizeOf(s, id) } +func (s *X) OffsetOf(id int) (uint64, error) { return s.Common.OffsetOf(s, id) } +func (s *X) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return s.Common.PrettyString(depth, withHeader, s, "X", opts...) +} +``` + +4. Implement `Validate()` and/or `Rehash()` if any values are derived from other fields, for example: +```go +func (s *X) Rehash() { + s.SizeOfData1 = BitSize(len(s.Data1)) +} + +func (s *X) Validate() error { + if int(s.SizeOfData1) != len(s.Data1) { + return fmt.Errorf("field 'SizeOfData1' expects %d, but has %d", len(s.Data1), s.SizeOfData1) + } + return nil +} +``` +If you need a completely new field behavior beyond existing `ManifestFieldType` values, +extend the `ManifestFieldType` constants and add corresponding handling in both +`Common.ReadFrom()` and `Common.WriteTo()`. + +### Extending a Structure +Let's take `SECBnT` as an example here, and assume that the update specification adds a field that stores the size of `IBBSegments`. Then we need to adapt the following: +1. Type definition +```go +type SECBnT struct { + cbnt.Common + cbnt.StructInfoCBNT `id:"__IBBS__" version:"0x20" var0:"0" var1:"uint16(s.TotalSize())"` + Reserved0 [1]byte `require:"0" json:"seReserved0,omitempty"` + SetNumber uint8 `require:"0" json:"seSetNumber,omitempty"` + Reserved1 [1]byte `require:"0" json:"seReserved1,omitempty"` + PBETValue PBETValue `json:"sePBETValue"` + Flags SEFlags `json:"seFlags"` + IBBMCHBAR uint64 `json:"seIBBMCHBAR"` + VTdBAR uint64 `json:"seVTdBAR"` + DMAProtBase0 uint32 `json:"seDMAProtBase0"` + DMAProtLimit0 uint32 `json:"seDMAProtLimit0"` + DMAProtBase1 uint64 `json:"seDMAProtBase1"` + DMAProtLimit1 uint64 `json:"seDMAProtLimit1"` + PostIBBHash cbnt.HashStructure `json:"sePostIBBHash"` + IBBEntryPoint uint32 `json:"seIBBEntry"` + DigestList cbnt.HashList `json:"seDigestList"` + OBBHash cbnt.HashStructure `json:"seOBBHash"` + Reserved2 [3]byte `require:"0" json:"seReserved2,omitempty"` + // NEW: size of IBBSegments + SizeOfIBBSeg [2]byte `json:"seSizeOfIBBSeg,omitemptu"` + IBBSegments []IBBSegment `countType:"uint8" json:"seIBBSegments,omitempty"` +} +``` + +2. Layout descriptor +```go +func (s *SECBnT) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return s.StructInfoCBNT.TotalSize() }, + Value: func() any { return &s.StructInfoCBNT }, + Type: cbnt.ManifestFieldSubStruct, + }, + ... + { + ID: 16, + Name: "Reserved 2", + Size: func() uint64 { return 3 }, + Value: func() any { return &s.Reserved2 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + // New entry + { + ID: 17, + Name: "Size of IBB Segments", + Size: func() uint64 { return 2 }, + Value: func() any { return s.IBBSegments.TotalSize() }, // Yes, this example makes little sense, but it is more about the mechanics of the approach than logics of specification. + Type: cbnt.ManifestFieldArrayDynamicWithSize, + } + { + ID: 18, // Incremented + Name: fmt.Sprintf("IBBSegments: Array of \"IBB Segments Element\" of length %d", len(s.IBBSegments)), + Size: func() uint64 { + ... + } +} +``` + +3. Any affected API calls + +`SizeOf` and `OffsetOf` methods depend on the ID of a field. Thus, after modifying the layout descriptor, these have to be adjusted. + -If you need to edit the template, please edit file: `./common/manifestcodegen/cmd/manifestcodegen/template_methods.tpl.go`. +## Testing -# Field tags +There are two types of tests used for the metadata related packages: -There are few special struct field tags which are recognized by the code -generator: -* `id` -- defines the element Structure ID string (for example `__TXTS__`). -* `version` -- defines the value of `StructVersion` (see document #575623). -* `countType` -- used only for slices and it defines which variable type is - used to store amount of items of the slice. Arrays in a structure in a Manifest - is almost always prepended with a count variable, and we automatically map - it to the real amount of elements of our slice. And to do that we need to know - the bitsize of the counter, therefore this tag exists. -* `countValue` -- (see also `countType`) sometimes a counter requires special - transformations before it could be maped into the real amount of elements - of a slice. `countValue` allows to define a function to calculate the - real count value. -* `require` -- defines the value required by the document #575623. -* `default` -- defines the default value. -* `prettyValue` -- defines the function which prints the value in a pretty format. -* `rehashValue` -- is used to receive an auto-updated value, for example it could - be handy to automatically update size-fields. +- Unit Tests: for the structures in the `cbnt` packages. +- Integration Tests: for manifests. These are further described in a dedicated [README](/pkg/intel/metadata/common/integration/README.md). -See also: +To run all the tests: +```bash +go test ./cbnt ``` -grep -RIn field.TagGet ./ -``` \ No newline at end of file diff --git a/pkg/intel/metadata/common/manifestcodegen/README.md b/pkg/intel/metadata/common/manifestcodegen/README.md new file mode 100644 index 00000000..9dd81b13 --- /dev/null +++ b/pkg/intel/metadata/common/manifestcodegen/README.md @@ -0,0 +1,63 @@ +## Manifestcodegen (DEPRECATED) + +This tool is deprecated, left here for reference. + +Prequesites: +Open another terminal and go get the sm2/sm3 crypto library into your gopath. +The code generator disables go modules. +``` +GOPATH=your/go/path go get github.com/tjfoc/gmsm/sm2 +``` + +To generalize all the logic related to Boot Policy Manifest and Key Manifest +we use code generation. Therefore it is enough to create structure declarations +and run command from this directory: +``` +go run ./../common/manifestcodegen/cmd/manifestcodegen/ . ./bootpolicy ./key +``` + +It will performe the code autogeneration in directories: +* Current directory (`.`), which contains common structures for different manifests; +* Boot Policy Manifest directory (`./bootpolicy`); +* and Key Manifest directory (`./key`). + +To check if the files are in the up-to-date state, one may add option `-check`: +``` +go run ./../common/manifestcodegen/cmd/manifestcodegen/ -check . ./bootpolicy ./key +``` + +Or if it is required to debug/trace the behavior of autogenerated code, one +may add option `-trace`: +``` +go run ./../common/manifestcodegen/cmd/manifestcodegen/ -trace . ./bootpolicy ./key +``` + +In this case the code will write a verbose log into stdout. + +If you need to edit the template, please edit file: `./common/manifestcodegen/cmd/manifestcodegen/template_methods.tpl.go`. + +# Field tags + +There are few special struct field tags which are recognized by the code +generator: +* `id` -- defines the element Structure ID string (for example `__TXTS__`). +* `version` -- defines the value of `StructVersion` (see document #575623). +* `countType` -- used only for slices and it defines which variable type is + used to store amount of items of the slice. Arrays in a structure in a Manifest + is almost always prepended with a count variable, and we automatically map + it to the real amount of elements of our slice. And to do that we need to know + the bitsize of the counter, therefore this tag exists. +* `countValue` -- (see also `countType`) sometimes a counter requires special + transformations before it could be maped into the real amount of elements + of a slice. `countValue` allows to define a function to calculate the + real count value. +* `require` -- defines the value required by the document #575623. +* `default` -- defines the default value. +* `prettyValue` -- defines the function which prints the value in a pretty format. +* `rehashValue` -- is used to receive an auto-updated value, for example it could + be handy to automatically update size-fields. + +See also: +``` +grep -RIn field.TagGet ./ +``` From 54e9245c9d0adc0b9bcccced0ccfaabe548854b8 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Wed, 15 Apr 2026 12:06:16 +0200 Subject: [PATCH 04/40] chore(intel/metadata): remove cbntbootpolicy pkg cbntbootpolicy and bgbootpolicy will be merged in the follow-up commits, thus bit of housekeeping here. Signed-off-by: Michal Gorlas --- .../metadata/cbnt/cbntbootpolicy/Reserved.go | 13 -- .../metadata/cbnt/cbntbootpolicy/bpmh.go | 47 ----- .../metadata/cbnt/cbntbootpolicy/manifest.go | 109 ----------- .../cbnt/cbntbootpolicy/manifest_nocodegen.go | 57 ------ .../cbnt/cbntbootpolicy/manifest_test.go | 15 -- pkg/intel/metadata/cbnt/cbntbootpolicy/pcd.go | 14 -- pkg/intel/metadata/cbnt/cbntbootpolicy/pm.go | 14 -- pkg/intel/metadata/cbnt/cbntbootpolicy/se.go | 176 ------------------ .../metadata/cbnt/cbntbootpolicy/signature.go | 17 -- .../cbnt/cbntbootpolicy/testdata/bpm.bin | Bin 973 -> 0 bytes pkg/intel/metadata/cbnt/cbntbootpolicy/txt.go | 52 ------ .../cbnt/cbntbootpolicy/txt_control_flags.go | 116 ------------ 12 files changed, 630 deletions(-) delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/Reserved.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/bpmh.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/manifest.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/manifest_nocodegen.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/manifest_test.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/pcd.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/pm.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/se.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/signature.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/testdata/bpm.bin delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/txt.go delete mode 100644 pkg/intel/metadata/cbnt/cbntbootpolicy/txt_control_flags.go diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/Reserved.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/Reserved.go deleted file mode 100644 index 7ce11f6f..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/Reserved.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package cbntbootpolicy - -// Reserved is reducted -type Reserved struct { - StructInfo `id:"__PFRS__" version:"0x21" var0:"0" var1:"uint16(s.TotalSize())"` - ReservedData [32]byte `json:"ReservedData"` -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/bpmh.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/bpmh.go deleted file mode 100644 index 291ab883..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/bpmh.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package cbntbootpolicy - -import ( - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" -) - -// BPMH is the header of boot policy manifest -type BPMH struct { - StructInfo `id:"__ACBP__" version:"0x23" var0:"0x20" var1:"uint16(s.TotalSize())"` - - KeySignatureOffset uint16 `json:"bpmhKeySignatureOffset"` - - BPMRevision uint8 `json:"bpmhRevision"` - - // BPMSVN is BPM security version number - // - // PrettyString: BPM SVN - BPMSVN cbnt.SVN `json:"bpmhSNV"` - - // ACMSVNAuth is authorized ACM security version number - // - // PrettyString: ACM SVN Auth - ACMSVNAuth cbnt.SVN `json:"bpmhACMSVN"` - - Reserved0 [1]byte `require:"0" json:"bpmhReserved0,omitempty"` - - NEMDataStack Size4K `json:"bpmhNEMStackSize"` -} - -// Size4K is a size in units of 4096 bytes. -type Size4K uint16 - -// InBytes returns the size in bytes. -func (s Size4K) InBytes() uint32 { - return uint32(s) * 4096 -} - -// NewSize4K returns the given size as multiple of 4K -func NewSize4K(size uint32) Size4K { - return Size4K(size / 4096) -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/manifest.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/manifest.go deleted file mode 100644 index d595c27f..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/manifest.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package cbntbootpolicy - -import ( - "bytes" - "fmt" - - pkgbytes "github.com/linuxboot/fiano/pkg/bytes" - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/linuxboot/fiano/pkg/uefi" -) - -// StructInfo is the common header of any element. -type StructInfo = cbnt.StructInfo - -// Manifest is a boot policy manifest -// -// PrettyString: Boot Policy Manifest -type Manifest struct { - // BPMH is the header of the boot policy manifest - // - // PrettyString: BPMH: Header - BPMH `rehashValue:"rehashedBPMH()" json:"bpmHeader"` - - SE []SE `json:"bpmSE"` - TXTE *TXT `json:"bpmTXTE,omitempty"` - Res *Reserved `json:"bpmReserved,omitempty"` - - // PCDE is the platform configuration data element - // - // PrettyString: PCDE: Platform Config Data - PCDE *PCD `json:"bpmPCDE,omitempty"` - - // PME is the platform manufacturer element - // - // PrettyString: PME: Platform Manufacturer - PME *PM `json:"bpmPME,omitempty"` - - // PMSE is the signature element - // - // PrettyString: PMSE: Signature - PMSE Signature `json:"bpmSignature"` -} - -// StructInfo is the information about how to parse the structure. -func (bpm Manifest) StructInfo() StructInfo { - return bpm.BPMH.StructInfo -} - -// ValidateIBB returns an error if IBB segments does not match the signature -func (bpm *Manifest) ValidateIBB(firmware uefi.Firmware) error { - if len(bpm.SE[0].DigestList.List) == 0 { - return fmt.Errorf("no IBB hashes") - } - - digest := bpm.SE[0].DigestList.List[0] // [0] instead of range -- is intentionally - - h, err := digest.HashAlg.Hash() - if err != nil { - return fmt.Errorf("invalid hash function: %v", digest.HashAlg) - } - - for _, _range := range bpm.IBBDataRanges(uint64(len(firmware.Buf()))) { - if _, err := h.Write(firmware.Buf()[_range.Offset:_range.End()]); err != nil { - return fmt.Errorf("unable to hash: %w", err) - } - } - hashValue := h.Sum(nil) - - if !bytes.Equal(hashValue, digest.HashBuffer) { - return fmt.Errorf("IBB %s hash mismatch: %X != %X", digest.HashAlg, hashValue, digest.HashBuffer) - } - - return nil -} - -// IBBDataRanges returns data ranges of IBB. -func (bpm *Manifest) IBBDataRanges(firmwareSize uint64) pkgbytes.Ranges { - var result pkgbytes.Ranges - - for _, seg := range bpm.SE[0].IBBSegments { - if seg.Flags&1 == 1 { - continue - } - startIdx := calculateOffsetFromPhysAddr(uint64(seg.Base), firmwareSize) - result = append(result, pkgbytes.Range{Offset: startIdx, Length: uint64(seg.Size)}) - } - - return result -} - -// calculateOffsetFromPhysAddr calculates the offset within an image -// of the physical address (address to a region mapped from -// the SPI chip). -// -// Examples: -// -// calculateOffsetFromPhysAddr(0xffffffff, 0x1000) == 0xfff -// calculateOffsetFromPhysAddr(0xffffffc0, 0x1000) == 0xfc0 -func calculateOffsetFromPhysAddr(physAddr uint64, imageSize uint64) uint64 { - const basePhysAddr = 1 << 32 // "4GiB" - startAddr := basePhysAddr - imageSize - return physAddr - startAddr -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/manifest_nocodegen.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/manifest_nocodegen.go deleted file mode 100644 index 271b7b70..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/manifest_nocodegen.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// -// To avoid errors "bpm.KeySignatureOffsetTotalSize undefined" and -// "bpm.BPMH.PrettyString undefined" we place these functions to a file -// with a build tag "!manifestcodegen" - -package cbntbootpolicy - -import ( - "fmt" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -func (bpm *Manifest) rehashedBPMH() BPMH { - bpmh := bpm.BPMH - bpmh.KeySignatureOffset = uint16(bpm.PMSEOffset() + bpm.PMSE.KeySignatureOffset()) - return bpmh -} - -// Print prints the Manifest -func (bpm Manifest) Print() { - fmt.Printf("%v", bpm.BPMH.PrettyString(1, true)) - for _, item := range bpm.SE { - fmt.Printf("%v", item.PrettyString(1, true)) - } - if bpm.TXTE != nil { - fmt.Printf("%v\n", bpm.TXTE.PrettyString(1, true)) - } else { - fmt.Printf(" --TXTE--\n\t not set!(optional)\n") - } - - if bpm.PCDE != nil { - fmt.Printf("%v\n", bpm.PCDE.PrettyString(1, true)) - } else { - fmt.Println(" --PCDE-- \n\tnot set!(optional)") - } - - if bpm.PME != nil { - fmt.Printf("%v\n", bpm.PME.PrettyString(1, true)) - } else { - fmt.Println(" --PME--\n\tnot set!(optional)") - } - - if bpm.PMSE.Signature.DataTotalSize() < 1 { - fmt.Printf("%v\n", bpm.PMSE.PrettyString(1, true, pretty.OptionOmitKeySignature(true))) - fmt.Printf(" --PMSE--\n\tBoot Policy Manifest not signed!\n\n") - } else { - fmt.Printf("%v\n", bpm.PMSE.PrettyString(1, true, pretty.OptionOmitKeySignature(false))) - } -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/manifest_test.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/manifest_test.go deleted file mode 100644 index 0b7de9a1..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/manifest_test.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cbntbootpolicy - -import ( - "testing" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/unittest" -) - -func TestReadWrite(t *testing.T) { - unittest.CBNTManifestReadWrite(t, &Manifest{}, "testdata/bpm.bin") -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/pcd.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/pcd.go deleted file mode 100644 index 466812b7..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/pcd.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package cbntbootpolicy - -// PCD holds various Platform Config Data. -type PCD struct { - StructInfo `id:"__PCDS__" version:"0x20" var0:"0" var1:"uint16(s.TotalSize())"` - Reserved0 [2]byte `json:"pcdReserved0,omitempty"` - Data []byte `json:"pcdData"` -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/pm.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/pm.go deleted file mode 100644 index 4e339ce5..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/pm.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package cbntbootpolicy - -// PM is the platform manufacturer data element -type PM struct { - StructInfo `id:"__PMDA__" version:"0x20" var0:"0" var1:"uint16(s.TotalSize())"` - Reserved0 [2]byte `require:"0" json:"pcReserved0,omitempty"` - Data []byte `json:"pcData"` -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/se.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/se.go deleted file mode 100644 index 5e122c62..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/se.go +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package cbntbootpolicy - -import ( - "fmt" - "math" - "time" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" -) - -// SE is an IBB segments element -// -// PrettyString: IBB Segments Element -type SE struct { - StructInfo `id:"__IBBS__" version:"0x20" var0:"0" var1:"uint16(s.TotalSize())"` - Reserved0 [1]byte `require:"0" json:"seReserved0,omitempty"` - SetNumber uint8 `require:"0" json:"seSetNumber,omitempty"` - Reserved1 [1]byte `require:"0" json:"seReserved1,omitempty"` - PBETValue PBETValue `json:"sePBETValue"` - Flags SEFlags `json:"seFlags"` - - // IBBMCHBAR - // PrettyString: IBB MCHBAR - IBBMCHBAR uint64 `json:"seIBBMCHBAR"` - - // VTdBAR - // PrettyString: VT-d BAR - VTdBAR uint64 `json:"seVTdBAR"` - - // DMAProtBase0 - // PrettyString: DMA Protection 0 Base Address - DMAProtBase0 uint32 `json:"seDMAProtBase0"` - - // DMAProtLimit0 - // PrettyString: DMA Protection 0 Limit Address - DMAProtLimit0 uint32 `json:"seDMAProtLimit0"` - - // DMAProtBase1 - // PrettyString: DMA Protection 1 Base Address - DMAProtBase1 uint64 `json:"seDMAProtBase1"` - - // DMAProtLimit1 - // PrettyString: DMA Protection 2 Limit Address - DMAProtLimit1 uint64 `json:"seDMAProtLimit1"` - - PostIBBHash cbnt.HashStructure `json:"sePostIBBHash"` - - IBBEntryPoint uint32 `json:"seIBBEntry"` - - DigestList cbnt.HashList `json:"seDigestList"` - - OBBHash cbnt.HashStructure `json:"seOBBHash"` - - Reserved2 [3]byte `require:"0" json:"seReserved2,omitempty"` - - IBBSegments []IBBSegment `countType:"uint8" json:"seIBBSegments,omitempty"` -} - -// PBETValue -type PBETValue uint8 - -// PBETValue returns the raw value of the timer setting. -func (pbet PBETValue) PBETValue() uint8 { - return uint8(pbet) & 0x0f -} - -// Duration returns the value as time.Duration. -func (pbet PBETValue) Duration() time.Duration { - v := pbet.PBETValue() - if v == 0 { - return math.MaxInt64 - } - return time.Second * time.Duration(5+v) -} - -// SetDuration sets the value using standard time.Duration as the input. -func (pbet *PBETValue) SetDuration(duration time.Duration) time.Duration { - v := duration.Nanoseconds()/time.Second.Nanoseconds() - 5 - if v <= 0 { - v = 1 - } - if v >= 16 { - v = 0 - } - *pbet = PBETValue(v) - - return pbet.Duration() -} - -// SEFlags -type SEFlags uint32 - -// Reserved0 -func (flags SEFlags) Reserved0() uint32 { - return uint32(flags & 0xffffffe0) -} - -// SupportsTopSwapRemediation -// -// PrettyString-true: BIOS supports Top Swap remediation action -// PrettyString-false: BIOS does not support Top Swap remediation action -func (flags SEFlags) SupportsTopSwapRemediation() bool { - return flags&0x10 != 0 -} - -// TPMFailureLeavesHierarchiesEnabled -// -// PrettyString-true: Leave Hierarchies enabled. Cap all PCRs on failure. -// PrettyString-false: Do not leave enabled. Disable all Hierarchies or deactivate on failure. -func (flags SEFlags) TPMFailureLeavesHierarchiesEnabled() bool { - return flags&0x08 != 0 -} - -// AuthorityMeasure -// -// PrettyString-true: Extend Authority Measurements into the Authority PCR 7 -// PrettyString-false: Do not extend into the Authority PCR 7 -func (flags SEFlags) AuthorityMeasure() bool { - return flags&0x04 != 0 -} - -// Locality3Startup -// -// PrettyString-true: Issue TPM Start-up from Locality 3 -// PrettyString-false: Disabled -func (flags SEFlags) Locality3Startup() bool { - return flags&0x02 != 0 -} - -// DMAProtection -// -// PrettyString-true: Enable DMA Protection -// PrettyString-false: Disable DMA Protection -func (flags SEFlags) DMAProtection() bool { - return flags&0x01 != 0 -} - -// IBBSegment defines a single IBB segment -type IBBSegment struct { - Reserved [2]byte `require:"0" json:"ibbSegReserved"` - Flags uint16 `json:"ibbSegFlags"` - Base uint32 `json:"ibbSegBase"` - Size uint32 `json:"ibbSegSize"` -} - -// CachingType -type CachingType uint8 - -// -const ( - CachingTypeWriteProtect = CachingType(iota) - CachingTypeWriteBack - CachingTypeReserved0 - CachingTypeReserved1 -) - -// String implements fmt.Stringer. -func (c CachingType) String() string { - switch c { - case CachingTypeWriteProtect: - return "write_protect" - case CachingTypeWriteBack: - return "write_back" - case CachingTypeReserved0: - return "value_0x02" - case CachingTypeReserved1: - return "value_0x03" - } - return fmt.Sprintf("unexpected_value_0x%02X", uint8(c)) -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/signature.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/signature.go deleted file mode 100644 index 8c15c8c3..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/signature.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package cbntbootpolicy - -import ( - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" -) - -// Signature contains the signature of the BPM. -type Signature struct { - StructInfo `id:"__PMSG__" version:"0x20" var0:"0" var1:"0"` - cbnt.KeySignature `json:"sigKeySignature"` -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/testdata/bpm.bin b/pkg/intel/metadata/cbnt/cbntbootpolicy/testdata/bpm.bin deleted file mode 100644 index a659255aecf5529d37d156fa92e6aadc796b15c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 973 zcma!#cXW0Nh>urN5MkKE$jHFN(7+fU@9E?e93QX1Ai~JNz`)NABrt&hQ0N1)Fi0%} zSoHt@|1%g^7`Pb}7a!jP}~m@@jWND@-P@MoPPSgDoFg~w94bNE(Xt5P&s-^B3-}e+TEV* zD%r2zeLdD>yRoaf@!xOvC(37xG;JA$fcC9F)6Tz$C!lhw=kzJ&ay_b#mmBggS7JEG zX+E=fopOdN$bCS-0-+B4Z&<4jW*#X0@ZSL<$iPth;eP{^-OvhTSMf8%$A?6OfWt%s zri#Iap{|~R70mqyH4vySz%2-?x45n_g#Pry2k!k~db2-BcxO(*`A`%a9U_j!2C3~PEJO>Z@JFN8uw4$>j^A9`u6GO zsu^C_3k3B<3|2FIsZM#n{7d(gNsqMhvYhjCS#CZOuT1xR^1<<{llz8~)34h3eVuIl zSdQV}MvFb&e%teMTlUZV z{uZ?Hh6pGixETcgrM0IwMjqLnbj`lrSS-aseXYmLvg6)6UQAJ#yRE&~|KhZQi0f<{ zoq>!uQ+CZRBOw^P5D|^ z3LUN)Ecn{pb4GOg*>Y{4XE_diJ}fhBm94*gKEgcluM&dr|-Z diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/txt.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/txt.go deleted file mode 100644 index 7c9c1be0..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/txt.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package cbntbootpolicy - -import ( - "fmt" - "time" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" -) - -// TXT is the TXT element -type TXT struct { - StructInfo `id:"__TXTS__" version:"0x21" var0:"0" var1:"uint16(s.TotalSize())"` - Reserved0 [1]byte `require:"0" json:"txtReserved0,omitempty"` - SetNumber [1]byte `require:"0" json:"txtSetNumer,omitempty"` - SInitMinSVNAuth uint8 `default:"0" json:"txtSVN"` - Reserved1 [1]byte `require:"0" json:"txtReserved1,omitempty"` - ControlFlags TXTControlFlags `json:"txtFlags"` - PwrDownInterval Duration16In5Sec `json:"txtPwrDownInterval"` - // PrettyString: PTT CMOS Offset 0 - PTTCMOSOffset0 uint8 `default:"126" json:"txtPTTCMOSOffset0"` - // PrettyString: PTT CMOS Offset 1 - PTTCMOSOffset1 uint8 `default:"127" json:"txtPTTCMOSOffset1"` - ACPIBaseOffset uint16 `default:"0x400" json:"txtACPIBaseOffset,omitempty"` - Reserved2 [2]byte `json:"txtReserved2,omitempty"` - // PrettyString: ACPI MMIO Offset - PwrMBaseOffset uint32 `default:"0xFE000000" json:"txtPwrMBaseOffset,omitempty"` - DigestList cbnt.HashList `json:"txtDigestList"` - Reserved3 [3]byte `require:"0" json:"txtReserved3,omitempty"` - - SegmentCount uint8 `require:"0" json:"txtSegmentCount,omitempty"` -} - -// Duration16In5Sec exports the custom type Duration16In5Sec -type Duration16In5Sec uint16 - -// Duration calculates a given time in multiple of 5 seconds. -func (d Duration16In5Sec) Duration() time.Duration { - return time.Second * 5 * time.Duration(d) -} - -func (d Duration16In5Sec) String() string { - if d == 0 { - return "0 (infinite)" - } - return fmt.Sprintf("%d (%s)", d, d.Duration().String()) -} diff --git a/pkg/intel/metadata/cbnt/cbntbootpolicy/txt_control_flags.go b/pkg/intel/metadata/cbnt/cbntbootpolicy/txt_control_flags.go deleted file mode 100644 index 448a0ffd..00000000 --- a/pkg/intel/metadata/cbnt/cbntbootpolicy/txt_control_flags.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package cbntbootpolicy - -import ( - "fmt" -) - -type TXTControlFlags uint32 - -func (flags TXTControlFlags) ExecutionProfile() ExecutionProfile { - return ExecutionProfile(flags & 0x1f) -} - -type ExecutionProfile uint8 - -const ( - ExecutionProfileA = ExecutionProfile(iota) - ExecutionProfileB - ExecutionProfileC -) - -// String just implements fmt.Stringer. -func (p ExecutionProfile) String() string { - switch p { - case ExecutionProfileA: - return `A (use default selection based on differentation between clients, UP, and MP servers)` - case ExecutionProfileB: - return `B (use "Server model": rely on BIOS to configure topoligy; do not use ACHECK)` - case ExecutionProfileC: - return `C (use "Client model": do not measure BIOS into D-PCRs; use ACHECK-based alias check)` - } - return fmt.Sprintf("unexpected_execution_profile_value_0x%02X", uint8(p)) -} - -func (flags TXTControlFlags) MemoryScrubbingPolicy() MemoryScrubbingPolicy { - return MemoryScrubbingPolicy((flags >> 5) & 0x3) -} - -type MemoryScrubbingPolicy uint8 - -const ( - MemoryScrubbingPolicyDefault = MemoryScrubbingPolicy(iota) - MemoryScrubbingPolicyBIOS - MemoryScrubbingPolicySACM -) - -// String implements fmt.Stringer. -func (policy MemoryScrubbingPolicy) String() string { - switch policy { - case MemoryScrubbingPolicyDefault: - return "BIOS if verified or backup action othersize" - case MemoryScrubbingPolicyBIOS: - return "BIOS" - case MemoryScrubbingPolicySACM: - return "S-ACM" - } - return fmt.Sprintf("unexpected_value_0x%02X", uint8(policy)) -} - -func (flags TXTControlFlags) BackupActionPolicy() BackupActionPolicy { - return BackupActionPolicy((flags >> 7) & 0x3) -} - -type BackupActionPolicy uint8 - -const ( - BackupActionPolicyDefault = BackupActionPolicy(iota) - BackupActionPolicyForceMemoryPowerDown - BackupActionPolicyForceBtGUnbreakableShutdown -) - -// String implements fmt.Stringer. -func (policy BackupActionPolicy) String() string { - switch policy { - case BackupActionPolicyDefault: - return "memory power down if profile D or BtG unbreakable shutdown otherwise" - case BackupActionPolicyForceMemoryPowerDown: - return "memory power down" - case BackupActionPolicyForceBtGUnbreakableShutdown: - return "BtG unbreakable shutdown" - } - return fmt.Sprintf("unexpected_value_0x%02X", uint8(policy)) -} - -// PrettyString-true: Default setting. S-ACM is requested to extend static PCRs -// PrettyString-false: S-ACM is not requested to extend static PCRs -func (flags TXTControlFlags) IsSACMRequestedToExtendStaticPCRs() bool { - return (flags>>9)&0x01 == 0 -} - -func (flags TXTControlFlags) ResetAUXControl() ResetAUXControl { - return ResetAUXControl((flags >> 31) & 0x01) -} - -type ResetAUXControl uint8 - -const ( - ResetAUXControlResetAUXIndex = ResetAUXControl(iota) - ResetAUXControlDeleteAUXIndex -) - -// String implements fmt.Stringer. -func (c ResetAUXControl) String() string { - switch c { - case ResetAUXControlResetAUXIndex: - return "AUX reset leaf will reset AUX index" - case ResetAUXControlDeleteAUXIndex: - return "AUX reset leaf will delete AUX index" - } - return fmt.Sprintf("unexpected_value_0x%02X", uint8(c)) -} From 535d7fdd2f681a08d39614bed79b0dda8d93ad80 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Wed, 15 Apr 2026 12:47:07 +0200 Subject: [PATCH 05/40] chore(intel/metadata): remove cbntkey pkg same reason as with cbntbootpolicy removal Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/cbntkey/hash.go | 98 ----------------- pkg/intel/metadata/cbnt/cbntkey/manifest.go | 103 ------------------ .../cbnt/cbntkey/manifest_nocodegen.go | 28 ----- .../metadata/cbnt/cbntkey/manifest_test.go | 15 --- .../metadata/cbnt/cbntkey/testdata/km.bin | Bin 641 -> 0 bytes 5 files changed, 244 deletions(-) delete mode 100644 pkg/intel/metadata/cbnt/cbntkey/hash.go delete mode 100644 pkg/intel/metadata/cbnt/cbntkey/manifest.go delete mode 100644 pkg/intel/metadata/cbnt/cbntkey/manifest_nocodegen.go delete mode 100644 pkg/intel/metadata/cbnt/cbntkey/manifest_test.go delete mode 100644 pkg/intel/metadata/cbnt/cbntkey/testdata/km.bin diff --git a/pkg/intel/metadata/cbnt/cbntkey/hash.go b/pkg/intel/metadata/cbnt/cbntkey/hash.go deleted file mode 100644 index 477919ab..00000000 --- a/pkg/intel/metadata/cbnt/cbntkey/hash.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package cbntkey - -import ( - "fmt" - "strings" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" -) - -// Hash is "KM hash Structure" defined in document #575623. -type Hash struct { - // Usage is the digest usage bitmask. - // - // More than one bit can be set to indicate shared digest usage. - // Usage of bit 0 is normative; other usages are informative. - Usage Usage `json:"hashUsage"` - - // Digest is the actual digest. - Digest cbnt.HashStructure `json:"hashStruct"` -} - -// Usage is the digest usage bitmask. -// -// More than one bit can be set to indicate shared digest usage. -// Usage of bit 0 is normative; other usages are informative. -type Usage uint64 - -const ( - // UsageBPMSigningPKD is the bit meaning the digest could be used as - // Boot Policy Manifest signing pubkey digest. - UsageBPMSigningPKD = Usage(1 << iota) - - // UsageFITPatchManifestSigningPKD is the bit meaning the digest could be used as - // FIT Patch Manifest signing pubkey digest. - UsageFITPatchManifestSigningPKD - - // UsageACMManifestSigningPKD is the bit meaning the digest could be used as - // ACM Manifest signing pubkey digest. - UsageACMManifestSigningPKD - - // UsageSDEVSigningPKD is the bit meaning the digest could be used as - // SDEV signing pubkey digest. - UsageSDEVSigningPKD - - // UsageReserved is a reserved bit - UsageReserved -) - -// String implements fmt.Stringer. -func (u Usage) String() string { - var result []string - for i := uint(0); i < 64; i++ { - f := Usage(1 << i) - if !u.IsSet(f) { - continue - } - var descr string - switch f { - case UsageBPMSigningPKD: - descr = "BPM_signing_pubkey_digest" - case UsageFITPatchManifestSigningPKD: - descr = "FIT_patch_manifest_signing_pubkey_digest" - case UsageACMManifestSigningPKD: - descr = "ACM_manifest_signing_pubkey_digest" - case UsageSDEVSigningPKD: - descr = "SDEV_signing_pubkey_digest" - case UsageReserved: - descr = "Reserved" - default: - descr = fmt.Sprintf("unexpected_bit_%d", i) - } - result = append(result, descr) - } - - return strings.Join(result, ",") -} - -// IsSet returns true if bits `f` are set in bitmask `u`. -func (u Usage) IsSet(f Usage) bool { - return u&f != 0 -} - -// Set sets/unsets the bits of `f` in bitmask `u`. -// -// To set the bits `v` should be true, to unset -- false. -func (u *Usage) Set(f Usage, v bool) { - if v { - *u |= f - } else { - *u &= ^f - } -} diff --git a/pkg/intel/metadata/cbnt/cbntkey/manifest.go b/pkg/intel/metadata/cbnt/cbntkey/manifest.go deleted file mode 100644 index 7b76ba82..00000000 --- a/pkg/intel/metadata/cbnt/cbntkey/manifest.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate manifestcodegen - -package cbntkey - -import ( - "bytes" - "crypto" - "fmt" - - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" -) - -// PrettyString: CBnT Key Manifest -type Manifest struct { - cbnt.StructInfo `id:"__KEYM__" version:"0x21" var0:"0" var1:"0"` - - // KeyManifestSignatureOffset is Key Manifest KeySignature offset. - // - // The original name is "KeySignatureOffset" (in #575623). - KeyManifestSignatureOffset uint16 `rehashValue:"KeyAndSignatureOffset()" json:"kmSigOffset,omitempty"` - - // Reserved2 is an alignment. - Reserved2 [3]byte `json:"kmReserved2,omitempty"` - - // Revision is the revision of the Key Manifest defined by the Platform - // Manufacturer. - Revision uint8 `json:"kmRevision"` - - // KMSVN is the Key Manifest Security Version Number. - KMSVN cbnt.SVN `json:"kmSVN"` - - // KMID is the Key Manifest Identifier. - KMID uint8 `json:"kmID"` - - // PubKeyHashAlg is the hash algorithm of OEM public key digest programmed - // into the FPF. - PubKeyHashAlg cbnt.Algorithm `json:"kmPubKeyHashAlg"` - - // Hash is the slice of KMHASH_STRUCT (KHS) structures (see table 5-3 - // of the document #575623). Describes BPM pubkey digest (among other). - Hash []Hash `json:"kmHash"` - - // KeyAndSignature is the Key Manifest signature. - KeyAndSignature cbnt.KeySignature `json:"kmKeySignature"` -} - -func (m *Manifest) SetSignature( - algo cbnt.Algorithm, - hashAlgo cbnt.Algorithm, - privKey crypto.Signer, - signedData []byte, -) error { - err := m.KeyAndSignature.SetSignature(algo, hashAlgo, privKey, signedData) - if err != nil { - return fmt.Errorf("unable to set the signature: %w", err) - } - m.PubKeyHashAlg = m.KeyAndSignature.Signature.HashAlg - - return nil -} - -func (m *Manifest) ValidateBPMKey(bpmKS cbnt.KeySignature) error { - hashCount := 0 - for _, hashEntry := range m.Hash { - if !hashEntry.Usage.IsSet(UsageBPMSigningPKD) { - continue - } - - h, err := hashEntry.Digest.HashAlg.Hash() - if err != nil { - return fmt.Errorf("invalid hash algo %v: %w", hashEntry.Digest.HashAlg, err) - } - - if len(hashEntry.Digest.HashBuffer) != h.Size() { - return fmt.Errorf("invalid hash lenght: actual:%d expected:%d", len(hashEntry.Digest.HashBuffer), h.Size()) - } - - switch bpmKS.Key.KeyAlg { - case cbnt.AlgRSA: - if _, err := h.Write(bpmKS.Key.Data[4:]); err != nil { - return fmt.Errorf("unable to hash: %w", err) - } - default: - return fmt.Errorf("unsupported key algorithm: %v", bpmKS.Key.KeyAlg) - } - digest := h.Sum(nil) - - if !bytes.Equal(hashEntry.Digest.HashBuffer, digest) { - return fmt.Errorf("BPM key hash does not match the one in KM: actual:%X != in-KM:%X (hash algo: %v)", digest, hashEntry.Digest.HashBuffer, hashEntry.Digest.HashAlg) - } - hashCount++ - } - - if hashCount == 0 { - return fmt.Errorf("no hash of BPM's key was found in KM") - } - - return nil -} diff --git a/pkg/intel/metadata/cbnt/cbntkey/manifest_nocodegen.go b/pkg/intel/metadata/cbnt/cbntkey/manifest_nocodegen.go deleted file mode 100644 index d3746d81..00000000 --- a/pkg/intel/metadata/cbnt/cbntkey/manifest_nocodegen.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// -// To avoid error "m.StructInfo.PrettyString undefined" we place this -// function to a file with a build tag "!manifestcodegen" - -package cbntkey - -import ( - "fmt" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" -) - -// Print prints the Key Manifest. -func (m *Manifest) Print() { - if m.KeyAndSignature.Signature.DataTotalSize() < 1 { - fmt.Printf("%v\n", m.PrettyString(1, true, pretty.OptionOmitKeySignature(true))) - fmt.Printf(" --KeyAndSignature--\n\tKey Manifest not signed!\n\n") - } else { - fmt.Printf("%v\n", m.PrettyString(1, true, pretty.OptionOmitKeySignature(false))) - } -} diff --git a/pkg/intel/metadata/cbnt/cbntkey/manifest_test.go b/pkg/intel/metadata/cbnt/cbntkey/manifest_test.go deleted file mode 100644 index 5b367c19..00000000 --- a/pkg/intel/metadata/cbnt/cbntkey/manifest_test.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cbntkey - -import ( - "testing" - - "github.com/linuxboot/fiano/pkg/intel/metadata/common/unittest" -) - -func TestReadWrite(t *testing.T) { - unittest.CBNTManifestReadWrite(t, &Manifest{}, "testdata/km.bin") -} diff --git a/pkg/intel/metadata/cbnt/cbntkey/testdata/km.bin b/pkg/intel/metadata/cbnt/cbntkey/testdata/km.bin deleted file mode 100644 index 805f488d876cfc667b83f9fd31aae31c1b13b660..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 641 zcmV-{0)G8pUrR+XPJV5KqrT#5N>l20RRvH2mt^A0C&#OXm=9|ncNB@$T+xej))L?#nz(!)xUbn zI^)QmVjZ{Jbb~bvsfka4$BELUmz|U0tW#^xa4I349huIUHbB4+#LbWc{Cb6ih3ODJ z8P|c*Oc8k5H~++`=^%Sd$>mD}EsA5fIvpvuZ7WtbU&6(pBHnpjT)Dw0wjKHC$9E++ z@tE>np|wgz7D$hK4Y$E2NVzqwu1;Mm#A>~Fq|Rc12`xcm9-=%(mrr3 zG-o)iEO00;{JH=mU|)%oStE{6qOO}=bLyWJC9Q1~_J zEVokAb#h@NT3QCzEaDLF9-=lMZ|W(*(nJjc=Ijdem!edp(+3YC*>5e z$s#bU=>e~mh^4*y{x}Hi_1qL2=}GXcYp`BtV^Tw!4dlF6>kTZ>Xa?#{4P~el_FTwm z69T~WMrACn86-a%YE Date: Wed, 15 Apr 2026 13:32:39 +0200 Subject: [PATCH 06/40] chore(intel/metadata): move consts and interfaces to dedicated files types.go is basically for interfaces definition that do not belong to one type but is rather implemented by remaining types. Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/config.go | 20 ------- pkg/intel/metadata/cbnt/consts.go | 91 +++++++++++++++++++++++++++++++ pkg/intel/metadata/cbnt/types.go | 61 +++++++++++++++++++++ 3 files changed, 152 insertions(+), 20 deletions(-) delete mode 100644 pkg/intel/metadata/cbnt/config.go create mode 100644 pkg/intel/metadata/cbnt/consts.go create mode 100644 pkg/intel/metadata/cbnt/types.go diff --git a/pkg/intel/metadata/cbnt/config.go b/pkg/intel/metadata/cbnt/config.go deleted file mode 100644 index 78db7115..00000000 --- a/pkg/intel/metadata/cbnt/config.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cbnt - -var ( - // StrictOrderCheck defines if elements order checks should be performed. - // For example in the Boot Policy Manifest elements could be in a wrong - // order. And we still can parse it, but in this way `*Offset` methods - // could be confusing, since they will show the offset as they will - // be written (not as they were parsed). - // - // We require a strict order because it is explicitly required - // in the documentation #575623: - // - // > The order of the elements and the order of the fields within each - // > element are architectural and must be followed. - StrictOrderCheck = true -) diff --git a/pkg/intel/metadata/cbnt/consts.go b/pkg/intel/metadata/cbnt/consts.go new file mode 100644 index 00000000..ae5d61f6 --- /dev/null +++ b/pkg/intel/metadata/cbnt/consts.go @@ -0,0 +1,91 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +const ( + // BasePhysAddr is the absolute physical address where the firmware image ends. + // + // See Figure 2.1 in https://www.intel.com/content/dam/www/public/us/en/documents/guides/fit-bios-specification.pdf + // + // Note: A firmware image grows towards lower addresses. So an image will be mapped to addresses: + // [ BasePhysAddr-length .. BasePhysAddr ) + // + // Note: SPI chip is mapped into this region. So we actually work directly with data of the SPI chip + // + // See also CalculatePhysAddrOfOffset(). + BasePhysAddr = 1 << 32 // "4GB" + + // FITPointerOffset is the offset of the physical address of the FIT pointer. + // See Section 3.1 in "Firmware Interface Table" specification: + // * https://www.intel.com/content/dam/www/public/us/en/documents/guides/fit-bios-specification.pdf + FITPointerOffset = 0x40 + + // FITPointerPhysAddr is the physical address of the FIT pointer. + // See "1 Firmware Interface Table" in "Firmware Interface Table" specification: + // * https://www.intel.com/content/dam/www/public/us/en/documents/guides/fit-bios-specification.pdf + FITPointerPhysAddr = BasePhysAddr - FITPointerOffset + + // FITPointerSize is the size of the FIT pointer. + // It is suggested to be 0x10 bytes because of "Figure 2-1" of the specification. + FITPointerSize = 0x10 + + // FITHeadersMagic is the magic string, expected in the beginning of the + // first FIT entry + FITHeadersMagic = "_FIT_ " + + Version10 BootGuardVersion = 1 + Version20 BootGuardVersion = 2 + Version21 BootGuardVersion = 3 + + // Supported algorithms, note that these are supported by both BG and CBnT, though + // BG uses onlt few of them + AlgUnknown Algorithm = 0x0000 + AlgRSA Algorithm = 0x0001 + AlgSHA1 Algorithm = 0x0004 + AlgSHA256 Algorithm = 0x000B + AlgSHA384 Algorithm = 0x000C + AlgSHA512 Algorithm = 0x000D + AlgNull Algorithm = 0x0010 + AlgSM3 Algorithm = 0x0012 + AlgRSASSA Algorithm = 0x0014 + AlgRSAPSS Algorithm = 0x0016 + AlgECDSA Algorithm = 0x0018 + AlgSM2 Algorithm = 0x001b + AlgECC Algorithm = 0x0023 + + // Possible values of TPM2PCRExtendPolicySupport + TPM2PCRExtendIllegal TPM2PCRExtendPolicySupport = 0 + TPM2PCRExtendMaximumAgilityPolicy TPM2PCRExtendPolicySupport = 1 + TPM2PCRExtendMaximumPerformancePolicy TPM2PCRExtendPolicySupport = 2 + TPM2PCRExtendBothPolicies TPM2PCRExtendPolicySupport = 3 + + // Possible types of Manifest fields. Refer to pkg/intel/metadata/README.md + // for detailed desription of the meaning and usage of these. + ManifestFieldEndValue ManifestFieldType = "endValue" + ManifestFieldArrayStatic ManifestFieldType = "arrayStatic" + ManifestFieldArrayDynamicWithSize ManifestFieldType = "arrayDynamicWithSize" + ManifestFieldArrayDynamicWithPrefix ManifestFieldType = "arrayDynamicWithPrefix" + ManifestFieldList ManifestFieldType = "list" + ManifestFieldSubStruct ManifestFieldType = "subStruct" + + // StructureIDManifest is the StructureID (in terms of + // the document #575623) of element 'Manifest'. + StructureIDManifest = "__KEYM__" +) + +var ( + // StrictOrderCheck defines if elements order checks should be performed. + // For example in the Boot Policy Manifest elements could be in a wrong + // order. And we still can parse it, but in this way `*Offset` methods + // could be confusing, since they will show the offset as they will + // be written (not as they were parsed). + // + // We require a strict order because it is explicitly required + // in the documentation #575623: + // + // > The order of the elements and the order of the fields within each + // > element are architectural and must be followed. + StrictOrderCheck = true +) diff --git a/pkg/intel/metadata/cbnt/types.go b/pkg/intel/metadata/cbnt/types.go new file mode 100644 index 00000000..003f236f --- /dev/null +++ b/pkg/intel/metadata/cbnt/types.go @@ -0,0 +1,61 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "io" + + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) + +// All custom types definitions for the metadata pkg that are shared +// and/or duplicated (for e.g. used both in bg and cbnt packages wo. +// any modifications) +type ( + ManifestFieldType string + + LayoutField struct { + ID int + Name string + Size func() uint64 + Value func() any + Type ManifestFieldType + // optional list reader onluy to be used for types that contain + // ManifestFieldList + ReadList func(r io.Reader) (int64, error) + // optional list writer to be used for types that contain + // ManifestFieldList + WriteList func(w io.Writer) (int64, error) + } + + // Structure is an abstraction of a structure of a manifest. + Structure interface { + io.ReaderFrom + io.WriterTo + TotalSize() uint64 + SizeOf(id int) (uint64, error) + OffsetOf(id int) (uint64, error) + Layout() []LayoutField + Validate() error + // PrettyString returns the whole object as a structured string. + PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string + } + + // Element is an abstraction of an element of a manifest. + Element interface { + Structure + GetStructInfo() StructInfo + SetStructInfo(StructInfo) + } + + Manifest interface { + Structure + } + + // StructureList is an abstraction of slice of Structures + StructureList interface { + Structures() []Structure + } +) From d92fc4aafe3b8f60462ef15a11bb62688ff20537 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Wed, 15 Apr 2026 13:53:46 +0200 Subject: [PATCH 07/40] feat(intel/metadata): recognize header version > 0x21 as Version21 Move bgheader.go to cbnt package since it is no longer reused by two separate packages (bg and cbnt as before). Recognize Header version > 0x21 is as CBnT 2.1 (Version21) after Table 5-16 in #575623-1.2.9. Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/revision.go | 53 +++++++ pkg/intel/metadata/cbnt/revision_test.go | 133 ++++++++++++++++++ .../metadata/common/bgheader/bgheader.go | 58 -------- 3 files changed, 186 insertions(+), 58 deletions(-) create mode 100644 pkg/intel/metadata/cbnt/revision.go create mode 100644 pkg/intel/metadata/cbnt/revision_test.go delete mode 100644 pkg/intel/metadata/common/bgheader/bgheader.go diff --git a/pkg/intel/metadata/cbnt/revision.go b/pkg/intel/metadata/cbnt/revision.go new file mode 100644 index 00000000..26558512 --- /dev/null +++ b/pkg/intel/metadata/cbnt/revision.go @@ -0,0 +1,53 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "encoding/binary" + "fmt" + "io" +) + +type BootGuardVersion uint8 + +func (bgv BootGuardVersion) String() string { + switch bgv { + case Version10: + return "1.0" + case Version20: + return "2.0" + case Version21: + return "2.1" + } + return "unknown" +} + +func DetectBGV(r io.ReadSeeker) (BootGuardVersion, error) { + // We could take StructInfoBG here as well since version + // is under the saem offset, so it does not really matter. + // Plus we just have it here for version detection, so it won't + // hurt even if read version is actually 0x10. + var s StructInfoCBNT + err := binary.Read(r, endianess, &s) + if err != nil { + return 0, fmt.Errorf("unable to read field 'ID': %w", err) + } + _, err = r.Seek(0, 0) + if err != nil { + return 0, err + } + + // See #575623-1.2.9 Section 5.3.3.1 Tab. 5-16. + switch s.Version { + case 0x10: + return Version10, nil + case 0x20, 0x21: + return Version20, nil + case 0x22, 0x23, 0x24, 0x25: + return Version21, nil + default: + return 0, fmt.Errorf("couldn't detect version 0x%x", s.Version) + } +} diff --git a/pkg/intel/metadata/cbnt/revision_test.go b/pkg/intel/metadata/cbnt/revision_test.go new file mode 100644 index 00000000..4ca25f1b --- /dev/null +++ b/pkg/intel/metadata/cbnt/revision_test.go @@ -0,0 +1,133 @@ +// Copyright 2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "bytes" + "errors" + "io" + "strings" + "testing" +) + +func TestBootGuardVersionString(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + in BootGuardVersion + want string + }{ + "version_1_0": {in: Version10, want: "1.0"}, + "version_2_0": {in: Version20, want: "2.0"}, + "version_2_1": {in: Version21, want: "2.1"}, + "unknown": {in: BootGuardVersion(0xFF), want: "unknown"}, + } + + for name, tt := range tests { + name := name + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + + if got := tt.in.String(); got != tt.want { + t.Errorf("BootGuardVersion(%d).String() = %q, want %q", tt.in, got, tt.want) + } + }) + } +} + +func TestDetectBGV(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + version byte + want BootGuardVersion + wantErr bool + errSub string + }{ + {name: "0x10_to_v1_0", version: 0x10, want: Version10}, + {name: "0x20_to_v2_0", version: 0x20, want: Version20}, + {name: "0x21_to_v2_0", version: 0x21, want: Version20}, + {name: "0x22_to_v2_1", version: 0x22, want: Version21}, + {name: "0x23_to_v2_1", version: 0x23, want: Version21}, + {name: "0x24_to_v2_1", version: 0x24, want: Version21}, + {name: "0x25_to_v2_1", version: 0x25, want: Version21}, + {name: "unknown", version: 0x99, wantErr: true, errSub: "couldn't detect version"}, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + r := bytes.NewReader(rawStructInfoVersion(tt.version)) + got, err := DetectBGV(r) + if tt.wantErr { + if err == nil { + t.Errorf("DetectBGV(version 0x%x) error = nil, want non-nil", tt.version) + } else if tt.errSub != "" && !strings.Contains(err.Error(), tt.errSub) { + t.Errorf("DetectBGV(version 0x%x) error = %q, want substring %q", tt.version, err.Error(), tt.errSub) + } + } else if err != nil { + t.Fatalf("DetectBGV(version 0x%x) error = %v, want nil", tt.version, err) + } else if got != tt.want { + t.Errorf("DetectBGV(version 0x%x) = %v, want %v", tt.version, got, tt.want) + } + + if pos, err := r.Seek(0, io.SeekCurrent); err != nil { + t.Fatalf("reader.Seek(current) error = %v, want nil", err) + } else if pos != 0 { + t.Errorf("reader position after DetectBGV() = %d, want %d", pos, 0) + } + }) + } +} + +func TestDetectBGVErrorPaths(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + r io.ReadSeeker + errSub string + }{ + {name: "read_error", r: bytes.NewReader(nil), errSub: "unable to read field 'ID'"}, + {name: "seek_error", r: seekFailReadSeeker{r: bytes.NewReader(rawStructInfoVersion(0x20))}, errSub: "seek failed"}, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + _, err := DetectBGV(tt.r) + if err == nil { + t.Fatalf("DetectBGV(%s) error = nil, want non-nil", tt.name) + } + if !strings.Contains(err.Error(), tt.errSub) { + t.Errorf("DetectBGV(%s) error = %q, want substring %q", tt.name, err.Error(), tt.errSub) + } + }) + } +} + +func rawStructInfoVersion(version byte) []byte { + b := make([]byte, 12) + b[8] = version + return b +} + +type seekFailReadSeeker struct { + r io.Reader +} + +func (s seekFailReadSeeker) Read(p []byte) (int, error) { + return s.r.Read(p) +} + +func (s seekFailReadSeeker) Seek(offset int64, whence int) (int64, error) { + return 0, errors.New("seek failed") +} diff --git a/pkg/intel/metadata/common/bgheader/bgheader.go b/pkg/intel/metadata/common/bgheader/bgheader.go deleted file mode 100644 index 92aaf6b8..00000000 --- a/pkg/intel/metadata/common/bgheader/bgheader.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2017-2023 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package bgheader - -import ( - "encoding/binary" - "fmt" - "io" -) - -var ( - binaryOrder = binary.LittleEndian -) - -type structInfo struct { - ID structureID `json:"StructInfoID"` - Version uint8 `json:"StructInfoVersion"` -} - -type structureID [8]byte - -type BootGuardVersion uint8 - -const ( - Version10 BootGuardVersion = 1 - Version20 BootGuardVersion = 2 -) - -func (bgv BootGuardVersion) String() string { - switch bgv { - case Version10: - return "1.0" - case Version20: - return "2.0" - } - return "unknown" -} - -func DetectBGV(r io.ReadSeeker) (BootGuardVersion, error) { - var s structInfo - err := binary.Read(r, binaryOrder, &s) - if err != nil { - return 0, fmt.Errorf("unable to read field 'ID': %w", err) - } - _, err = r.Seek(0, 0) - if err != nil { - return 0, err - } - if s.Version >= 0x20 { - return Version20, nil - } else if (s.Version < 0x20) && (s.Version >= 0x10) { - return Version10, nil - } else { - return 0, fmt.Errorf("couldn't detect version") - } -} From 597441c6277b2b14ef9763a42d727d899ca7c53d Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Wed, 15 Apr 2026 14:06:42 +0200 Subject: [PATCH 08/40] feat(intel/metadata): add Common struct for accessing shared methods Add Common struct. Acts as an accessor for shared methods (ReadFrom, WriteTo, TotalSize, <>Offset, TotalSize and PrettyString). Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/common.go | 315 ++++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 pkg/intel/metadata/cbnt/common.go diff --git a/pkg/intel/metadata/cbnt/common.go b/pkg/intel/metadata/cbnt/common.go new file mode 100644 index 00000000..17315771 --- /dev/null +++ b/pkg/intel/metadata/cbnt/common.go @@ -0,0 +1,315 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cbnt provides representation of BG/CBnT structures. +package cbnt + +import ( + "encoding/binary" + "fmt" + "io" + "strings" + + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) + +var ( + endianess = binary.LittleEndian +) + +type LayoutProvider interface { + Layout() []LayoutField +} + +// Acts as an accessor for all the methods shared accross the types. +// All types implementing Structure should embed it. +type Common struct{} + +func (Common) TotalSize(p LayoutProvider) uint64 { + var total uint64 + for _, f := range p.Layout() { + total += f.Size() + } + return total +} + +func (Common) SizeOf(p LayoutProvider, id int) (uint64, error) { + for _, f := range p.Layout() { + if f.ID == id { + return f.Size(), nil + } + } + + return 0, fmt.Errorf("has no field of ID %d", id) +} + +func (Common) OffsetOf(p LayoutProvider, id int) (uint64, error) { + var offset uint64 + + for _, f := range p.Layout() { + if f.ID == id { + return offset, nil + } + offset += f.Size() + } + + return 0, fmt.Errorf("has no field of ID %d", id) +} + +func (Common) PrettyString(depth uint, withHeader bool, p LayoutProvider, structName string, opts ...pretty.Option) string { + var lines []string + + if withHeader { + lines = append(lines, pretty.Header(depth, structName, p)) + } + + for _, f := range p.Layout() { + if f.Type == ManifestFieldList { + // Handling type detection here would be dirty here, let's not do that and just skip + // This case is difficult to handle without using reflection (which I really want to avoid), + // thus this is an exception from generalizing logic and has to be handled by the type itself. + continue + } + lines = append(lines, pretty.SubValue(depth+1, f.Name, "", f.Value(), opts...)...) + } + + if depth < 2 { + lines = append(lines, "") + } + return strings.Join(lines, "\n") +} + +func (Common) ReadFrom(r io.Reader, p LayoutProvider) (int64, error) { + totalN := int64(0) + + for _, f := range p.Layout() { + switch f.Type { + case ManifestFieldEndValue: + n, err := readStatic(r, f.Size(), f.Value()) + if err != nil { + return totalN, fmt.Errorf("unable to read field '%s': %w", f.Name, err) + } + totalN += n + case ManifestFieldArrayDynamicWithSize: + size := uint16(f.Size()) + n, err := readArrayDynamic(r, &size, f.Value()) + if err != nil { + return totalN, fmt.Errorf("unable to read field '%s': %w", f.Name, err) + } + totalN += n + case ManifestFieldArrayDynamicWithPrefix: + n, err := readArrayDynamic(r, nil, f.Value()) + if err != nil { + return totalN, fmt.Errorf("unable to read field '%s': %w", f.Name, err) + } + totalN += n + case ManifestFieldList: + if f.ReadList == nil { + return totalN, fmt.Errorf("field '%s' has no list reader", f.Name) + } + n, err := f.ReadList(r) + if err != nil { + return totalN, fmt.Errorf("unable to read field '%s': %w", f.Name, err) + } + totalN += n + case ManifestFieldArrayStatic: + n, err := readStatic(r, f.Size(), f.Value()) + if err != nil { + return totalN, fmt.Errorf("unable to read field '%s': %w", f.Name, err) + } + totalN += n + case ManifestFieldSubStruct: + fieldValue := f.Value() + sub, ok := fieldValue.(io.ReaderFrom) + if !ok { + return totalN, fmt.Errorf("field '%s' does not implement io.ReaderFrom", f.Name) + } + n, err := readSubStruct(r, sub) + if err != nil { + return totalN, fmt.Errorf("unable to read field '%s': %w", f.Name, err) + } + totalN += n + } + } + + return totalN, nil +} + +func (Common) WriteTo(w io.Writer, p LayoutProvider) (int64, error) { + totalN := int64(0) + + for _, f := range p.Layout() { + switch f.Type { + case ManifestFieldEndValue: + n, err := writeStatic(w, f.Size(), f.Value()) + if err != nil { + return totalN, fmt.Errorf("unable to write field '%s': %w", f.Name, err) + } + totalN += n + case ManifestFieldArrayDynamicWithSize: + n, err := writeArrayDynamic(w, false, f.Value()) + if err != nil { + return totalN, fmt.Errorf("unable to write field '%s': %w", f.Name, err) + } + totalN += n + case ManifestFieldArrayDynamicWithPrefix: + n, err := writeArrayDynamic(w, true, f.Value()) + if err != nil { + return totalN, fmt.Errorf("unable to write field '%s': %w", f.Name, err) + } + totalN += n + case ManifestFieldList: + if f.WriteList == nil { + return totalN, fmt.Errorf("field '%s' has no list writer", f.Name) + } + n, err := f.WriteList(w) + if err != nil { + return totalN, fmt.Errorf("unable to write field '%s': %w", f.Name, err) + } + totalN += n + case ManifestFieldArrayStatic: + n, err := writeStatic(w, f.Size(), f.Value()) + if err != nil { + return totalN, fmt.Errorf("unable to write field '%s': %w", f.Name, err) + } + totalN += n + case ManifestFieldSubStruct: + fieldValue := f.Value() + if fieldValue == nil { + continue + } + + sub, ok := fieldValue.(io.WriterTo) + if !ok { + return totalN, fmt.Errorf("field '%s' does not implement io.WriterTo", f.Name) + } + n, err := writeSubStruct(w, sub) + if err != nil { + return totalN, fmt.Errorf("unable to write field '%s': %w", f.Name, err) + } + totalN += n + } + } + + return totalN, nil + +} + +// We have 5 possible types of ManifestFieldType: +// endValue, arrayDynamic, arrayStatic, list and subStruct. +// Common.ReadFrom will distingush these (apart from list) and use the helpers. +func readStatic(r io.Reader, fieldSize uint64, fieldValue any) (int64, error) { + n, err := fieldSize, binary.Read(r, endianess, fieldValue) + if err != nil { + return 0, err + } + return int64(n), nil +} + +func readArrayDynamic(r io.Reader, size *uint16, out any) (int64, error) { + total := int64(0) + + if size == nil { + var n uint16 + if err := binary.Read(r, endianess, &n); err != nil { + return total, err + } + total += int64(binary.Size(n)) + size = &n + } + + dst, ok := out.(*[]byte) + if !ok { + return total, fmt.Errorf("arrayDynamic expects *[]byte, got %T", out) + } + + *dst = make([]byte, *size) + n := len(*dst) + if err := binary.Read(r, endianess, *dst); err != nil { + return total, err + } + total += int64(n) + + return total, nil +} + +func readSubStruct(r io.Reader, out io.ReaderFrom) (int64, error) { + n, err := out.ReadFrom(r) + if err != nil { + return 0, err + } + return n, nil +} + +func writeStatic(w io.Writer, fieldSize uint64, fieldValue any) (int64, error) { + n, err := fieldSize, binary.Write(w, endianess, fieldValue) + if err != nil { + return 0, err + } + return int64(n), nil +} + +func writeArrayDynamic(w io.Writer, withPrefix bool, out any) (int64, error) { + total := int64(0) + + src, ok := out.(*[]byte) + if !ok { + return total, fmt.Errorf("arrayDynamic expects *[]byte, got %T", out) + } + + if withPrefix { + size := uint16(len(*src)) + if err := binary.Write(w, endianess, size); err != nil { + return total, err + } + total += int64(binary.Size(size)) + } + + n := len(*src) + if err := binary.Write(w, endianess, *src); err != nil { + return total, err + } + total += int64(n) + + return total, nil +} + +func writeSubStruct(w io.Writer, out io.WriterTo) (int64, error) { + n, err := out.WriteTo(w) + if err != nil { + return 0, err + } + return n, nil +} + +// Okay this might seem bit hacky: we use dummy type that just +// implements LayoutProvider, and based on info value passes +// either full Layout or Layout - StructInfo. +// This is used a lot with BPM types. Not ideal, but +// spares lines of boilerplate code per type. +type DummyLayout struct { + Fields []LayoutField +} + +func (s DummyLayout) Layout() []LayoutField { + return s.Fields +} + +type StructInfo interface { + Structure + StructInfo() StructInfo +} + +func NewStructInfo(bgv BootGuardVersion) StructInfo { + switch bgv { + case Version10: + s := &StructInfoBG{} + return s + case Version20, Version21: + s := &StructInfoCBNT{} + return s + default: + return nil + } +} From a1dc7a230a8a6639c5944fd7371bc98791b039c9 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Wed, 15 Apr 2026 14:42:21 +0200 Subject: [PATCH 09/40] feat(intel/metadata): add merged StructInfo Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/structure.go | 131 +++++++++----- pkg/intel/metadata/cbnt/structure_bg.go | 91 ++++++++++ pkg/intel/metadata/cbnt/structure_test.go | 201 ++++++++++++++++++++++ 3 files changed, 383 insertions(+), 40 deletions(-) create mode 100644 pkg/intel/metadata/cbnt/structure_bg.go create mode 100644 pkg/intel/metadata/cbnt/structure_test.go diff --git a/pkg/intel/metadata/cbnt/structure.go b/pkg/intel/metadata/cbnt/structure.go index 59618a8b..93fbf623 100644 --- a/pkg/intel/metadata/cbnt/structure.go +++ b/pkg/intel/metadata/cbnt/structure.go @@ -1,70 +1,121 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:generate manifestcodegen - package cbnt import ( - "encoding/binary" + "fmt" "io" "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" ) -var ( - binaryOrder = binary.LittleEndian -) +// StructureID is the magic ID string used to identify the structure type +// in the manifest +type StructureID [8]byte -// StructInfo is the common part of any structure of a manifest -type StructInfo struct { +type StructInfoCBNT struct { + Common ID StructureID `json:"StructInfoID"` Version uint8 `json:"StructInfoVersion"` Variable0 uint8 `json:"StructInfoVariable0"` ElementSize uint16 `json:"StructInfoElementSize"` } -// StructInfo just returns StructInfo, it is a handy method if StructInfo -// is included anonymously to another type. -func (s StructInfo) StructInfo() StructInfo { - return s +// ReadFrom reads the StructInfo from 'r' in format defined in the document #575623. +func (s StructInfoCBNT) ReadFrom(r io.Reader) (int64, error) { + totalN, err := s.Common.ReadFrom(r, s) + if err != nil { + return 0, err + } + + return totalN, nil } -// StructureID is the magic ID string used to identify the structure type -// in the manifest -type StructureID [8]byte +func (s StructInfoCBNT) Validate() error { + // ID, version and element size might differ, only thing that we can always validate is + // Variable0. + if s.Variable0 != 0 { + return fmt.Errorf("field 'Variable0' expects value '0', but has %v", s.Variable0) + } + return nil +} -// String returns the ID as a string. -func (s StructureID) String() string { - return string(s[:]) +// WriteTo writes the StructInfo into 'w' in format defined in +// the document #575623. +func (s StructInfoCBNT) WriteTo(w io.Writer) (int64, error) { + return s.Common.WriteTo(w, s) +} + +func (s StructInfoCBNT) Layout() []LayoutField { + return []LayoutField{ + { + ID: 0, + Name: "ID", + Size: func() uint64 { return 8 }, + Value: func() any { return &s.ID }, + Type: ManifestFieldArrayStatic, + }, + { + ID: 1, + Name: "Version", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Version }, + Type: ManifestFieldEndValue, + }, + { + ID: 2, + Name: "Variable 0", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Variable0 }, + Type: ManifestFieldEndValue, + }, + { + ID: 3, + Name: "Element Size", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.ElementSize }, + Type: ManifestFieldEndValue, + }, + } +} + +func (s StructInfoCBNT) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("StructInfoCBnT: %v", err) + } + + return ret, nil } -// Structure is an abstraction of a structure of a manifest. -type Structure interface { - io.ReaderFrom - io.WriterTo - TotalSize() uint64 - // PrettyString returns the whole object as a structured string. - PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string +func (s StructInfoCBNT) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("StructInfoCBnT: %v", err) + } + + return ret, nil } -// Element is an abstraction of an element of a manifest. -type Element interface { - Structure - ReadDataFrom(r io.Reader) (int64, error) - GetStructInfo() StructInfo - SetStructInfo(StructInfo) +// Size returns the total size of the StructInfo. +func (s StructInfoCBNT) TotalSize() uint64 { + return s.Common.TotalSize(s) } -// ElementsContainer is an abstraction of set of elements of a manifest (for -// example: the root structure of BPM). -type ElementsContainer interface { - Structure - GetFieldByStructID(structID string) interface{} +// PrettyString returns the content of the structure in an easy-to-read format. +func (s StructInfoCBNT) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return Common{}.PrettyString(depth, withHeader, s, "Struct Info", opts...) } -// Manifest is an abstract manifest. -type Manifest interface { - Structure +// StructInfo just returns StructInfo, it is a handy method if StructInfo +// is included anonymously to another type. +func (s StructInfoCBNT) StructInfo() StructInfo { + return s +} + +// String returns the ID as a string. +func (s StructureID) String() string { + return string(s[:]) } diff --git a/pkg/intel/metadata/cbnt/structure_bg.go b/pkg/intel/metadata/cbnt/structure_bg.go new file mode 100644 index 00000000..74389276 --- /dev/null +++ b/pkg/intel/metadata/cbnt/structure_bg.go @@ -0,0 +1,91 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "fmt" + "io" + + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) + +type StructInfoBG struct { + Common + ID StructureID `json:"StructInfoID"` + Version uint8 `json:"StructInfoVersion"` +} + +// ReadFrom reads the StructInfo from 'r' in format defined in the document #575623. +func (s StructInfoBG) ReadFrom(r io.Reader) (int64, error) { + totalN, err := s.Common.ReadFrom(r, s) + if err != nil { + return 0, err + } + + return totalN, nil +} + +func (s StructInfoBG) Validate() error { + return nil +} + +// WriteTo writes the StructInfo into 'w' in format defined in +// the document #575623. +func (s StructInfoBG) WriteTo(w io.Writer) (int64, error) { + return s.Common.WriteTo(w, s) +} + +func (s StructInfoBG) Layout() []LayoutField { + return []LayoutField{ + { + ID: 0, + Name: "ID", + Size: func() uint64 { return 8 }, + Value: func() any { return &s.ID }, + Type: ManifestFieldArrayStatic, + }, + { + ID: 1, + Name: "Version", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Version }, + Type: ManifestFieldEndValue, + }, + } +} + +func (s StructInfoBG) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("HashList: %v", err) + } + + return ret, nil +} + +func (s StructInfoBG) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("HashList: %v", err) + } + + return ret, nil +} + +// Size returns the total size of the StructInfo. +func (s StructInfoBG) TotalSize() uint64 { + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s StructInfoBG) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return Common{}.PrettyString(depth, withHeader, s, "Struct Info", opts...) +} + +// StructInfo just returns StructInfo, it is a handy method if StructInfo +// is included anonymously to another type. +func (s StructInfoBG) StructInfo() StructInfo { + return s +} diff --git a/pkg/intel/metadata/cbnt/structure_test.go b/pkg/intel/metadata/cbnt/structure_test.go new file mode 100644 index 00000000..1f2a46bc --- /dev/null +++ b/pkg/intel/metadata/cbnt/structure_test.go @@ -0,0 +1,201 @@ +// Copyright 2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "bytes" + "reflect" + "strings" + "testing" +) + +func TestNewStructInfo(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + bgv BootGuardVersion + wantType string + wantNil bool + }{ + "version_1_0": {bgv: Version10, wantType: "*cbnt.StructInfoBG"}, + "version_2_0": {bgv: Version20, wantType: "*cbnt.StructInfoCBNT"}, + "version_2_1": {bgv: Version21, wantType: "*cbnt.StructInfoCBNT"}, + "unknown": {bgv: BootGuardVersion(0xFF), wantNil: true}, + } + + for name, tT := range tests { + name := name + tT := tT + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := NewStructInfo(tT.bgv) + if tT.wantNil { + if got != nil { + t.Errorf("NewStructInfo(%v) = %T, want nil", tT.bgv, got) + } + return + } + + if got == nil { + t.Fatalf("NewStructInfo(%v) = nil, want non-nil", tT.bgv) + } + + if gotType := reflect.TypeOf(got).String(); gotType != tT.wantType { + t.Errorf("NewStructInfo(%v) type = %s, want %s", tT.bgv, gotType, tT.wantType) + } + }) + } +} + +func TestStructInfoBGMethods(t *testing.T) { + t.Parallel() + + s := StructInfoBG{ID: StructureID{'S', 'T', 'R', 'U', 'C', 'T', 'B', 'G'}, Version: 0x10} + + if err := s.Validate(); err != nil { + t.Errorf("StructInfoBG.Validate() error = %v, want nil", err) + } + + if got := len(s.Layout()); got != 2 { + t.Errorf("len(StructInfoBG.Layout()) = %d, want %d", got, 2) + } + + if got := s.TotalSize(); got != 9 { + t.Errorf("StructInfoBG.TotalSize() = %d, want %d", got, 9) + } + + size0, err := s.SizeOf(0) + if err != nil { + t.Fatalf("StructInfoBG.SizeOf(0) error = %v, want nil", err) + } + if size0 != 8 { + t.Errorf("StructInfoBG.SizeOf(0) = %d, want %d", size0, 8) + } + + offset1, err := s.OffsetOf(1) + if err != nil { + t.Fatalf("StructInfoBG.OffsetOf(1) error = %v, want nil", err) + } + if offset1 != 8 { + t.Errorf("StructInfoBG.OffsetOf(1) = %d, want %d", offset1, 8) + } + + if _, err := s.SizeOf(99); err == nil { + t.Errorf("StructInfoBG.SizeOf(99) error = nil, want non-nil") + } + if _, err := s.OffsetOf(99); err == nil { + t.Errorf("StructInfoBG.OffsetOf(99) error = nil, want non-nil") + } + + var buf bytes.Buffer + n, err := s.WriteTo(&buf) + if err != nil { + t.Fatalf("StructInfoBG.WriteTo() error = %v, want nil", err) + } + if n != int64(s.TotalSize()) { + t.Errorf("StructInfoBG.WriteTo() bytes = %d, want %d", n, s.TotalSize()) + } + + var readTarget StructInfoBG + n, err = readTarget.ReadFrom(bytes.NewReader(buf.Bytes())) + if err != nil { + t.Fatalf("StructInfoBG.ReadFrom() error = %v, want nil", err) + } + if n != int64(s.TotalSize()) { + t.Errorf("StructInfoBG.ReadFrom() bytes = %d, want %d", n, s.TotalSize()) + } + + if got := s.StructInfo(); reflect.TypeOf(got).String() != "cbnt.StructInfoBG" { + t.Errorf("StructInfoBG.StructInfo() type = %T, want cbnt.StructInfoBG", got) + } + + pretty := s.PrettyString(0, true) + if !strings.Contains(pretty, "Struct Info") { + t.Errorf("StructInfoBG.PrettyString() = %q, want to contain %q", pretty, "Struct Info") + } +} + +func TestStructInfoCBNTMethods(t *testing.T) { + t.Parallel() + + s := StructInfoCBNT{ + ID: StructureID{'S', 'T', 'R', 'U', 'C', 'T', '2', '0'}, + Version: 0x20, + Variable0: 0, + ElementSize: 0x0020, + } + + if err := s.Validate(); err != nil { + t.Errorf("StructInfoCBNT.Validate() error = %v, want nil", err) + } + + if got := len(s.Layout()); got != 4 { + t.Errorf("len(StructInfoCBNT.Layout()) = %d, want %d", got, 4) + } + + if got := s.TotalSize(); got != 12 { + t.Errorf("StructInfoCBNT.TotalSize() = %d, want %d", got, 12) + } + + size3, err := s.SizeOf(3) + if err != nil { + t.Fatalf("StructInfoCBNT.SizeOf(3) error = %v, want nil", err) + } + if size3 != 2 { + t.Errorf("StructInfoCBNT.SizeOf(3) = %d, want %d", size3, 2) + } + + offset3, err := s.OffsetOf(3) + if err != nil { + t.Fatalf("StructInfoCBNT.OffsetOf(3) error = %v, want nil", err) + } + if offset3 != 10 { + t.Errorf("StructInfoCBNT.OffsetOf(3) = %d, want %d", offset3, 10) + } + + if _, err := s.SizeOf(99); err == nil { + t.Errorf("StructInfoCBNT.SizeOf(99) error = nil, want non-nil") + } + if _, err := s.OffsetOf(99); err == nil { + t.Errorf("StructInfoCBNT.OffsetOf(99) error = nil, want non-nil") + } + + var buf bytes.Buffer + n, err := s.WriteTo(&buf) + if err != nil { + t.Fatalf("StructInfoCBNT.WriteTo() error = %v, want nil", err) + } + if n != int64(s.TotalSize()) { + t.Errorf("StructInfoCBNT.WriteTo() bytes = %d, want %d", n, s.TotalSize()) + } + + var readTarget StructInfoCBNT + n, err = readTarget.ReadFrom(bytes.NewReader(buf.Bytes())) + if err != nil { + t.Fatalf("StructInfoCBNT.ReadFrom() error = %v, want nil", err) + } + if n != int64(s.TotalSize()) { + t.Errorf("StructInfoCBNT.ReadFrom() bytes = %d, want %d", n, s.TotalSize()) + } + + if got := s.StructInfo(); reflect.TypeOf(got).String() != "cbnt.StructInfoCBNT" { + t.Errorf("StructInfoCBNT.StructInfo() type = %T, want cbnt.StructInfoCBNT", got) + } + + pretty := s.PrettyString(0, true) + if !strings.Contains(pretty, "Struct Info") { + t.Errorf("StructInfoCBNT.PrettyString() = %q, want to contain %q", pretty, "Struct Info") + } +} + +func TestStructureIDString(t *testing.T) { + t.Parallel() + + id := StructureID{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'} + if got, want := id.String(), "ABCDEFGH"; got != want { + t.Errorf("StructureID.String() = %q, want %q", got, want) + } +} From 1acbabbce09f02d3c19e2a8b9a93c3a3f8bd4865 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Wed, 15 Apr 2026 14:59:54 +0200 Subject: [PATCH 10/40] feat(intel/metadata): adapt Signature to use Common shared methods Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/signature.go | 220 +++++++--- pkg/intel/metadata/cbnt/signature_test.go | 513 ++++++++++++++++++++++ 2 files changed, 676 insertions(+), 57 deletions(-) create mode 100644 pkg/intel/metadata/cbnt/signature_test.go diff --git a/pkg/intel/metadata/cbnt/signature.go b/pkg/intel/metadata/cbnt/signature.go index 53d1ec89..055df4de 100644 --- a/pkg/intel/metadata/cbnt/signature.go +++ b/pkg/intel/metadata/cbnt/signature.go @@ -8,18 +8,16 @@ package cbnt import ( "crypto" - "crypto/rand" "fmt" "math/big" -) -var ( - // RandReader exports the rand.Reader - RandReader = rand.Reader + "io" + + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" ) -// Signature exports the Signature structure type Signature struct { + Common SigScheme Algorithm `json:"sigScheme"` Version uint8 `require:"0x10" json:"sigVersion,omitempty"` KeySize BitSize `json:"sigKeysize,omitempty"` @@ -27,8 +25,116 @@ type Signature struct { Data []byte `countValue:"KeySize.InBytes()" prettyValue:"dataPrettyValue()" json:"sigData"` } -func (m Signature) dataPrettyValue() interface{} { - r, _ := m.SignatureData() +// NewSignature returns a new instance of Signature with +// all default values set. +func NewSignature() *Signature { + s := &Signature{} + // Set through tag "required": + s.Version = 0x10 + return s +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *Signature) Validate() error { + // See tag "require" + if s.Version != 0x10 { + return fmt.Errorf("field 'Version' expects value '0x10', but has %v", s.Version) + } + + return nil +} + +// ReadFrom reads the Signature from 'r' in format defined in the document #575623. +func (s *Signature) ReadFrom(r io.Reader) (int64, error) { + totalN, err := s.Common.ReadFrom(r, s) + if err != nil { + return 0, err + } + + return totalN, nil +} + +// WriteTo writes the Signature into 'w' in format defined in +// the document #575623. +func (s *Signature) WriteTo(w io.Writer) (int64, error) { + return s.Common.WriteTo(w, s) +} + +func (s *Signature) Layout() []LayoutField { + return []LayoutField{ + { + ID: 0, + Name: "Sig Scheme", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.SigScheme }, + Type: ManifestFieldEndValue, + }, + { + ID: 1, + Name: "Version", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Version }, + Type: ManifestFieldEndValue, + }, + { + ID: 2, + Name: "Key Size", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.KeySize }, + Type: ManifestFieldEndValue, + }, + { + ID: 3, + Name: "Hash Alg", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.HashAlg }, + Type: ManifestFieldEndValue, + }, + { + ID: 4, + Name: "Data", + Size: func() uint64 { return uint64(s.KeySize.InBytes()) }, + Value: func() any { return &s.Data }, + Type: ManifestFieldArrayDynamicWithSize, + }, + } +} + +func (s *Signature) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("HashList: %v", err) + } + + return ret, nil +} + +func (s *Signature) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("HashList: %v", err) + } + + return ret, nil +} + +// Size returns the total size of the Signature. +func (s *Signature) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *Signature) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return Common{}.PrettyString(depth, withHeader, s, "Signature", opts...) +} + +func (s Signature) dataPrettyValue() any { + r, _ := s.SignatureData() return r } @@ -37,31 +143,31 @@ func (m Signature) dataPrettyValue() interface{} { // * SignatureRSAASA // * SignatureECDSA // * SignatureSM2 -func (m Signature) SignatureData() (SignatureDataInterface, error) { - switch m.SigScheme { +func (s Signature) SignatureData() (SignatureDataInterface, error) { + switch s.SigScheme { case AlgRSAPSS: - return SignatureRSAPSS(m.Data), nil + return SignatureRSAPSS(s.Data), nil case AlgRSASSA: - return SignatureRSAASA(m.Data), nil + return SignatureRSAASA(s.Data), nil case AlgECDSA: - if len(m.Data) != 64 && len(m.Data) != 96 { - return nil, fmt.Errorf("invalid length of the signature data: %d (expected 64 or 96)", len(m.Data)) + if len(s.Data) != 64 && len(s.Data) != 96 { + return nil, fmt.Errorf("invalid length of the signature data: %d (expected 64 or 96)", len(s.Data)) } return SignatureECDSA{ - R: new(big.Int).SetBytes(reverseBytes(m.Data[:len(m.Data)/2])), - S: new(big.Int).SetBytes(reverseBytes(m.Data[len(m.Data)/2:])), + R: new(big.Int).SetBytes(reverseBytes(s.Data[:len(s.Data)/2])), + S: new(big.Int).SetBytes(reverseBytes(s.Data[len(s.Data)/2:])), }, nil case AlgSM2: - if len(m.Data) != 64 && len(m.Data) != 96 { - return nil, fmt.Errorf("invalid length of the signature data: %d (expected 64 or 96)", len(m.Data)) + if len(s.Data) != 64 && len(s.Data) != 96 { + return nil, fmt.Errorf("invalid length of the signature data: %d (expected 64 or 96)", len(s.Data)) } return SignatureSM2{ - R: new(big.Int).SetBytes(reverseBytes(m.Data[:len(m.Data)/2])), - S: new(big.Int).SetBytes(reverseBytes(m.Data[len(m.Data)/2:])), + R: new(big.Int).SetBytes(reverseBytes(s.Data[:len(s.Data)/2])), + S: new(big.Int).SetBytes(reverseBytes(s.Data[len(s.Data)/2:])), }, nil } - return nil, fmt.Errorf("unexpected signature scheme: %s", m.SigScheme) + return nil, fmt.Errorf("unexpected signature scheme: %s", s.SigScheme) } // SetSignatureByData sets all the fields of the structure Signature by @@ -70,45 +176,45 @@ func (m Signature) SignatureData() (SignatureDataInterface, error) { // * SignatureRSAASA // * SignatureECDSA // * SignatureSM2 -func (m *Signature) SetSignatureByData(sig SignatureDataInterface, hashAlgo Algorithm) error { - err := m.SetSignatureData(sig) +func (s *Signature) SetSignatureByData(sig SignatureDataInterface, hashAlgo Algorithm) error { + err := s.SetSignatureData(sig) if err != nil { return err } switch sig := sig.(type) { case SignatureRSAPSS: - m.SigScheme = AlgRSAPSS + s.SigScheme = AlgRSAPSS if hashAlgo.IsNull() { - m.HashAlg = AlgSHA384 + s.HashAlg = AlgSHA384 } else { - m.HashAlg = hashAlgo + s.HashAlg = hashAlgo } - m.KeySize.SetInBytes(uint16(len(m.Data))) + s.KeySize.SetInBytes(uint16(len(s.Data))) case SignatureRSAASA: - m.SigScheme = AlgRSASSA + s.SigScheme = AlgRSASSA if hashAlgo.IsNull() { - m.HashAlg = AlgSHA256 + s.HashAlg = AlgSHA256 } else { - m.HashAlg = hashAlgo + s.HashAlg = hashAlgo } - m.KeySize.SetInBytes(uint16(len(m.Data))) + s.KeySize.SetInBytes(uint16(len(s.Data))) case SignatureECDSA: - m.SigScheme = AlgECDSA + s.SigScheme = AlgECDSA if hashAlgo.IsNull() { - m.HashAlg = AlgSHA512 + s.HashAlg = AlgSHA512 } else { - m.HashAlg = hashAlgo + s.HashAlg = hashAlgo } - m.KeySize.SetInBits(uint16(sig.R.BitLen())) + s.KeySize.SetInBits(uint16(sig.R.BitLen())) case SignatureSM2: - m.SigScheme = AlgSM2 + s.SigScheme = AlgSM2 if hashAlgo.IsNull() { - m.HashAlg = AlgSM3 + s.HashAlg = AlgSM3 } else { - m.HashAlg = hashAlgo + s.HashAlg = hashAlgo } - m.KeySize.SetInBits(uint16(sig.R.BitLen())) + s.KeySize.SetInBits(uint16(sig.R.BitLen())) default: return fmt.Errorf("unexpected signature type: %T", sig) } @@ -121,31 +227,31 @@ func (m *Signature) SetSignatureByData(sig SignatureDataInterface, hashAlgo Algo // * SignatureRSAASA // * SignatureECDSA // * SignatureSM2 -func (m *Signature) SetSignatureData(sig SignatureDataInterface) error { +func (s *Signature) SetSignatureData(sig SignatureDataInterface) error { switch sig := sig.(type) { case SignatureRSAPSS: - m.Data = sig + s.Data = sig case SignatureRSAASA: - m.Data = sig + s.Data = sig case SignatureECDSA, SignatureSM2: - var r, s *big.Int + var r, p *big.Int switch sig := sig.(type) { case SignatureECDSA: - r, s = sig.R, sig.S + r, p = sig.R, sig.S case SignatureSM2: - r, s = sig.R, sig.S + r, p = sig.R, sig.S default: return fmt.Errorf("internal error") } - if r.BitLen() != s.BitLen() { - return fmt.Errorf("the length of component R (%d) is not equal to the length of component S (%d)", r.BitLen(), s.BitLen()) + if r.BitLen() != p.BitLen() { + return fmt.Errorf("the length of component R (%d) is not equal to the length of component S (%d)", r.BitLen(), p.BitLen()) } if r.BitLen() != 256 && r.BitLen() != 384 { return fmt.Errorf("component R (or S) size should be 256 or 384 bites (not %d)", r.BitLen()) } - m.Data = make([]byte, r.BitLen()/8+s.BitLen()/8) - copy(m.Data[:], reverseBytes(r.Bytes())) - copy(m.Data[r.BitLen()/8:], reverseBytes(s.Bytes())) + s.Data = make([]byte, r.BitLen()/8+p.BitLen()/8) + copy(s.Data[:], reverseBytes(r.Bytes())) + copy(s.Data[r.BitLen()/8:], reverseBytes(p.Bytes())) default: return fmt.Errorf("unexpected signature type: %T", sig) } @@ -157,14 +263,14 @@ func (m *Signature) SetSignatureData(sig SignatureDataInterface) error { // // if signAlgo is zero then it is detected automatically, based on the type // of the provided private key. -func (m *Signature) SetSignature(signAlgo Algorithm, hashAlgo Algorithm, privKey crypto.Signer, signedData []byte) error { - m.Version = 0x10 - m.HashAlg = hashAlgo +func (s *Signature) SetSignature(signAlgo Algorithm, hashAlgo Algorithm, privKey crypto.Signer, signedData []byte) error { + s.Version = 0x10 + s.HashAlg = hashAlgo signData, err := NewSignatureData(signAlgo, privKey, signedData) if err != nil { return fmt.Errorf("unable to construct the signature data: %w", err) } - err = m.SetSignatureByData(signData, m.HashAlg) + err = s.SetSignatureByData(signData, s.HashAlg) if err != nil { return fmt.Errorf("unable to set the signature: %w", err) } @@ -177,14 +283,14 @@ func (m *Signature) SetSignature(signAlgo Algorithm, hashAlgo Algorithm, privKey // // if signAlgo is zero then it is detected automatically, based on the type // of the provided private key. -func (m *Signature) FillSignature(signAlgo Algorithm, pubKey crypto.PublicKey, signedData []byte, hashAlgo Algorithm) error { - m.Version = 0x10 +func (s *Signature) FillSignature(signAlgo Algorithm, pubKey crypto.PublicKey, signedData []byte, hashAlgo Algorithm) error { + s.Version = 0x10 signData, err := NewSignatureByData(signAlgo, pubKey, signedData) if err != nil { return fmt.Errorf("unable to construct the signature data: %w", err) } - err = m.SetSignatureByData(signData, hashAlgo) + err = s.SetSignatureByData(signData, hashAlgo) if err != nil { return fmt.Errorf("unable to set the signature: %w", err) } diff --git a/pkg/intel/metadata/cbnt/signature_test.go b/pkg/intel/metadata/cbnt/signature_test.go new file mode 100644 index 00000000..d361f204 --- /dev/null +++ b/pkg/intel/metadata/cbnt/signature_test.go @@ -0,0 +1,513 @@ +// Copyright 2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "bytes" + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "fmt" + "math/big" + "strings" + "testing" +) + +func TestSignatureNewAndValidate(t *testing.T) { + t.Parallel() + + s := NewSignature() + if s == nil { + t.Fatal("NewSignature() = nil, want non-nil") + } + if s.Version != 0x10 { + t.Errorf("NewSignature().Version = 0x%x, want 0x10", s.Version) + } + if err := s.Validate(); err != nil { + t.Errorf("NewSignature().Validate() error = %v, want nil", err) + } +} + +func TestSignatureValidateRejectsInvalidVersion(t *testing.T) { + t.Parallel() + + s := NewSignature() + s.Version = 0 + + if err := s.Validate(); err == nil { + t.Errorf("Signature.Validate() error = nil, want non-nil") + } +} + +func TestSignatureSetSignatureByData(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + sig SignatureDataInterface + hashAlgo Algorithm + wantSigScheme Algorithm + wantHash Algorithm + wantSizeBits uint16 + }{ + "rsassa_default_hash": { + sig: SignatureRSAASA([]byte{1, 2, 3, 4}), + hashAlgo: AlgUnknown, + wantSigScheme: AlgRSASSA, + wantHash: AlgSHA256, + wantSizeBits: 32, + }, + "rsapss_default_hash": { + sig: SignatureRSAPSS([]byte{1, 2, 3, 4, 5, 6}), + hashAlgo: AlgUnknown, + wantSigScheme: AlgRSAPSS, + wantHash: AlgSHA384, + wantSizeBits: 48, + }, + } + + for name, tt := range tests { + name := name + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + + s := NewSignature() + if err := s.SetSignatureByData(tt.sig, tt.hashAlgo); err != nil { + t.Fatalf("Signature.SetSignatureByData() error = %v, want nil", err) + } + + if s.SigScheme != tt.wantSigScheme { + t.Errorf("Signature.SetSignatureByData() SigScheme = %v, want %v", s.SigScheme, tt.wantSigScheme) + } + if s.HashAlg != tt.wantHash { + t.Errorf("Signature.SetSignatureByData() HashAlg = %v, want %v", s.HashAlg, tt.wantHash) + } + if got := s.KeySize.InBits(); got != tt.wantSizeBits { + t.Errorf("Signature.SetSignatureByData() KeySize = %d, want %d", got, tt.wantSizeBits) + } + }) + } +} + +func TestSignatureSetSignatureDataErrors(t *testing.T) { + t.Parallel() + + s := NewSignature() + + if err := s.SetSignatureData(unsupportedSignatureData{}); err == nil { + t.Errorf("Signature.SetSignatureData(unsupportedSignatureData{}) error = nil, want non-nil") + } + + badLen := SignatureECDSA{R: big.NewInt(1), S: new(big.Int).Lsh(big.NewInt(1), 255)} + if err := s.SetSignatureData(badLen); err == nil { + t.Errorf("Signature.SetSignatureData(mismatched ECDSA components) error = nil, want non-nil") + } + + badSize := SignatureECDSA{R: big.NewInt(1), S: big.NewInt(1)} + if err := s.SetSignatureData(badSize); err == nil { + t.Errorf("Signature.SetSignatureData(non-256/384 ECDSA components) error = nil, want non-nil") + } +} + +func TestSignatureSetFillAndParseDataWithRSA(t *testing.T) { + key := genRSA(t, 2048) + + payload := []byte("signature-rsa") + + sSet := NewSignature() + if err := sSet.SetSignature(AlgRSASSA, AlgSHA256, key, payload); err != nil { + t.Fatalf("Signature.SetSignature() error = %v, want nil", err) + } + parsed, err := sSet.SignatureData() + if err != nil { + t.Fatalf("Signature.SignatureData() error = %v, want nil", err) + } + if err := parsed.Verify(&key.PublicKey, sSet.HashAlg, payload); err != nil { + t.Errorf("SignatureData.Verify() error = %v, want nil", err) + } + + sFill := NewSignature() + if err := sFill.FillSignature(AlgRSASSA, &key.PublicKey, sSet.Data, AlgSHA256); err != nil { + t.Fatalf("Signature.FillSignature() error = %v, want nil", err) + } + parsedFill, err := sFill.SignatureData() + if err != nil { + t.Fatalf("Signature.SignatureData() after FillSignature error = %v, want nil", err) + } + if err := parsedFill.Verify(&key.PublicKey, sFill.HashAlg, payload); err != nil { + t.Errorf("SignatureData.Verify() after FillSignature error = %v, want nil", err) + } +} + +func TestSignatureDataByScheme(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + sigScheme Algorithm + data []byte + wantType string + wantErr bool + errSub string + }{ + "rsapss": {sigScheme: AlgRSAPSS, data: []byte{1, 2, 3}, wantType: "cbnt.SignatureRSAPSS"}, + "rsassa": {sigScheme: AlgRSASSA, data: []byte{4, 5, 6}, wantType: "cbnt.SignatureRSAASA"}, + "ecdsa_64": { + sigScheme: AlgECDSA, + data: bytes.Repeat([]byte{0x11}, 64), + wantType: "cbnt.SignatureECDSA", + }, + "sm2_96": { + sigScheme: AlgSM2, + data: bytes.Repeat([]byte{0x22}, 96), + wantType: "cbnt.SignatureSM2", + }, + "ecdsa_bad_len": { + sigScheme: AlgECDSA, + data: []byte{1, 2, 3}, + wantErr: true, + errSub: "invalid length", + }, + "sm2_bad_len": { + sigScheme: AlgSM2, + data: []byte{1, 2, 3}, + wantErr: true, + errSub: "invalid length", + }, + "unknown_scheme": { + sigScheme: AlgSHA256, + data: []byte{1}, + wantErr: true, + errSub: "unexpected signature scheme", + }, + } + + for name, tt := range tests { + name := name + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + + s := Signature{SigScheme: tt.sigScheme, Data: tt.data} + got, err := s.SignatureData() + if tt.wantErr { + if err == nil { + t.Errorf("Signature.SignatureData(%v) error = nil, want non-nil", tt.sigScheme) + } else if tt.errSub != "" && !strings.Contains(err.Error(), tt.errSub) { + t.Errorf("Signature.SignatureData(%v) error = %q, want substring %q", tt.sigScheme, err.Error(), tt.errSub) + } + return + } + + if err != nil { + t.Fatalf("Signature.SignatureData(%v) error = %v, want nil", tt.sigScheme, err) + } + if gotType := fmt.Sprintf("%T", got); gotType != tt.wantType { + t.Errorf("Signature.SignatureData(%v) type = %s, want %s", tt.sigScheme, gotType, tt.wantType) + } + }) + } +} + +func TestSignatureSetSignatureByDataAdditionalCases(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + sig SignatureDataInterface + hashAlgo Algorithm + wantSigScheme Algorithm + wantHash Algorithm + wantKeyBits uint16 + wantErr bool + errSub string + }{ + "ecdsa_default_hash": { + sig: SignatureECDSA{R: bigIntBits(256), S: bigIntBits(256)}, + hashAlgo: AlgUnknown, + wantSigScheme: AlgECDSA, + wantHash: AlgSHA512, + wantKeyBits: 256, + }, + "sm2_default_hash": { + sig: SignatureSM2{R: bigIntBits(256), S: bigIntBits(256)}, + hashAlgo: AlgUnknown, + wantSigScheme: AlgSM2, + wantHash: AlgSM3, + wantKeyBits: 256, + }, + "ecdsa_explicit_hash": { + sig: SignatureECDSA{R: bigIntBits(256), S: bigIntBits(256)}, + hashAlgo: AlgSHA384, + wantSigScheme: AlgECDSA, + wantHash: AlgSHA384, + wantKeyBits: 256, + }, + "unsupported_sig_type": { + sig: unsupportedSignatureData{}, + wantErr: true, + errSub: "unexpected signature type", + }, + } + + for name, tt := range tests { + name := name + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + + s := NewSignature() + err := s.SetSignatureByData(tt.sig, tt.hashAlgo) + if tt.wantErr { + if err == nil { + t.Errorf("Signature.SetSignatureByData(%T) error = nil, want non-nil", tt.sig) + } else if tt.errSub != "" && !strings.Contains(err.Error(), tt.errSub) { + t.Errorf("Signature.SetSignatureByData(%T) error = %q, want substring %q", tt.sig, err.Error(), tt.errSub) + } + return + } + + if err != nil { + t.Fatalf("Signature.SetSignatureByData(%T) error = %v, want nil", tt.sig, err) + } + if s.SigScheme != tt.wantSigScheme { + t.Errorf("Signature.SetSignatureByData(%T) SigScheme = %v, want %v", tt.sig, s.SigScheme, tt.wantSigScheme) + } + if s.HashAlg != tt.wantHash { + t.Errorf("Signature.SetSignatureByData(%T) HashAlg = %v, want %v", tt.sig, s.HashAlg, tt.wantHash) + } + if got := s.KeySize.InBits(); got != tt.wantKeyBits { + t.Errorf("Signature.SetSignatureByData(%T) KeySize bits = %d, want %d", tt.sig, got, tt.wantKeyBits) + } + }) + } +} + +func TestNewSignatureDataAndNewSignatureByData(t *testing.T) { + rsaKey := genRSA(t, 2048) + ecdsaKey := genECDSA(t) + data := []byte("signature-data") + + t.Run("NewSignatureData", func(t *testing.T) { + tests := map[string]struct { + signAlgo Algorithm + privKey crypto.Signer + wantType string + wantErr bool + errSub string + }{ + "auto_detect_rsa": { + signAlgo: 0, + privKey: rsaKey, + wantErr: true, + errSub: "is not implemented", + }, + "explicit_rsassa": { + signAlgo: AlgRSASSA, + privKey: rsaKey, + wantType: "cbnt.SignatureRSAASA", + }, + "ecdsa_wrong_key_type": { + signAlgo: AlgECDSA, + privKey: rsaKey, + wantErr: true, + errSub: "expected private ECDSA key", + }, + "unsupported_algo": { + signAlgo: AlgSHA1, + privKey: rsaKey, + wantErr: true, + errSub: "is not implemented", + }, + } + + for name, tt := range tests { + name := name + tt := tt + t.Run(name, func(t *testing.T) { + sig, err := NewSignatureData(tt.signAlgo, tt.privKey, data) + if tt.wantErr { + if err == nil { + t.Errorf("NewSignatureData(%v, %T) error = nil, want non-nil", tt.signAlgo, tt.privKey) + } else if tt.errSub != "" && !strings.Contains(err.Error(), tt.errSub) { + t.Errorf("NewSignatureData(%v, %T) error = %q, want substring %q", tt.signAlgo, tt.privKey, err.Error(), tt.errSub) + } + return + } + + if err != nil { + t.Fatalf("NewSignatureData(%v, %T) error = %v, want nil", tt.signAlgo, tt.privKey, err) + } + if gotType := fmt.Sprintf("%T", sig); gotType != tt.wantType { + t.Errorf("NewSignatureData(%v, %T) type = %s, want %s", tt.signAlgo, tt.privKey, gotType, tt.wantType) + } + }) + } + }) + + t.Run("NewSignatureByData", func(t *testing.T) { + rawECDSA := append(bytes.Repeat([]byte{0xA5}, 32), bytes.Repeat([]byte{0x5A}, 32)...) + + tests := map[string]struct { + signAlgo Algorithm + pubKey crypto.PublicKey + input []byte + wantType string + wantErr bool + errSub string + }{ + "auto_detect_rsa": { + signAlgo: 0, + pubKey: &rsaKey.PublicKey, + input: []byte{1, 2, 3}, + wantType: "cbnt.SignatureRSAASA", + }, + "auto_detect_ecdsa": { + signAlgo: 0, + pubKey: &ecdsaKey.PublicKey, + input: rawECDSA, + wantType: "cbnt.SignatureECDSA", + }, + "explicit_pss": { + signAlgo: AlgRSAPSS, + pubKey: &rsaKey.PublicKey, + input: []byte{9, 8, 7}, + wantType: "cbnt.SignatureRSAPSS", + }, + "unsupported_algo": { + signAlgo: AlgSHA1, + pubKey: &rsaKey.PublicKey, + input: []byte{1}, + wantErr: true, + errSub: "is not implemented", + }, + } + + for name, tt := range tests { + name := name + tt := tt + t.Run(name, func(t *testing.T) { + sig, err := NewSignatureByData(tt.signAlgo, tt.pubKey, tt.input) + if tt.wantErr { + if err == nil { + t.Errorf("NewSignatureByData(%v, %T) error = nil, want non-nil", tt.signAlgo, tt.pubKey) + } else if tt.errSub != "" && !strings.Contains(err.Error(), tt.errSub) { + t.Errorf("NewSignatureByData(%v, %T) error = %q, want substring %q", tt.signAlgo, tt.pubKey, err.Error(), tt.errSub) + } + return + } + + if err != nil { + t.Fatalf("NewSignatureByData(%v, %T) error = %v, want nil", tt.signAlgo, tt.pubKey, err) + } + if gotType := fmt.Sprintf("%T", sig); gotType != tt.wantType { + t.Errorf("NewSignatureByData(%v, %T) type = %s, want %s", tt.signAlgo, tt.pubKey, gotType, tt.wantType) + } + }) + } + }) +} + +func TestSignatureReadWriteRoundTrip(t *testing.T) { + t.Parallel() + + want := &Signature{ + SigScheme: AlgRSASSA, + Version: 0x10, + HashAlg: AlgSHA256, + Data: []byte{0x10, 0x11, 0x12, 0x13}, + } + want.KeySize.SetInBytes(uint16(len(want.Data))) + + var buf bytes.Buffer + n, err := want.WriteTo(&buf) + if err != nil { + t.Fatalf("Signature.WriteTo() error = %v, want nil", err) + } + if n != int64(want.TotalSize()) { + t.Errorf("Signature.WriteTo() bytes = %d, want %d", n, want.TotalSize()) + } + + var got Signature + n, err = got.ReadFrom(&buf) + if err != nil { + t.Fatalf("Signature.ReadFrom() error = %v, want nil", err) + } + if n != int64(got.TotalSize()) { + t.Errorf("Signature.ReadFrom() bytes = %d, want %d", n, got.TotalSize()) + } + + if got.SigScheme != want.SigScheme { + t.Errorf("Signature round-trip SigScheme = %v, want %v", got.SigScheme, want.SigScheme) + } + if got.KeySize != want.KeySize { + t.Errorf("Signature round-trip KeySize = %v, want %v", got.KeySize, want.KeySize) + } + if !bytes.Equal(got.Data, want.Data) { + t.Errorf("Signature round-trip Data = %v, want %v", got.Data, want.Data) + } +} + +func TestSignatureMethods(t *testing.T) { + t.Parallel() + + s := NewSignature() + if _, err := s.SizeOf(99); err == nil { + t.Errorf("Signature.SizeOf(99) error = nil, want non-nil") + } + if _, err := s.OffsetOf(99); err == nil { + t.Errorf("Signature.OffsetOf(99) error = nil, want non-nil") + } + + if got := len(s.Layout()); got != 5 { + t.Errorf("len(Signature.Layout()) = %d, want %d", got, 5) + } + + var nilSig *Signature + if got := nilSig.TotalSize(); got != 0 { + t.Errorf("(*Signature)(nil).TotalSize() = %d, want %d", got, 0) + } + + pretty := s.PrettyString(0, true) + if !strings.Contains(pretty, "Signature") { + t.Errorf("Signature.PrettyString() = %q, want to contain %q", pretty, "Signature") + } +} + +type unsupportedSignatureData struct{} + +func (unsupportedSignatureData) String() string { return "unsupported" } + +func (unsupportedSignatureData) Verify(pkIface crypto.PublicKey, hashAlgo Algorithm, signedData []byte) error { + return nil +} + +func genRSA(t *testing.T, bits int) *rsa.PrivateKey { + t.Helper() + + key, err := rsa.GenerateKey(rand.Reader, bits) + if err != nil { + t.Fatalf("rsa.GenerateKey(%d) error = %v, want nil", bits, err) + } + + return key +} + +func genECDSA(t *testing.T) *ecdsa.PrivateKey { + t.Helper() + + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("ecdsa.GenerateKey(P256) error = %v, want nil", err) + } + + return key +} + +func bigIntBits(bits int) *big.Int { + b := make([]byte, bits/8) + b[0] = 0x80 + return new(big.Int).SetBytes(b) +} From dd0e59a9e99f9dc8aaefea432a5abd69a0e8941c Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Wed, 22 Apr 2026 11:33:57 +0200 Subject: [PATCH 11/40] feat(intel/metadata): adapt Hash* to use Common shared methods Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/hash.go | 356 +++++++++++++++++- pkg/intel/metadata/cbnt/hash_list_test.go | 147 ++++++++ .../metadata/cbnt/hash_structure_fill_test.go | 137 +++++++ .../metadata/cbnt/hash_structure_test.go | 123 ++++++ 4 files changed, 756 insertions(+), 7 deletions(-) create mode 100644 pkg/intel/metadata/cbnt/hash_list_test.go create mode 100644 pkg/intel/metadata/cbnt/hash_structure_fill_test.go create mode 100644 pkg/intel/metadata/cbnt/hash_structure_test.go diff --git a/pkg/intel/metadata/cbnt/hash.go b/pkg/intel/metadata/cbnt/hash.go index c2f9bc83..eae9844a 100644 --- a/pkg/intel/metadata/cbnt/hash.go +++ b/pkg/intel/metadata/cbnt/hash.go @@ -2,18 +2,360 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:generate manifestcodegen - package cbnt -// HashStructure describes a digest. -type HashStructure struct { - HashAlg Algorithm `default:"0x10" json:"hsAlg"` - HashBuffer []byte `json:"hsBuffer"` -} +import ( + "encoding/binary" + "fmt" + "io" + "strings" + + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) // HashList describes multiple digests type HashList struct { + Common Size uint16 `rehashValue:"TotalSize()" json:"hlSize"` List []HashStructure `json:"hlList"` } + +// NewHashList returns a new instance of HashList with +// all default values set. +func NewHashList() *HashList { + s := &HashList{} + s.Rehash() + return s +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *HashList) Validate() error { + expectedValue := uint16(s.Common.TotalSize(s)) + if s.Size != expectedValue { + return fmt.Errorf("field 'Size' expects write-value '%v', but has %v", expectedValue, s.Size) + } + + return nil +} + +// ReadFrom reads the HashList from 'r' in format defined in the document #575623. +func (s *HashList) ReadFrom(r io.Reader) (int64, error) { + totalN, err := s.Common.ReadFrom(r, s) + if err != nil { + return 0, err + } + + return totalN, nil +} + +// RehashRecursive calls Rehash (see below) recursively. +func (s *HashList) RehashRecursive() { + s.Rehash() +} + +// Rehash sets values which are calculated automatically depending on the rest +// data. It is usually about the total size field of an element. +func (s *HashList) Rehash() { + s.Size = uint16(s.Common.TotalSize(s)) +} + +// WriteTo writes the HashList into 'w' in format defined in +// the document #575623. +func (s *HashList) WriteTo(w io.Writer) (int64, error) { + s.Rehash() + return s.Common.WriteTo(w, s) +} + +func (s *HashList) Layout() []LayoutField { + return []LayoutField{ + { + ID: 0, + Name: "Size", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.Size }, + Type: ManifestFieldEndValue, + }, + { + ID: 1, + Name: fmt.Sprintf("List: Array of \"Hash List\" of length %d", len(s.List)), + Size: func() uint64 { + size := uint64(binary.Size(uint16(0))) + for idx := range s.List { + size += s.List[idx].Common.TotalSize(&s.List[idx]) + } + return size + }, + Value: func() any { return &s.List }, + Type: ManifestFieldList, + // this is basically the logic from ReadFrom of HashList + // for the ManifestFieldType list. Just that now we pass it + // as closure and let generic ReadFrom make use of it. + ReadList: func(r io.Reader) (int64, error) { + var count uint16 + if err := binary.Read(r, endianess, &count); err != nil { + return 0, fmt.Errorf("unable to read the count for field 'List': %w", err) + } + totalN := int64(binary.Size(count)) + + s.List = make([]HashStructure, count) + for idx := range s.List { + n, err := s.List[idx].ReadFrom(r) + if err != nil { + return totalN, fmt.Errorf("unable to read field 'List[%d]': %w", idx, err) + } + totalN += int64(n) + } + return totalN, nil + }, + WriteList: func(w io.Writer) (int64, error) { + count := uint16(len(s.List)) + if err := binary.Write(w, binary.LittleEndian, &count); err != nil { + return 0, fmt.Errorf("unable to write the count for field 'List': %w", err) + } + totalN := int64(binary.Size(count)) + + for idx := range s.List { + n, err := s.List[idx].WriteTo(w) + if err != nil { + return totalN, fmt.Errorf("unable to write field 'List[%d]': %w", idx, err) + } + totalN += int64(n) + } + + return totalN, nil + }, + }, + } +} + +func (s *HashList) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + // normally it would be 0, but ret is already 0 if we land here + return ret, fmt.Errorf("HashList: %v", err) + } + + return ret, nil +} + +func (s *HashList) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("HashList: %v", err) + } + + return ret, nil +} + +// Size returns the total size of the HashList. +func (s *HashList) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *HashList) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + base := Common{}.PrettyString(depth, withHeader, s, "Hash List", opts...) + var lines []string + lines = append(lines, base) + + lines = append(lines, pretty.Header(depth+1, fmt.Sprintf("List: Array of \"Hash List\" of length %d", len(s.List)), s.List)) + for i := 0; i < len(s.List); i++ { + lines = append(lines, fmt.Sprintf("%sitem #%d: ", strings.Repeat(" ", int(depth+2)), i)+strings.TrimSpace(s.List[i].PrettyString(depth+2, true, opts...))) + } + + if depth < 1 { + lines = append(lines, "") + } + + return strings.Join(lines, "\n") +} + +type HashStructure struct { + Common + HashAlg Algorithm `default:"0x10" json:"hsAlg"` + HashBuffer []byte `json:"hsBuffer"` +} + +// NewHashStructure returns a new instance of HashStructure with +// all default values set. +func NewHashStructure(alg Algorithm) *HashStructure { + s := &HashStructure{} + // For bg pkg, the default one + s.HashAlg = alg + return s +} + +// ReadFrom reads the HashStructure from 'r' in format defined in the document #575623. +func (s *HashStructure) ReadFrom(r io.Reader) (int64, error) { + totalN, err := s.Common.ReadFrom(r, s) + if err != nil { + return 0, err + } + + return totalN, nil +} + +// WriteTo writes the HashStructure into 'w' in format defined in +// the document #575623. +func (s *HashStructure) WriteTo(w io.Writer) (int64, error) { + return s.Common.WriteTo(w, s) +} + +func (s *HashStructure) Layout() []LayoutField { + return []LayoutField{ + { + ID: 0, + Name: "Hash Alg", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.HashAlg }, + Type: ManifestFieldEndValue, + }, + { + ID: 1, + Name: "Hash Buffer", + Size: func() uint64 { + h, err := s.HashAlg.Hash() + if err != nil { + return uint64(binary.Size(uint16(0))) + } + return uint64(binary.Size(uint16(0))) + uint64(h.Size()) + }, + Value: func() any { return &s.HashBuffer }, + Type: ManifestFieldArrayDynamicWithPrefix, + }, + } +} + +func (s *HashStructure) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + // normally it would be 0, but ret is already 0 if we land here + return ret, fmt.Errorf("HashStructure: %v", err) + } + + return ret, nil +} + +func (s *HashStructure) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("HashStructure: %v", err) + } + + return ret, nil +} + +func (s *HashStructure) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *HashStructure) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return Common{}.PrettyString(depth, withHeader, s, "Hash Structure", opts...) +} + +// HashStructureFill describes a digest in BG fill format. +// Unlike HashStructure, HashBuffer does not carry a size prefix on the wire. +type HashStructureFill struct { + Common + HashAlg Algorithm `default:"0x0b" json:"hsAlg"` + HashBuffer []byte `json:"hsBuffer"` +} + +// NewHashStructureFill returns a new instance of HashStructureFill with +// all default values set. Note: here only for legacy reasons (i.e. supporting +// BG 1.0). +func NewHashStructureFill(alg Algorithm) *HashStructureFill { + s := &HashStructureFill{} + s.HashAlg = alg + return s +} + +// this little hack here mimics the hack from old bg package +func (s *HashStructureFill) hashBufferSize() uint64 { + const hashSizeFieldLen = 2 + if s.HashAlg.IsNull() { + return 32 + hashSizeFieldLen + } + + h, err := s.HashAlg.Hash() + if err != nil { + return hashSizeFieldLen + } + return uint64((h.Size() + hashSizeFieldLen)) +} + +// ReadFrom reads the HashStructureFill from 'r' in format defined in the document #575623. +func (s *HashStructureFill) ReadFrom(r io.Reader) (int64, error) { + totalN, err := s.Common.ReadFrom(r, s) + if err != nil { + return 0, err + } + + return totalN, nil +} + +// WriteTo writes the HashStructureFill into 'w' in format defined in +// the document #575623. +func (s *HashStructureFill) WriteTo(w io.Writer) (int64, error) { + return s.Common.WriteTo(w, s) +} + +func (s *HashStructureFill) Layout() []LayoutField { + return []LayoutField{ + { + ID: 0, + Name: "Hash Alg", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.HashAlg }, + Type: ManifestFieldEndValue, + }, + { + ID: 1, + Name: "Hash Buffer", + Size: s.hashBufferSize, + Value: func() any { return &s.HashBuffer }, + Type: ManifestFieldArrayDynamicWithSize, + }, + } +} + +func (s *HashStructureFill) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("HashStructureFill: %v", err) + } + + return ret, nil +} + +func (s *HashStructureFill) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("HashStructureFill: %v", err) + } + + return ret, nil +} + +func (s *HashStructureFill) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *HashStructureFill) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return Common{}.PrettyString(depth, withHeader, s, "Hash Structure Fill", opts...) +} diff --git a/pkg/intel/metadata/cbnt/hash_list_test.go b/pkg/intel/metadata/cbnt/hash_list_test.go new file mode 100644 index 00000000..972a76c5 --- /dev/null +++ b/pkg/intel/metadata/cbnt/hash_list_test.go @@ -0,0 +1,147 @@ +// Copyright 2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "bytes" + "strings" + "testing" +) + +func TestHashListNew(t *testing.T) { + t.Parallel() + + h := NewHashList() + if h == nil { + t.Fatal("NewHashList() = nil, want non-nil") + } + if h.Size != 4 { + t.Errorf("NewHashList().Size = %d, want %d", h.Size, 4) + } + if err := h.Validate(); err != nil { + t.Errorf("NewHashList().Validate() error = %v, want nil", err) + } +} + +func TestHashListValidateRejectsInvalidSize(t *testing.T) { + t.Parallel() + + h := NewHashList() + h.Size = 0 + + if err := h.Validate(); err == nil { + t.Errorf("HashList.Validate() error = nil, want non-nil") + } +} + +func TestHashListRehashRecursive(t *testing.T) { + t.Parallel() + + h := &HashList{ + List: []HashStructure{{ + HashAlg: AlgSHA256, + HashBuffer: bytes.Repeat([]byte{0xA5}, 32), + }}, + } + h.RehashRecursive() + + wantSize := uint16(h.TotalSize()) + if h.Size != wantSize { + t.Errorf("HashList.RehashRecursive() Size = %d, want %d", h.Size, wantSize) + } +} + +func TestHashListReadWriteRoundTrip(t *testing.T) { + t.Parallel() + + want := &HashList{ + List: []HashStructure{{ + HashAlg: AlgSHA256, + HashBuffer: bytes.Repeat([]byte{0x5A}, 32), + }}, + } + want.Rehash() + + var buf bytes.Buffer + n, err := want.WriteTo(&buf) + if err != nil { + t.Fatalf("HashList.WriteTo() error = %v, want nil", err) + } + if n != int64(want.TotalSize()) { + t.Errorf("HashList.WriteTo() bytes = %d, want %d", n, want.TotalSize()) + } + + var got HashList + n, err = got.ReadFrom(&buf) + if err != nil { + t.Fatalf("HashList.ReadFrom() error = %v, want nil", err) + } + if n != int64(got.TotalSize()) { + t.Errorf("HashList.ReadFrom() bytes = %d, want %d", n, got.TotalSize()) + } + + if got.Size != want.Size { + t.Errorf("HashList round-trip Size = %d, want %d", got.Size, want.Size) + } + if len(got.List) != len(want.List) { + t.Fatalf("len(HashList round-trip List) = %d, want %d", len(got.List), len(want.List)) + } + if got.List[0].HashAlg != want.List[0].HashAlg { + t.Errorf("HashList round-trip List[0].HashAlg = %v, want %v", got.List[0].HashAlg, want.List[0].HashAlg) + } + if !bytes.Equal(got.List[0].HashBuffer, want.List[0].HashBuffer) { + t.Errorf("HashList round-trip List[0].HashBuffer = %v, want %v", got.List[0].HashBuffer, want.List[0].HashBuffer) + } +} + +func TestHashListSizeOffsetAndTotal(t *testing.T) { + t.Parallel() + + h := &HashList{ + List: []HashStructure{{ + HashAlg: AlgSHA256, + HashBuffer: bytes.Repeat([]byte{0xCC}, 32), + }}, + } + h.Rehash() + + size0, err := h.SizeOf(0) + if err != nil { + t.Fatalf("HashList.SizeOf(0) error = %v, want nil", err) + } + if size0 != 2 { + t.Errorf("HashList.SizeOf(0) = %d, want %d", size0, 2) + } + + offset1, err := h.OffsetOf(1) + if err != nil { + t.Fatalf("HashList.OffsetOf(1) error = %v, want nil", err) + } + if offset1 != 2 { + t.Errorf("HashList.OffsetOf(1) = %d, want %d", offset1, 2) + } + + if _, err := h.SizeOf(99); err == nil { + t.Errorf("HashList.SizeOf(99) error = nil, want non-nil") + } + if _, err := h.OffsetOf(99); err == nil { + t.Errorf("HashList.OffsetOf(99) error = nil, want non-nil") + } + + var nilList *HashList + if got := nilList.TotalSize(); got != 0 { + t.Errorf("(*HashList)(nil).TotalSize() = %d, want %d", got, 0) + } +} + +func TestHashListPrettyString(t *testing.T) { + t.Parallel() + + h := NewHashList() + got := h.PrettyString(0, true) + if !strings.Contains(got, "Hash List") { + t.Errorf("HashList.PrettyString() = %q, want to contain %q", got, "Hash List") + } +} diff --git a/pkg/intel/metadata/cbnt/hash_structure_fill_test.go b/pkg/intel/metadata/cbnt/hash_structure_fill_test.go new file mode 100644 index 00000000..b0bc8b99 --- /dev/null +++ b/pkg/intel/metadata/cbnt/hash_structure_fill_test.go @@ -0,0 +1,137 @@ +// Copyright 2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "bytes" + "strings" + "testing" +) + +func TestHashStructureFillNew(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + alg Algorithm + }{ + "sha384": {alg: AlgSHA384}, + "null": {alg: AlgNull}, + } + + for name, tt := range tests { + name := name + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + + h := NewHashStructureFill(tt.alg) + if h == nil { + t.Fatal("NewHashStructureFill() = nil, want non-nil") + } + if h.HashAlg != tt.alg { + t.Errorf("NewHashStructureFill(%v).HashAlg = %v, want %v", tt.alg, h.HashAlg, tt.alg) + } + }) + } +} + +func TestHashStructureFillHashBufferSizeByAlgorithm(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + alg Algorithm + wantSize uint64 + }{ + "sha256": {alg: AlgSHA256, wantSize: 34}, + "null": {alg: AlgNull, wantSize: 34}, + "unknown": { + alg: AlgRSA, + wantSize: 2, + }, + } + + for name, tt := range tests { + name := name + tt := tt + + t.Run(name, func(t *testing.T) { + t.Parallel() + + h := &HashStructureFill{HashAlg: tt.alg} + size, err := h.SizeOf(1) + if err != nil { + t.Fatalf("HashStructureFill.SizeOf(1) error = %v, want nil", err) + } + if size != tt.wantSize { + t.Errorf("HashStructureFill.SizeOf(1) with alg %v = %d, want %d", tt.alg, size, tt.wantSize) + } + }) + } +} + +func TestHashStructureFillReadWriteRoundTrip(t *testing.T) { + t.Parallel() + + want := &HashStructureFill{ + HashAlg: AlgSHA256, + HashBuffer: bytes.Repeat([]byte{0x33}, 34), + } + + var buf bytes.Buffer + n, err := want.WriteTo(&buf) + if err != nil { + t.Fatalf("HashStructureFill.WriteTo() error = %v, want nil", err) + } + if n != int64(want.TotalSize()) { + t.Errorf("HashStructureFill.WriteTo() bytes = %d, want %d", n, want.TotalSize()) + } + + var got HashStructureFill + n, err = got.ReadFrom(&buf) + if err != nil { + t.Fatalf("HashStructureFill.ReadFrom() error = %v, want nil", err) + } + if n != int64(got.TotalSize()) { + t.Errorf("HashStructureFill.ReadFrom() bytes = %d, want %d", n, got.TotalSize()) + } + + if got.HashAlg != want.HashAlg { + t.Errorf("HashStructureFill round-trip HashAlg = %v, want %v", got.HashAlg, want.HashAlg) + } + if !bytes.Equal(got.HashBuffer, want.HashBuffer) { + t.Errorf("HashStructureFill round-trip HashBuffer = %v, want %v", got.HashBuffer, want.HashBuffer) + } +} + +func TestHashStructureFillMethods(t *testing.T) { + t.Parallel() + + h := &HashStructureFill{HashAlg: AlgSHA256, HashBuffer: bytes.Repeat([]byte{0x10}, 34)} + + offset1, err := h.OffsetOf(1) + if err != nil { + t.Fatalf("HashStructureFill.OffsetOf(1) error = %v, want nil", err) + } + if offset1 != 2 { + t.Errorf("HashStructureFill.OffsetOf(1) = %d, want %d", offset1, 2) + } + + if _, err := h.SizeOf(99); err == nil { + t.Errorf("HashStructureFill.SizeOf(99) error = nil, want non-nil") + } + if _, err := h.OffsetOf(99); err == nil { + t.Errorf("HashStructureFill.OffsetOf(99) error = nil, want non-nil") + } + + var nilHS *HashStructureFill + if got := nilHS.TotalSize(); got != 0 { + t.Errorf("(*HashStructureFill)(nil).TotalSize() = %d, want %d", got, 0) + } + + pretty := h.PrettyString(0, true) + if !strings.Contains(pretty, "Hash Structure Fill") { + t.Errorf("HashStructureFill.PrettyString() = %q, want to contain %q", pretty, "Hash Structure Fill") + } +} diff --git a/pkg/intel/metadata/cbnt/hash_structure_test.go b/pkg/intel/metadata/cbnt/hash_structure_test.go new file mode 100644 index 00000000..9b7a73a7 --- /dev/null +++ b/pkg/intel/metadata/cbnt/hash_structure_test.go @@ -0,0 +1,123 @@ +// Copyright 2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "bytes" + "strings" + "testing" +) + +func TestHashStructureNew(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + alg Algorithm + }{ + "sha256": {alg: AlgSHA256}, + "null": {alg: AlgNull}, + } + + for name, tt := range tests { + name := name + tt := tt + + t.Run(name, func(t *testing.T) { + t.Parallel() + + h := NewHashStructure(tt.alg) + if h == nil { + t.Fatal("NewHashStructure() = nil, want non-nil") + } + if h.HashAlg != tt.alg { + t.Errorf("NewHashStructure(%v).HashAlg = %v, want %v", tt.alg, h.HashAlg, tt.alg) + } + }) + } +} + +func TestHashStructureReadWriteRoundTrip(t *testing.T) { + t.Parallel() + + want := &HashStructure{ + HashAlg: AlgSHA256, + HashBuffer: bytes.Repeat([]byte{0x7C}, 32), + } + + var buf bytes.Buffer + n, err := want.WriteTo(&buf) + if err != nil { + t.Fatalf("HashStructure.WriteTo() error = %v, want nil", err) + } + if n != int64(want.TotalSize()) { + t.Errorf("HashStructure.WriteTo() bytes = %d, want %d", n, want.TotalSize()) + } + + var got HashStructure + n, err = got.ReadFrom(&buf) + if err != nil { + t.Fatalf("HashStructure.ReadFrom() error = %v, want nil", err) + } + if n != int64(got.TotalSize()) { + t.Errorf("HashStructure.ReadFrom() bytes = %d, want %d", n, got.TotalSize()) + } + + if got.HashAlg != want.HashAlg { + t.Errorf("HashStructure round-trip HashAlg = %v, want %v", got.HashAlg, want.HashAlg) + } + if !bytes.Equal(got.HashBuffer, want.HashBuffer) { + t.Errorf("HashStructure round-trip HashBuffer = %v, want %v", got.HashBuffer, want.HashBuffer) + } +} + +func TestHashStructureMethods(t *testing.T) { + t.Parallel() + + h := &HashStructure{ + HashAlg: AlgSHA256, + HashBuffer: bytes.Repeat([]byte{0x22}, 32), + } + + size0, err := h.SizeOf(0) + if err != nil { + t.Fatalf("HashStructure.SizeOf(0) error = %v, want nil", err) + } + if size0 != 2 { + t.Errorf("HashStructure.SizeOf(0) = %d, want %d", size0, 2) + } + + size1, err := h.SizeOf(1) + if err != nil { + t.Fatalf("HashStructure.SizeOf(1) error = %v, want nil", err) + } + if size1 != 34 { + t.Errorf("HashStructure.SizeOf(1) = %d, want %d", size1, 34) + } + + offset1, err := h.OffsetOf(1) + if err != nil { + t.Fatalf("HashStructure.OffsetOf(1) error = %v, want nil", err) + } + if offset1 != 2 { + t.Errorf("HashStructure.OffsetOf(1) = %d, want %d", offset1, 2) + } + + if _, err := h.SizeOf(99); err == nil { + t.Errorf("HashStructure.SizeOf(99) error = nil, want non-nil") + } + if _, err := h.OffsetOf(99); err == nil { + t.Errorf("HashStructure.OffsetOf(99) error = nil, want non-nil") + } + + var nilHS *HashStructure + if got := nilHS.TotalSize(); got != 0 { + t.Errorf("(*HashStructure)(nil).TotalSize() = %d, want %d", got, 0) + } + + pretty := h.PrettyString(0, true) + if !strings.Contains(pretty, "Hash Structure") { + t.Errorf("HashStructure.PrettyString() = %q, want to contain %q", pretty, "Hash Structure") + } +} From 2758061fc0197ee955d5df4cabf97d05fad406b3 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Wed, 22 Apr 2026 11:38:23 +0200 Subject: [PATCH 12/40] chore(intel/metadata): adapt Algorithm methods and add tests Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/crypto_routines.go | 49 +++-- .../metadata/cbnt/crypto_routines_test.go | 197 ++++++++++++++++++ 2 files changed, 223 insertions(+), 23 deletions(-) create mode 100644 pkg/intel/metadata/cbnt/crypto_routines_test.go diff --git a/pkg/intel/metadata/cbnt/crypto_routines.go b/pkg/intel/metadata/cbnt/crypto_routines.go index c97fd196..487502eb 100644 --- a/pkg/intel/metadata/cbnt/crypto_routines.go +++ b/pkg/intel/metadata/cbnt/crypto_routines.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:generate manifestcodegen - package cbnt import ( @@ -12,33 +10,16 @@ import ( _ "crypto/sha1" _ "crypto/sha256" _ "crypto/sha512" + "encoding/binary" "fmt" "hash" + "io" "strings" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" "github.com/tjfoc/gmsm/sm3" ) -// Algorithm represents a crypto algorithm value. -type Algorithm uint16 - -// Supported algorithms -const ( - AlgUnknown Algorithm = 0x0000 - AlgRSA Algorithm = 0x0001 - AlgSHA1 Algorithm = 0x0004 - AlgSHA256 Algorithm = 0x000B - AlgSHA384 Algorithm = 0x000C - AlgSHA512 Algorithm = 0x000D - AlgNull Algorithm = 0x0010 - AlgSM3 Algorithm = 0x0012 - AlgRSASSA Algorithm = 0x0014 - AlgRSAPSS Algorithm = 0x0016 - AlgECDSA Algorithm = 0x0018 - AlgSM2 Algorithm = 0x001b - AlgECC Algorithm = 0x0023 -) - var hashInfo = []struct { alg Algorithm hashFactory func() hash.Hash @@ -50,6 +31,8 @@ var hashInfo = []struct { {AlgSM3, sm3.New}, } +type Algorithm uint16 + // IsNull returns true if a is AlgNull or zero (unset). func (a Algorithm) IsNull() bool { return a == AlgNull || a == AlgUnknown @@ -86,7 +69,7 @@ func (a Algorithm) String() string { case AlgSHA512: _, err = s.WriteString("SHA512") case AlgSM3: - _, err = s.WriteString("SM3_256") + _, err = s.WriteString("SM3") case AlgNull: _, err = s.WriteString("AlgNull") case AlgRSASSA: @@ -139,3 +122,23 @@ func GetAlgFromString(name string) (Algorithm, error) { return AlgNull, fmt.Errorf("algorithm name provided unknown") } } + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (a Algorithm) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return a.String() +} + +// TotalSize returns the total size measured through binary.Size. +func (a Algorithm) TotalSize() uint64 { + return uint64(binary.Size(a)) +} + +// WriteTo writes the Algorithm into 'w' in binary format. +func (a Algorithm) WriteTo(w io.Writer) (int64, error) { + return int64(a.TotalSize()), binary.Write(w, binary.LittleEndian, a) +} + +// ReadFrom reads the Algorithm from 'r' in binary format. +func (a *Algorithm) ReadFrom(r io.Reader) (int64, error) { + return int64(a.TotalSize()), binary.Read(r, binary.LittleEndian, a) +} diff --git a/pkg/intel/metadata/cbnt/crypto_routines_test.go b/pkg/intel/metadata/cbnt/crypto_routines_test.go new file mode 100644 index 00000000..44f246a4 --- /dev/null +++ b/pkg/intel/metadata/cbnt/crypto_routines_test.go @@ -0,0 +1,197 @@ +// Copyright 2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "bytes" + "strings" + "testing" +) + +func TestAlgorithmIsNull(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + alg Algorithm + want bool + }{ + "unknown": {alg: AlgUnknown, want: true}, + "null": {alg: AlgNull, want: true}, + "sha256": {alg: AlgSHA256, want: false}, + } + + for name, tt := range tests { + name := name + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + if got := tt.alg.IsNull(); got != tt.want { + t.Errorf("Algorithm(%v).IsNull() = %v, want %v", tt.alg, got, tt.want) + } + }) + } +} + +func TestAlgorithmHash(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + alg Algorithm + wantSize int + wantErr bool + }{ + "sha1": {alg: AlgSHA1, wantSize: 20}, + "sha256": {alg: AlgSHA256, wantSize: 32}, + "sha384": {alg: AlgSHA384, wantSize: 48}, + "sha512": {alg: AlgSHA512, wantSize: 64}, + "sm3": {alg: AlgSM3, wantSize: 32}, + "non_hash": {alg: AlgRSA, wantErr: true}, + } + + for name, tt := range tests { + name := name + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + + h, err := tt.alg.Hash() + if tt.wantErr { + if err == nil { + t.Errorf("Algorithm(%v).Hash() error = nil, want non-nil", tt.alg) + } + return + } + + if err != nil { + t.Fatalf("Algorithm(%v).Hash() error = %v, want nil", tt.alg, err) + } + if got := h.Size(); got != tt.wantSize { + t.Errorf("Algorithm(%v).Hash().Size() = %d, want %d", tt.alg, got, tt.wantSize) + } + }) + } +} + +func TestAlgorithmString(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + alg Algorithm + want string + }{ + "unknown_alg": {alg: AlgUnknown, want: "AlgUnknown"}, + "rsa": {alg: AlgRSA, want: "RSA"}, + "sha1": {alg: AlgSHA1, want: "SHA1"}, + "sha256": {alg: AlgSHA256, want: "SHA256"}, + "sha384": {alg: AlgSHA384, want: "SHA384"}, + "sha512": {alg: AlgSHA512, want: "SHA512"}, + "sm3": {alg: AlgSM3, want: "SM3"}, + "alg_null": {alg: AlgNull, want: "AlgNull"}, + "rsassa": {alg: AlgRSASSA, want: "RSASSA"}, + "rsapss": {alg: AlgRSAPSS, want: "RSAPSS"}, + "ecdsa": {alg: AlgECDSA, want: "ECDSA"}, + "ecc": {alg: AlgECC, want: "ECC"}, + "sm2": {alg: AlgSM2, want: "SM2"}, + "fallback": {alg: Algorithm(0xFFFF), want: "Alg?<65535>"}, + } + + for name, tt := range tests { + name := name + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + + if got := tt.alg.String(); got != tt.want { + t.Errorf("Algorithm(%d).String() = %q, want %q", tt.alg, got, tt.want) + } + }) + } +} + +func TestGetAlgFromString(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + in string + want Algorithm + wantErr bool + }{ + "algunknown": {in: "AlgUnknown", want: AlgUnknown}, + "rsa": {in: "rsa", want: AlgRSA}, + "sha1": {in: "SHA1", want: AlgSHA1}, + "sha256": {in: "sha256", want: AlgSHA256}, + "sha384": {in: "SHA384", want: AlgSHA384}, + "sm3": {in: "sm3", want: AlgSM3}, + "algnull": {in: "AlgNull", want: AlgNull}, + "rsassa": {in: "RSASSA", want: AlgRSASSA}, + "rsapss": {in: "rsapss", want: AlgRSAPSS}, + "ecdsa": {in: "ECDSA", want: AlgECDSA}, + "ecc": {in: "ecc", want: AlgECC}, + "sm2": {in: "SM2", want: AlgSM2}, + "bad": {in: "invalid-algo", want: AlgNull, wantErr: true}, + } + + for name, tt := range tests { + name := name + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + + got, err := GetAlgFromString(tt.in) + if tt.wantErr { + if err == nil { + t.Errorf("GetAlgFromString(%q) error = nil, want non-nil", tt.in) + } + } else if err != nil { + t.Fatalf("GetAlgFromString(%q) error = %v, want nil", tt.in, err) + } + + if got != tt.want { + t.Errorf("GetAlgFromString(%q) = %v, want %v", tt.in, got, tt.want) + } + }) + } +} + +func TestAlgorithmPrettyStringTotalSizeAndRW(t *testing.T) { + t.Parallel() + + a := AlgSHA256 + if got, want := a.PrettyString(0, true), a.String(); got != want { + t.Errorf("Algorithm.PrettyString() = %q, want %q", got, want) + } + + if got := a.TotalSize(); got != 2 { + t.Errorf("Algorithm.TotalSize() = %d, want %d", got, 2) + } + + var buf bytes.Buffer + n, err := a.WriteTo(&buf) + if err != nil { + t.Fatalf("Algorithm.WriteTo() error = %v, want nil", err) + } + if n != int64(a.TotalSize()) { + t.Errorf("Algorithm.WriteTo() bytes = %d, want %d", n, a.TotalSize()) + } + + var got Algorithm + n, err = (&got).ReadFrom(&buf) + if err != nil { + t.Fatalf("Algorithm.ReadFrom() error = %v, want nil", err) + } + if n != int64(got.TotalSize()) { + t.Errorf("Algorithm.ReadFrom() bytes = %d, want %d", n, got.TotalSize()) + } + if got != a { + t.Errorf("Algorithm round-trip = %v, want %v", got, a) + } + + _, err = (&got).ReadFrom(bytes.NewBuffer([]byte{0x01})) + if err == nil { + t.Errorf("Algorithm.ReadFrom(short input) error = nil, want non-nil") + } else if !strings.Contains(err.Error(), "unexpected EOF") { + t.Errorf("Algorithm.ReadFrom(short input) error = %q, want to contain %q", err.Error(), "unexpected EOF") + } +} From e239fc5d3661ab08b9e928c2bc137e8966917c40 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 11:54:50 +0200 Subject: [PATCH 13/40] feat(intel/metadata): adapt KeySignature to use Common shared methods Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/key_signature.go | 110 ++++++++++++- pkg/intel/metadata/cbnt/key_signature_test.go | 147 ++++++++++++++++++ 2 files changed, 253 insertions(+), 4 deletions(-) create mode 100644 pkg/intel/metadata/cbnt/key_signature_test.go diff --git a/pkg/intel/metadata/cbnt/key_signature.go b/pkg/intel/metadata/cbnt/key_signature.go index baf4967b..01b9b6aa 100644 --- a/pkg/intel/metadata/cbnt/key_signature.go +++ b/pkg/intel/metadata/cbnt/key_signature.go @@ -1,18 +1,19 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:generate manifestcodegen - package cbnt import ( "crypto" "fmt" + "io" + + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" ) -// KeySignature combines a public key and a signature in a single structure. type KeySignature struct { + Common Version uint8 `require:"0x10" json:"ksVersion,omitempty"` Key Key `json:"ksKey"` Signature Signature `json:"ksSignature"` @@ -79,3 +80,104 @@ func (s *KeySignature) FillSignature(signAlgo Algorithm, pubKey crypto.PublicKey return s.Signature.FillSignature(signAlgo, pubKey, signedData, hashAlgo) } + +// NewKeySignature returns a new instance of KeySignature with +// all default values set. +func NewKeySignature() *KeySignature { + s := &KeySignature{} + // Set through tag "required": + s.Version = 0x10 + // Recursively initializing a child structure: + s.Key = *NewKey() + // Recursively initializing a child structure: + s.Signature = *NewSignature() + return s +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *KeySignature) Validate() error { + // See tag "require" + if s.Version != 0x10 { + return fmt.Errorf("field 'Version' expects value '0x10', but has %v", s.Version) + } + // Recursively validating a child structure: + if err := s.Key.Validate(); err != nil { + return fmt.Errorf("error on field 'Key': %w", err) + } + // Recursively validating a child structure: + if err := s.Signature.Validate(); err != nil { + return fmt.Errorf("error on field 'Signature': %w", err) + } + + return nil +} + +// ReadFrom reads the KeySignature from 'r' in format defined in the document #575623. +func (s *KeySignature) ReadFrom(r io.Reader) (int64, error) { + return s.Common.ReadFrom(r, s) +} + +// WriteTo writes the KeySignature into 'w' in format defined in +// the document #575623. +func (s *KeySignature) WriteTo(w io.Writer) (int64, error) { + return s.Common.WriteTo(w, s) +} + +func (s *KeySignature) Layout() []LayoutField { + return []LayoutField{ + { + ID: 0, + Name: "Version", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Version }, + Type: ManifestFieldEndValue, + }, + { + ID: 1, + Name: "Key", + Size: func() uint64 { return s.Key.Common.TotalSize(&s.Key) }, + Value: func() any { return &s.Key }, + Type: ManifestFieldSubStruct, + }, + { + ID: 2, + Name: "Signature", + Size: func() uint64 { return s.Signature.Common.TotalSize(&s.Signature) }, + Value: func() any { return &s.Signature }, + Type: ManifestFieldSubStruct, + }, + } +} + +func (s *KeySignature) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("HashList: %v", err) + } + + return ret, nil +} + +func (s *KeySignature) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("HashList: %v", err) + } + + return ret, nil +} + +// Size returns the total size of the KeySignature. +func (s *KeySignature) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *KeySignature) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return Common{}.PrettyString(depth, withHeader, s, "Key Signature", opts...) +} diff --git a/pkg/intel/metadata/cbnt/key_signature_test.go b/pkg/intel/metadata/cbnt/key_signature_test.go new file mode 100644 index 00000000..fcadd038 --- /dev/null +++ b/pkg/intel/metadata/cbnt/key_signature_test.go @@ -0,0 +1,147 @@ +// Copyright 2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "strings" + "testing" +) + +func TestKeySignatureNew(t *testing.T) { + t.Parallel() + + ks := NewKeySignature() + if ks == nil { + t.Fatal("NewKeySignature() = nil, want non-nil") + } + if ks.Version != 0x10 { + t.Errorf("NewKeySignature().Version = 0x%x, want 0x10", ks.Version) + } + if ks.Key.Version != 0x10 { + t.Errorf("NewKeySignature().Key.Version = 0x%x, want 0x10", ks.Key.Version) + } + if ks.Signature.Version != 0x10 { + t.Errorf("NewKeySignature().Signature.Version = 0x%x, want 0x10", ks.Signature.Version) + } + if err := ks.Validate(); err != nil { + t.Errorf("NewKeySignature().Validate() error = %v, want nil", err) + } +} + +func TestKeySignatureSetSignatureAuto(t *testing.T) { + key, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatalf("rsa.GenerateKey() error = %v, want nil", err) + } + + payload := []byte("key-signature-auto") + ks := NewKeySignature() + if err := ks.SetSignatureAuto(key, payload); err == nil { + t.Errorf("KeySignature.SetSignatureAuto() error = nil, want non-nil") + } +} + +func TestKeySignatureSetSignatureAndFillSignature(t *testing.T) { + key, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatalf("rsa.GenerateKey() error = %v, want nil", err) + } + + payload := []byte("key-signature-manual") + + ksSet := NewKeySignature() + if err := ksSet.SetSignature(AlgRSASSA, AlgSHA256, key, payload); err != nil { + t.Fatalf("KeySignature.SetSignature() error = %v, want nil", err) + } + if err := ksSet.Verify(payload); err != nil { + t.Errorf("KeySignature.Verify() after SetSignature error = %v, want nil", err) + } + + sigData, err := NewSignatureData(AlgRSASSA, key, payload) + if err != nil { + t.Fatalf("NewSignatureData() error = %v, want nil", err) + } + rawSig, ok := sigData.(SignatureRSAASA) + if !ok { + t.Fatalf("NewSignatureData() type = %T, want %T", sigData, SignatureRSAASA(nil)) + } + + ksFill := NewKeySignature() + if err := ksFill.FillSignature(AlgRSASSA, &key.PublicKey, []byte(rawSig), AlgSHA256); err != nil { + t.Fatalf("KeySignature.FillSignature() error = %v, want nil", err) + } + if err := ksFill.Verify(payload); err != nil { + t.Errorf("KeySignature.Verify() after FillSignature error = %v, want nil", err) + } +} + +func TestKeySignatureReadWriteRoundTrip(t *testing.T) { + key, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatalf("rsa.GenerateKey() error = %v, want nil", err) + } + + want := NewKeySignature() + if err := want.SetSignature(AlgRSASSA, AlgSHA256, key, []byte("round-trip")); err != nil { + t.Fatalf("KeySignature.SetSignature() error = %v, want nil", err) + } + + var buf bytes.Buffer + n, err := want.WriteTo(&buf) + if err != nil { + t.Fatalf("KeySignature.WriteTo() error = %v, want nil", err) + } + if n != int64(want.TotalSize()) { + t.Errorf("KeySignature.WriteTo() bytes = %d, want %d", n, want.TotalSize()) + } + + var got KeySignature + n, err = got.ReadFrom(&buf) + if err != nil { + t.Fatalf("KeySignature.ReadFrom() error = %v, want nil", err) + } + if n != int64(got.TotalSize()) { + t.Errorf("KeySignature.ReadFrom() bytes = %d, want %d", n, got.TotalSize()) + } + + if got.Version != want.Version { + t.Errorf("KeySignature round-trip Version = 0x%x, want 0x%x", got.Version, want.Version) + } + if got.Key.KeyAlg != want.Key.KeyAlg { + t.Errorf("KeySignature round-trip KeyAlg = %v, want %v", got.Key.KeyAlg, want.Key.KeyAlg) + } + if got.Signature.SigScheme != want.Signature.SigScheme { + t.Errorf("KeySignature round-trip SigScheme = %v, want %v", got.Signature.SigScheme, want.Signature.SigScheme) + } +} + +func TestKeySignatureMethods(t *testing.T) { + t.Parallel() + + ks := NewKeySignature() + if _, err := ks.SizeOf(99); err == nil { + t.Errorf("KeySignature.SizeOf(99) error = nil, want non-nil") + } + if _, err := ks.OffsetOf(99); err == nil { + t.Errorf("KeySignature.OffsetOf(99) error = nil, want non-nil") + } + + if got := len(ks.Layout()); got != 3 { + t.Errorf("len(KeySignature.Layout()) = %d, want %d", got, 3) + } + + var nilKS *KeySignature + if got := nilKS.TotalSize(); got != 0 { + t.Errorf("(*KeySignature)(nil).TotalSize() = %d, want %d", got, 0) + } + + pretty := ks.PrettyString(0, true) + if !strings.Contains(pretty, "Key Signature") { + t.Errorf("KeySignature.PrettyString() = %q, want to contain %q", pretty, "Key Signature") + } +} From c15c52b09f1b0a9ed4d94de54de99fbfb4df0a5c Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 12:02:43 +0200 Subject: [PATCH 14/40] chore(intel/metadata): add unit tests for signature_types Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/signature_types.go | 6 +- .../metadata/cbnt/signature_types_test.go | 163 ++++++++++++++++++ 2 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 pkg/intel/metadata/cbnt/signature_types_test.go diff --git a/pkg/intel/metadata/cbnt/signature_types.go b/pkg/intel/metadata/cbnt/signature_types.go index 6ac96134..a790bb39 100644 --- a/pkg/intel/metadata/cbnt/signature_types.go +++ b/pkg/intel/metadata/cbnt/signature_types.go @@ -7,6 +7,7 @@ package cbnt import ( "crypto" "crypto/ecdsa" + "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/sha512" @@ -17,7 +18,10 @@ import ( "github.com/tjfoc/gmsm/sm2" ) -var sm2UID = []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38} +var ( + sm2UID = []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38} + RandReader = rand.Reader +) // NewSignatureData returns an implementation of SignatureDataInterface, // accordingly to signAlgo, privKey and signedData. diff --git a/pkg/intel/metadata/cbnt/signature_types_test.go b/pkg/intel/metadata/cbnt/signature_types_test.go new file mode 100644 index 00000000..23df6ebf --- /dev/null +++ b/pkg/intel/metadata/cbnt/signature_types_test.go @@ -0,0 +1,163 @@ +// Copyright 2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/sha512" + "fmt" + "math/big" + "strings" + "testing" +) + +func TestSignatureRSAStringAndVerify(t *testing.T) { + tests := []struct { + name string + buildFunc func(*testing.T, *rsa.PrivateKey, []byte) ([]byte, SignatureDataInterface) + okHash Algorithm + badHash Algorithm + }{ + { + name: "RSAPSS", + buildFunc: func(t *testing.T, key *rsa.PrivateKey, data []byte) ([]byte, SignatureDataInterface) { + t.Helper() + h := sha512.New384() + if _, err := h.Write(data); err != nil { + t.Fatalf("hash.Write() error = %v, want nil", err) + } + digest := h.Sum(nil) + rawSig, err := rsa.SignPSS(rand.Reader, key, crypto.SHA384, digest, &rsa.PSSOptions{ + SaltLength: rsa.PSSSaltLengthAuto, + Hash: crypto.SHA384, + }) + if err != nil { + t.Fatalf("rsa.SignPSS() error = %v, want nil", err) + } + return rawSig, SignatureRSAPSS(rawSig) + }, + okHash: AlgSHA384, + badHash: AlgSHA512, + }, + { + name: "RSAASA", + buildFunc: func(t *testing.T, key *rsa.PrivateKey, data []byte) ([]byte, SignatureDataInterface) { + t.Helper() + h := sha256.New() + if _, err := h.Write(data); err != nil { + t.Fatalf("hash.Write() error = %v, want nil", err) + } + digest := h.Sum(nil) + rawSig, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, digest) + if err != nil { + t.Fatalf("rsa.SignPKCS1v15() error = %v, want nil", err) + } + return rawSig, SignatureRSAASA(rawSig) + }, + okHash: AlgSHA256, + badHash: AlgSHA512, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + key, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatalf("rsa.GenerateKey() error = %v, want nil", err) + } + + wrongKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("ecdsa.GenerateKey() error = %v, want nil", err) + } + + data := []byte(strings.ToLower(tt.name) + "-signature-data") + rawSig, sig := tt.buildFunc(t, key, data) + + if got, want := sig.String(), fmt.Sprintf("0x%X", rawSig); got != want { + t.Errorf("%s.String() = %q, want %q", tt.name, got, want) + } + + verifyTests := []struct { + name string + pk crypto.PublicKey + hash Algorithm + msg []byte + wantErr bool + }{ + {name: "valid", pk: &key.PublicKey, hash: tt.okHash, msg: data, wantErr: false}, + {name: "unsupported_hash", pk: &key.PublicKey, hash: tt.badHash, msg: data, wantErr: true}, + {name: "wrong_key_type", pk: &wrongKey.PublicKey, hash: tt.okHash, msg: data, wantErr: true}, + {name: "tampered_data", pk: &key.PublicKey, hash: tt.okHash, msg: []byte("tampered"), wantErr: true}, + } + + for _, vt := range verifyTests { + vt := vt + t.Run(vt.name, func(t *testing.T) { + err := sig.Verify(vt.pk, vt.hash, vt.msg) + if vt.wantErr { + if err == nil { + t.Errorf("%s.Verify(%s) error = nil, want non-nil", tt.name, vt.name) + } + } else if err != nil { + t.Errorf("%s.Verify(%s) error = %v, want nil", tt.name, vt.name, err) + } + }) + } + }) + } +} + +func TestSignatureNonRSAStringAndVerify(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + sig SignatureDataInterface + hash Algorithm + wantString string + errSubstring string + }{ + { + name: "ECDSA", + sig: SignatureECDSA{R: big.NewInt(0x12), S: big.NewInt(0xAB)}, + hash: AlgSHA256, + wantString: "{R: 0x12, S: 0xAB}", + errSubstring: "not implemented", + }, + { + name: "SM2", + sig: SignatureSM2{R: big.NewInt(0x34), S: big.NewInt(0xCD)}, + hash: AlgSM3, + wantString: "{R: 0x34, S: 0xCD}", + errSubstring: "not implemented", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.sig.String(); got != tt.wantString { + t.Errorf("%s.String() = %q, want %q", tt.name, got, tt.wantString) + } + + err := tt.sig.Verify(nil, tt.hash, []byte("data")) + if err == nil { + t.Fatalf("%s.Verify() error = nil, want non-nil", tt.name) + } + if !strings.Contains(err.Error(), tt.errSubstring) { + t.Errorf("%s.Verify() error = %q, want substring %q", tt.name, err.Error(), tt.errSubstring) + } + }) + } +} From 88ae7a6c6ce93b7315536d7f771a1e1872e0c562 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 12:04:59 +0200 Subject: [PATCH 15/40] feat(intel/metadata): adapt TPM related structs to use Common methods Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/tpm_info_list.go | 271 +++++++++++++++--- pkg/intel/metadata/cbnt/tpm_info_list_test.go | 245 ++++++++++++++++ 2 files changed, 484 insertions(+), 32 deletions(-) create mode 100644 pkg/intel/metadata/cbnt/tpm_info_list_test.go diff --git a/pkg/intel/metadata/cbnt/tpm_info_list.go b/pkg/intel/metadata/cbnt/tpm_info_list.go index 9456fc7a..83a5f311 100644 --- a/pkg/intel/metadata/cbnt/tpm_info_list.go +++ b/pkg/intel/metadata/cbnt/tpm_info_list.go @@ -1,44 +1,168 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:generate manifestcodegen - package cbnt -// TPM2PCRExtendPolicySupport defined TPM2 PCR Extend policy support. -type TPM2PCRExtendPolicySupport uint8 +import ( + "encoding/binary" + "fmt" + "io" + "strings" -// Possible values of TPM2PCRExtendPolicySupport -const ( - TPM2PCRExtendIllegal TPM2PCRExtendPolicySupport = 0 - TPM2PCRExtendMaximumAgilityPolicy TPM2PCRExtendPolicySupport = 1 - TPM2PCRExtendMaximumPerformancePolicy TPM2PCRExtendPolicySupport = 2 - TPM2PCRExtendBothPolicies TPM2PCRExtendPolicySupport = 3 + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" ) -// TPMFamilySupport defines TPM family support -type TPMFamilySupport uint8 +// TPMInfoList represents TPM capabilities supported by ACM +type TPMInfoList struct { + Common + Capabilities TPMCapabilities + Algorithms []Algorithm +} -// IsDiscreteTPM12Supported returns true if discrete TPM1.2 is supported. -// PrettyString-true: Discrete TPM1.2 is supported -// PrettyString-false: Discrete TPM1.2 is not supported -func (familySupport TPMFamilySupport) IsDiscreteTPM12Supported() bool { - return familySupport&1 != 0 +// NewTPMInfoList returns a new instance of TPMInfoList with +// all default values set. +func NewTPMInfoList() *TPMInfoList { + s := &TPMInfoList{} + return s } -// IsDiscreteTPM20Supported returns true if discrete TPM2.0 is supported. -// PrettyString-true: Discrete TPM2.0 is supported -// PrettyString-false: Discrete TPM2.0 is not supported -func (familySupport TPMFamilySupport) IsDiscreteTPM20Supported() bool { - return familySupport&2 != 0 +// ReadFrom reads the TPMInfoList from 'r' in format defined in the document #575623. +func (s *TPMInfoList) ReadFrom(r io.Reader) (int64, error) { + totalN, err := s.Common.ReadFrom(r, s) + if err != nil { + return 0, err + } + + return totalN, nil } -// IsFirmwareTPM20Supported returns true if firmware TPM2.0 is supported. -// PrettyString-true: Firmware TPM2.0 is supported -// PrettyString-false: Firmware TPM2.0 is not supported -func (familySupport TPMFamilySupport) IsFirmwareTPM20Supported() bool { - return familySupport&(1<<3) != 0 +// WriteTo writes the TPMInfoList into 'w' in format defined in +// the document #575623. +func (s *TPMInfoList) WriteTo(w io.Writer) (int64, error) { + return s.Common.WriteTo(w, s) +} + +func (s *TPMInfoList) Layout() []LayoutField { + return []LayoutField{ + { + ID: 0, + Name: "Capabilities", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.Capabilities }, + Type: ManifestFieldEndValue, + }, + { + ID: 1, + Name: fmt.Sprintf("Algorithms: Array of \"TPM Info List\" of length %d", len(s.Algorithms)), + Size: func() uint64 { + size := uint64(binary.Size(uint16(0))) + for idx := range s.Algorithms { + size += s.Algorithms[idx].TotalSize() + } + return size + }, + Value: func() any { return &s.Algorithms }, + Type: ManifestFieldList, + ReadList: func(r io.Reader) (int64, error) { + var count uint16 + err := binary.Read(r, binary.LittleEndian, &count) + if err != nil { + return 0, fmt.Errorf("unable to read the count for field 'Algorithms': %w", err) + } + totalN := int64(binary.Size(count)) + s.Algorithms = make([]Algorithm, count) + + for idx := range s.Algorithms { + n, err := s.Algorithms[idx].ReadFrom(r) + if err != nil { + return totalN, fmt.Errorf("unable to read field 'Algorithms[%d]': %w", idx, err) + } + totalN += int64(n) + } + return totalN, nil + }, + WriteList: func(w io.Writer) (int64, error) { + count := uint16(len(s.Algorithms)) + if err := binary.Write(w, binary.LittleEndian, &count); err != nil { + return 0, fmt.Errorf("unable to write the count for field 'Algorithms': %w", err) + } + totalN := int64(binary.Size(count)) + + for idx := range s.Algorithms { + n, err := s.Algorithms[idx].WriteTo(w) + if err != nil { + return totalN, fmt.Errorf("unable to write field 'Algorithms[%d]': %w", idx, err) + } + totalN += int64(n) + } + + return totalN, nil + }, + }, + } +} + +func (s *TPMInfoList) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("HashList: %v", err) + } + + return ret, nil +} + +func (s *TPMInfoList) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("HashList: %v", err) + } + + return ret, nil +} + +func (s *TPMInfoList) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *TPMInfoList) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + result := Common{}.PrettyString(depth, withHeader, s, "TPM Info List", opts...) + if depth < 1 { + return result + "\n" + } + return result +} + +// TPM2PCRExtendPolicySupport defined TPM2 PCR Extend policy support. +type TPM2PCRExtendPolicySupport uint8 + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (v TPM2PCRExtendPolicySupport) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + var lines []string + if withHeader { + lines = append(lines, pretty.Header(depth, "TPM 2 PCR Extend Policy Support", v)) + } + return strings.Join(lines, "\n") +} + +// TotalSize returns the total size measured through binary.Size. +func (v TPM2PCRExtendPolicySupport) TotalSize() uint64 { + return uint64(binary.Size(v)) +} + +// WriteTo writes the TPM2PCRExtendPolicySupport into 'w' in binary format. +func (v TPM2PCRExtendPolicySupport) WriteTo(w io.Writer) (int64, error) { + return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) +} + +// ReadFrom reads the TPM2PCRExtendPolicySupport from 'r' in binary format. +func (v TPM2PCRExtendPolicySupport) ReadFrom(r io.Reader) (int64, error) { + return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) } // TPMCapabilities defines TPM capabilities @@ -54,8 +178,91 @@ func (cap TPMCapabilities) TPMFamilySupport() TPMFamilySupport { return TPMFamilySupport((cap >> 2) & 15) } -// TPMInfoList represents TPM capabilities supported by ACM -type TPMInfoList struct { - Capabilities TPMCapabilities - Algorithms []Algorithm +// PrettyString returns the bits of the flags in an easy-to-read format. +func (cap TPMCapabilities) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + var lines []string + if withHeader { + lines = append(lines, pretty.Header(depth, "TPM Capabilities", cap)) + } + lines = append(lines, pretty.SubValue(depth+1, "TPM 2 PCR Extend Policy Support", "", cap.TPM2PCRExtendPolicySupport(), opts...)...) + lines = append(lines, pretty.SubValue(depth+1, "TPM Family Support", "", cap.TPMFamilySupport(), opts...)...) + return strings.Join(lines, "\n") +} + +// TotalSize returns the total size measured through binary.Size. +func (cap TPMCapabilities) TotalSize() uint64 { + return uint64(binary.Size(cap)) +} + +// WriteTo writes the TPMCapabilities into 'w' in binary format. +func (cap TPMCapabilities) WriteTo(w io.Writer) (int64, error) { + return int64(cap.TotalSize()), binary.Write(w, binary.LittleEndian, cap) +} + +// ReadFrom reads the TPMCapabilities from 'r' in binary format. +func (cap TPMCapabilities) ReadFrom(r io.Reader) (int64, error) { + return int64(cap.TotalSize()), binary.Read(r, binary.LittleEndian, cap) +} + +// TPMFamilySupport defines TPM family support +type TPMFamilySupport uint8 + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (v TPMFamilySupport) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + var lines []string + if withHeader { + lines = append(lines, pretty.Header(depth, "TPM Family Support", v)) + } + if v.IsDiscreteTPM12Supported() { + lines = append(lines, pretty.SubValue(depth+1, "Is Discrete TPM 12 Supported", "Discrete TPM1.2 is supported", true, opts...)...) + } else { + lines = append(lines, pretty.SubValue(depth+1, "Is Discrete TPM 12 Supported", "Discrete TPM1.2 is not supported", false, opts...)...) + } + if v.IsDiscreteTPM20Supported() { + lines = append(lines, pretty.SubValue(depth+1, "Is Discrete TPM 20 Supported", "Discrete TPM2.0 is supported", true, opts...)...) + } else { + lines = append(lines, pretty.SubValue(depth+1, "Is Discrete TPM 20 Supported", "Discrete TPM2.0 is not supported", false, opts...)...) + } + if v.IsFirmwareTPM20Supported() { + lines = append(lines, pretty.SubValue(depth+1, "Is Firmware TPM 20 Supported", "Firmware TPM2.0 is supported", true, opts...)...) + } else { + lines = append(lines, pretty.SubValue(depth+1, "Is Firmware TPM 20 Supported", "Firmware TPM2.0 is not supported", false, opts...)...) + } + return strings.Join(lines, "\n") +} + +// TotalSize returns the total size measured through binary.Size. +func (v TPMFamilySupport) TotalSize() uint64 { + return uint64(binary.Size(v)) +} + +// WriteTo writes the TPMFamilySupport into 'w' in binary format. +func (v TPMFamilySupport) WriteTo(w io.Writer) (int64, error) { + return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) +} + +// ReadFrom reads the TPMFamilySupport from 'r' in binary format. +func (v TPMFamilySupport) ReadFrom(r io.Reader) (int64, error) { + return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) +} + +// IsDiscreteTPM12Supported returns true if discrete TPM1.2 is supported. +// PrettyString-true: Discrete TPM1.2 is supported +// PrettyString-false: Discrete TPM1.2 is not supported +func (v TPMFamilySupport) IsDiscreteTPM12Supported() bool { + return v&1 != 0 +} + +// IsDiscreteTPM20Supported returns true if discrete TPM2.0 is supported. +// PrettyString-true: Discrete TPM2.0 is supported +// PrettyString-false: Discrete TPM2.0 is not supported +func (v TPMFamilySupport) IsDiscreteTPM20Supported() bool { + return v&2 != 0 +} + +// IsFirmwareTPM20Supported returns true if firmware TPM2.0 is supported. +// PrettyString-true: Firmware TPM2.0 is supported +// PrettyString-false: Firmware TPM2.0 is not supported +func (v TPMFamilySupport) IsFirmwareTPM20Supported() bool { + return v&(1<<3) != 0 } diff --git a/pkg/intel/metadata/cbnt/tpm_info_list_test.go b/pkg/intel/metadata/cbnt/tpm_info_list_test.go new file mode 100644 index 00000000..861f6e9c --- /dev/null +++ b/pkg/intel/metadata/cbnt/tpm_info_list_test.go @@ -0,0 +1,245 @@ +// Copyright 2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "bytes" + "encoding/binary" + "strings" + "testing" +) + +func TestTPMInfoListNew(t *testing.T) { + t.Parallel() + + tpm := NewTPMInfoList() + if tpm == nil { + t.Fatal("NewTPMInfoList() = nil, want non-nil") + } + if tpm.Capabilities != 0 { + t.Errorf("NewTPMInfoList().Capabilities = %d, want %d", tpm.Capabilities, 0) + } + if len(tpm.Algorithms) != 0 { + t.Errorf("len(NewTPMInfoList().Algorithms) = %d, want %d", len(tpm.Algorithms), 0) + } +} + +func TestTPMInfoListReadWriteRoundTrip(t *testing.T) { + t.Parallel() + + want := &TPMInfoList{ + Capabilities: TPMCapabilities(0x3D), + Algorithms: []Algorithm{AlgSHA256, AlgSHA384, AlgSM3}, + } + + var buf bytes.Buffer + n, err := want.WriteTo(&buf) + if err != nil { + t.Fatalf("TPMInfoList.WriteTo() error = %v, want nil", err) + } + if n != int64(want.TotalSize()) { + t.Errorf("TPMInfoList.WriteTo() bytes = %d, want %d", n, want.TotalSize()) + } + + var got TPMInfoList + n, err = got.ReadFrom(&buf) + if err != nil { + t.Fatalf("TPMInfoList.ReadFrom() error = %v, want nil", err) + } + if n != int64(got.TotalSize()) { + t.Errorf("TPMInfoList.ReadFrom() bytes = %d, want %d", n, got.TotalSize()) + } + + if got.Capabilities != want.Capabilities { + t.Errorf("TPMInfoList round-trip Capabilities = 0x%x, want 0x%x", got.Capabilities, want.Capabilities) + } + if len(got.Algorithms) != len(want.Algorithms) { + t.Fatalf("len(TPMInfoList round-trip Algorithms) = %d, want %d", len(got.Algorithms), len(want.Algorithms)) + } + for idx := range want.Algorithms { + if got.Algorithms[idx] != want.Algorithms[idx] { + t.Errorf("TPMInfoList round-trip Algorithms[%d] = %v, want %v", idx, got.Algorithms[idx], want.Algorithms[idx]) + } + } +} + +func TestTPMInfoListMethods(t *testing.T) { + t.Parallel() + + tpm := &TPMInfoList{Algorithms: []Algorithm{AlgSHA256}} + + size0, err := tpm.SizeOf(0) + if err != nil { + t.Fatalf("TPMInfoList.SizeOf(0) error = %v, want nil", err) + } + if size0 != 4 { + t.Errorf("TPMInfoList.SizeOf(0) = %d, want %d", size0, 4) + } + + offset1, err := tpm.OffsetOf(1) + if err != nil { + t.Fatalf("TPMInfoList.OffsetOf(1) error = %v, want nil", err) + } + if offset1 != 4 { + t.Errorf("TPMInfoList.OffsetOf(1) = %d, want %d", offset1, 4) + } + + if _, err := tpm.SizeOf(99); err == nil { + t.Errorf("TPMInfoList.SizeOf(99) error = nil, want non-nil") + } + if _, err := tpm.OffsetOf(99); err == nil { + t.Errorf("TPMInfoList.OffsetOf(99) error = nil, want non-nil") + } + + var nilTPM *TPMInfoList + if got := nilTPM.TotalSize(); got != 0 { + t.Errorf("(*TPMInfoList)(nil).TotalSize() = %d, want %d", got, 0) + } + + pretty := tpm.PrettyString(0, true) + if !strings.Contains(pretty, "TPM Info List") { + t.Errorf("TPMInfoList.PrettyString() = %q, want to contain %q", pretty, "TPM Info List") + } +} + +func TestTPMCapabilitiesAccessors(t *testing.T) { + t.Parallel() + + cap := TPMCapabilities(0) + cap |= TPMCapabilities(TPM2PCRExtendBothPolicies) + cap |= TPMCapabilities(0x0D << 2) + + if got := cap.TPM2PCRExtendPolicySupport(); got != TPM2PCRExtendBothPolicies { + t.Errorf("TPMCapabilities.TPM2PCRExtendPolicySupport() = %v, want %v", got, TPM2PCRExtendBothPolicies) + } + + family := cap.TPMFamilySupport() + if !family.IsDiscreteTPM12Supported() { + t.Errorf("TPMFamilySupport.IsDiscreteTPM12Supported() = false, want true") + } + if !family.IsFirmwareTPM20Supported() { + t.Errorf("TPMFamilySupport.IsFirmwareTPM20Supported() = false, want true") + } + if family.IsDiscreteTPM20Supported() { + t.Errorf("TPMFamilySupport.IsDiscreteTPM20Supported() = true, want false") + } +} + +func TestTPMSimpleTypesReadWriteRoundTrip(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + write func(*bytes.Buffer) (int64, error) + read func(*bytes.Buffer) (any, error) + readFrom func(*bytes.Buffer) (int64, error) + wantSize int64 + want any + wantErr bool + errSub string + }{ + "TPM2PCRExtendPolicySupport": { + write: func(buf *bytes.Buffer) (int64, error) { + v := TPM2PCRExtendPolicySupport(0x12) + return v.WriteTo(buf) + }, + read: func(buf *bytes.Buffer) (any, error) { + var v TPM2PCRExtendPolicySupport + if err := binary.Read(buf, binary.LittleEndian, &v); err != nil { + return nil, err + } + return v, nil + }, + readFrom: func(buf *bytes.Buffer) (int64, error) { + var v TPM2PCRExtendPolicySupport + return (&v).ReadFrom(buf) + }, + wantSize: int64(TPM2PCRExtendPolicySupport(0).TotalSize()), + want: TPM2PCRExtendPolicySupport(0x12), + wantErr: true, + errSub: "invalid type", + }, + "TPMCapabilities": { + write: func(buf *bytes.Buffer) (int64, error) { + v := TPMCapabilities(0x1234ABCD) + return v.WriteTo(buf) + }, + read: func(buf *bytes.Buffer) (any, error) { + var v TPMCapabilities + if err := binary.Read(buf, binary.LittleEndian, &v); err != nil { + return nil, err + } + return v, nil + }, + readFrom: func(buf *bytes.Buffer) (int64, error) { + var v TPMCapabilities + return (&v).ReadFrom(buf) + }, + wantSize: int64(TPMCapabilities(0).TotalSize()), + want: TPMCapabilities(0x1234ABCD), + wantErr: true, + errSub: "invalid type", + }, + "TPMFamilySupport": { + write: func(buf *bytes.Buffer) (int64, error) { + v := TPMFamilySupport(0x0D) + return v.WriteTo(buf) + }, + read: func(buf *bytes.Buffer) (any, error) { + var v TPMFamilySupport + if err := binary.Read(buf, binary.LittleEndian, &v); err != nil { + return nil, err + } + return v, nil + }, + readFrom: func(buf *bytes.Buffer) (int64, error) { + var v TPMFamilySupport + return (&v).ReadFrom(buf) + }, + wantSize: int64(TPMFamilySupport(0).TotalSize()), + want: TPMFamilySupport(0x0D), + wantErr: true, + errSub: "invalid type", + }, + } + + for name, tt := range tests { + name := name + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + + var writeBuf bytes.Buffer + n, err := tt.write(&writeBuf) + if err != nil { + t.Fatalf("%s.WriteTo() error = %v, want nil", name, err) + } + if n != tt.wantSize { + t.Errorf("%s.WriteTo() bytes = %d, want %d", name, n, tt.wantSize) + } + + decoded, err := tt.read(bytes.NewBuffer(writeBuf.Bytes())) + if err != nil { + t.Fatalf("binary.Read(%s) error = %v, want nil", name, err) + } + if decoded != tt.want { + t.Errorf("%s round-trip decoded value = %v, want %v", name, decoded, tt.want) + } + + n, err = tt.readFrom(bytes.NewBuffer(writeBuf.Bytes())) + if tt.wantErr { + if err == nil { + t.Errorf("%s.ReadFrom() error = nil, want non-nil (current implementation uses value receiver)", name) + } else if tt.errSub != "" && !strings.Contains(err.Error(), tt.errSub) { + t.Errorf("%s.ReadFrom() error = %q, want substring %q", name, err.Error(), tt.errSub) + } + } else if err != nil { + t.Errorf("%s.ReadFrom() error = %v, want nil", name, err) + } + if n != tt.wantSize { + t.Errorf("%s.ReadFrom() bytes = %d, want %d", name, n, tt.wantSize) + } + }) + } +} From 5941128e036fcae60f4b7d5ea9731f48debc1a17 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 12:08:49 +0200 Subject: [PATCH 16/40] feat(intel/metadata): adapt Key to use Common methods Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/key.go | 189 ++++++++++++++++++---- pkg/intel/metadata/cbnt/key_test.go | 241 ++++++++++++++++++++++++++++ 2 files changed, 401 insertions(+), 29 deletions(-) create mode 100644 pkg/intel/metadata/cbnt/key_test.go diff --git a/pkg/intel/metadata/cbnt/key.go b/pkg/intel/metadata/cbnt/key.go index 4b700592..464ff88c 100644 --- a/pkg/intel/metadata/cbnt/key.go +++ b/pkg/intel/metadata/cbnt/key.go @@ -14,42 +14,22 @@ import ( "crypto/rsa" "encoding/binary" "fmt" + "io" "math/big" + "strings" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" "github.com/tjfoc/gmsm/sm2" ) -// Key is a public key of an asymmetric crypto keypair. type Key struct { + Common KeyAlg Algorithm `json:"keyAlg"` Version uint8 `require:"0x10" json:"keyVersion"` KeySize BitSize `json:"keyBitsize"` Data []byte `countValue:"keyDataSize()" json:"keyData"` } -// BitSize is a size in bits. -type BitSize uint16 - -// InBits returns the size in bits. -func (ks BitSize) InBits() uint16 { - return uint16(ks) -} - -// InBytes returns the size in bytes. -func (ks BitSize) InBytes() uint16 { - return uint16(ks >> 3) -} - -// SetInBits sets the size in bits. -func (ks *BitSize) SetInBits(amountOfBits uint16) { - *ks = BitSize(amountOfBits) -} - -// SetInBytes sets the size in bytes. -func (ks *BitSize) SetInBytes(amountOfBytes uint16) { - *ks = BitSize(amountOfBytes << 3) -} - // keyDataSize returns the expected length of Data for specified // KeyAlg and KeySize. func (k Key) keyDataSize() int64 { @@ -76,7 +56,7 @@ func (k Key) PubKey() (crypto.PublicKey, error) { case AlgRSA: result := &rsa.PublicKey{ N: new(big.Int).SetBytes(reverseBytes(k.Data[4:])), - E: int(binaryOrder.Uint32(k.Data)), + E: int(endianess.Uint32(k.Data)), } return result, nil case AlgECC: @@ -112,7 +92,7 @@ func (k *Key) SetPubKey(key crypto.PublicKey) error { n := key.N.Bytes() k.KeySize.SetInBytes(uint16(len(n))) k.Data = make([]byte, 4+len(n)) - binaryOrder.PutUint32(k.Data, uint32(key.E)) + endianess.PutUint32(k.Data, uint32(key.E)) copy(k.Data[4:], reverseBytes(n)) return nil @@ -164,7 +144,8 @@ func (k *Key) PrintBPMPubKey(bpmAlg Algorithm) error { if err != nil { return err } - if k.KeyAlg == AlgRSA { + switch k.KeyAlg { + case AlgRSA: if err := binary.Write(buf, binary.LittleEndian, k.Data[4:]); err != nil { return err } @@ -172,7 +153,7 @@ func (k *Key) PrintBPMPubKey(bpmAlg Algorithm) error { return fmt.Errorf("unable to hash: %w", err) } fmt.Printf(" Boot Policy Manifest Pubkey Hash: 0x%x\n", hash.Sum(nil)) - } else if k.KeyAlg == AlgSM2 || k.KeyAlg == AlgECC { + case AlgSM2, AlgECC: if err := binary.Write(buf, binary.LittleEndian, k.Data); err != nil { return err } @@ -180,7 +161,7 @@ func (k *Key) PrintBPMPubKey(bpmAlg Algorithm) error { return fmt.Errorf("unable to hash: %w", err) } fmt.Printf(" Boot Policy Manifest Pubkey Hash: 0x%x\n", hash.Sum(nil)) - } else { + default: fmt.Printf(" Boot Policy Manifest Pubkey Hash: Unknown Algorithm\n") } } else { @@ -228,3 +209,153 @@ func (k *Key) PrintKMPubKey(kmAlg Algorithm) error { return nil } + +// NewKey returns a new instance of Key with +// all default values set. +func NewKey() *Key { + s := &Key{} + // Set through tag "required": + s.Version = 0x10 + return s +} + +func (k *Key) Layout() []LayoutField { + return []LayoutField{ + { + ID: 0, + Name: "Key Alg", + Size: func() uint64 { return 2 }, + Value: func() any { return &k.KeyAlg }, + Type: ManifestFieldEndValue, + }, + { + ID: 1, + Name: "Version", + Size: func() uint64 { return 1 }, + Value: func() any { return &k.Version }, + Type: ManifestFieldEndValue, + }, + { + ID: 2, + Name: "Key Size", + Size: func() uint64 { return 2 }, + Value: func() any { return &k.KeySize }, + Type: ManifestFieldEndValue, + }, + { + ID: 3, + Name: "Data", + Size: func() uint64 { return uint64(k.keyDataSize()) }, + Value: func() any { return &k.Data }, + Type: ManifestFieldArrayDynamicWithSize, + }, + } +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (k *Key) Validate() error { + // See tag "require" + if k.Version != 0x10 { + return fmt.Errorf("field 'Version' expects value '0x10', but has %v", k.Version) + } + + return nil +} + +// ReadFrom reads the Key from 'r' in format defined in the document #575623. +func (k *Key) ReadFrom(r io.Reader) (int64, error) { + totalN, err := k.Common.ReadFrom(r, k) + if err != nil { + return 0, err + } + + return totalN, nil +} + +// WriteTo writes the Key into 'w' in format defined in +// the document #575623. +func (k *Key) WriteTo(w io.Writer) (int64, error) { + return k.Common.WriteTo(w, k) +} + +func (k *Key) SizeOf(id int) (uint64, error) { + ret, err := k.Common.SizeOf(k, id) + if err != nil { + // normally it would be 0, but ret is already 0 if we land here + return ret, fmt.Errorf("Key: %v", err) + } + + return ret, nil +} + +func (k *Key) OffsetOf(id int) (uint64, error) { + ret, err := k.Common.OffsetOf(k, id) + if err != nil { + return ret, fmt.Errorf("Key: %v", err) + } + + return ret, nil +} + +// Size returns the total size of the Key. +func (k *Key) TotalSize() uint64 { + if k == nil { + return 0 + } + + return k.Common.TotalSize(k) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (k *Key) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return Common{}.PrettyString(depth, withHeader, k, "Key", opts...) +} + +type BitSize uint16 + +// InBits returns the size in bits. +func (ks BitSize) InBits() uint16 { + return uint16(ks) +} + +// InBytes returns the size in bytes. +func (ks BitSize) InBytes() uint16 { + return uint16(ks >> 3) +} + +// SetInBits sets the size in bits. +func (ks *BitSize) SetInBits(amountOfBits uint16) { + *ks = BitSize(amountOfBits) +} + +// SetInBytes sets the size in bytes. +func (ks *BitSize) SetInBytes(amountOfBytes uint16) { + *ks = BitSize(amountOfBytes << 3) +} + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (ks BitSize) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + var lines []string + if withHeader { + lines = append(lines, pretty.Header(depth, "Bit Size", ks)) + } + lines = append(lines, pretty.SubValue(depth+1, "In Bits", "", ks.InBits(), opts...)...) + lines = append(lines, pretty.SubValue(depth+1, "In Bytes", "", ks.InBytes(), opts...)...) + return strings.Join(lines, "\n") +} + +// TotalSize returns the total size measured through binary.Size. +func (ks BitSize) TotalSize() uint64 { + return uint64(binary.Size(ks)) +} + +// WriteTo writes the BitSize into 'w' in binary format. +func (ks BitSize) WriteTo(w io.Writer) (int64, error) { + return int64(ks.TotalSize()), binary.Write(w, binary.LittleEndian, ks) +} + +// ReadFrom reads the BitSize from 'r' in binary format. +func (ks BitSize) ReadFrom(r io.Reader) (int64, error) { + return int64(ks.TotalSize()), binary.Read(r, binary.LittleEndian, ks) +} diff --git a/pkg/intel/metadata/cbnt/key_test.go b/pkg/intel/metadata/cbnt/key_test.go new file mode 100644 index 00000000..66db972c --- /dev/null +++ b/pkg/intel/metadata/cbnt/key_test.go @@ -0,0 +1,241 @@ +// Copyright 2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "strings" + "testing" +) + +func TestKeyNewAndValidate(t *testing.T) { + t.Parallel() + + k := NewKey() + if k == nil { + t.Fatal("NewKey() = nil, want non-nil") + } + if k.Version != 0x10 { + t.Errorf("NewKey().Version = 0x%x, want 0x10", k.Version) + } + if err := k.Validate(); err != nil { + t.Errorf("NewKey().Validate() error = %v, want nil", err) + } +} + +func TestKeySetPubKeyAndPubKeyRSA(t *testing.T) { + key, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatalf("rsa.GenerateKey() error = %v, want nil", err) + } + + k := NewKey() + if err := k.SetPubKey(&key.PublicKey); err != nil { + t.Fatalf("Key.SetPubKey(RSA) error = %v, want nil", err) + } + + gotPub, err := k.PubKey() + if err != nil { + t.Fatalf("Key.PubKey() error = %v, want nil", err) + } + rsaPub, ok := gotPub.(*rsa.PublicKey) + if !ok { + t.Fatalf("Key.PubKey() type = %T, want %T", gotPub, &rsa.PublicKey{}) + } + + if rsaPub.E != key.E { + t.Errorf("Key.PubKey().E = %d, want %d", rsaPub.E, key.E) + } + if rsaPub.N.Cmp(key.N) != 0 { + t.Errorf("Key.PubKey().N = %x, want %x", rsaPub.N.Bytes(), key.N.Bytes()) + } +} + +func TestKeySetPubKeyAndPubKeyECDSA(t *testing.T) { + key := ecdsaP256with32b(t) + + k := NewKey() + if err := k.SetPubKey(&key.PublicKey); err != nil { + t.Fatalf("Key.SetPubKey(ECDSA) error = %v, want nil", err) + } + + gotPub, err := k.PubKey() + if err != nil { + t.Fatalf("Key.PubKey() error = %v, want nil", err) + } + ecdsaPub, ok := gotPub.(ecdsa.PublicKey) + if !ok { + t.Fatalf("Key.PubKey() type = %T, want %T", gotPub, ecdsa.PublicKey{}) + } + + if ecdsaPub.X.Cmp(key.X) != 0 { + t.Errorf("Key.PubKey().X = %x, want %x", ecdsaPub.X.Bytes(), key.X.Bytes()) + } + if ecdsaPub.Y.Cmp(key.Y) != 0 { + t.Errorf("Key.PubKey().Y = %x, want %x", ecdsaPub.Y.Bytes(), key.Y.Bytes()) + } +} + +func TestKeyPubKeyErrors(t *testing.T) { + t.Parallel() + + k := Key{KeyAlg: AlgRSA} + k.KeySize.SetInBytes(256) + k.Data = []byte{1} + if _, err := k.PubKey(); err == nil { + t.Errorf("Key.PubKey() with invalid data length error = nil, want non-nil") + } + + k = Key{KeyAlg: AlgSHA1} + if _, err := k.PubKey(); err == nil { + t.Errorf("Key.PubKey() with unexpected algorithm error = nil, want non-nil") + } +} + +func TestKeySetPubKeyUnexpectedType(t *testing.T) { + t.Parallel() + + k := NewKey() + if err := k.SetPubKey(struct{}{}); err == nil { + t.Errorf("Key.SetPubKey(struct{}{}) error = nil, want non-nil") + } +} + +func TestKeyReadWriteRoundTrip(t *testing.T) { + key, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatalf("rsa.GenerateKey() error = %v, want nil", err) + } + + want := NewKey() + if err := want.SetPubKey(&key.PublicKey); err != nil { + t.Fatalf("Key.SetPubKey() error = %v, want nil", err) + } + + var buf bytes.Buffer + n, err := want.WriteTo(&buf) + if err != nil { + t.Fatalf("Key.WriteTo() error = %v, want nil", err) + } + if n != int64(want.TotalSize()) { + t.Errorf("Key.WriteTo() bytes = %d, want %d", n, want.TotalSize()) + } + + var got Key + n, err = got.ReadFrom(&buf) + if err != nil { + t.Fatalf("Key.ReadFrom() error = %v, want nil", err) + } + if n != int64(got.TotalSize()) { + t.Errorf("Key.ReadFrom() bytes = %d, want %d", n, got.TotalSize()) + } + + if got.KeyAlg != want.KeyAlg { + t.Errorf("Key round-trip KeyAlg = %v, want %v", got.KeyAlg, want.KeyAlg) + } + if got.KeySize != want.KeySize { + t.Errorf("Key round-trip KeySize = %v, want %v", got.KeySize, want.KeySize) + } + if !bytes.Equal(got.Data, want.Data) { + t.Errorf("Key round-trip Data = %v, want %v", got.Data, want.Data) + } +} + +func TestKeyMethods(t *testing.T) { + t.Parallel() + + k := NewKey() + + if got := len(k.Layout()); got != 4 { + t.Errorf("len(Key.Layout()) = %d, want %d", got, 4) + } + + if _, err := k.SizeOf(99); err == nil { + t.Errorf("Key.SizeOf(99) error = nil, want non-nil") + } + if _, err := k.OffsetOf(99); err == nil { + t.Errorf("Key.OffsetOf(99) error = nil, want non-nil") + } + + var nilKey *Key + if got := nilKey.TotalSize(); got != 0 { + t.Errorf("(*Key)(nil).TotalSize() = %d, want %d", got, 0) + } + + pretty := k.PrettyString(0, true) + if !strings.Contains(pretty, "Key") { + t.Errorf("Key.PrettyString() = %q, want to contain %q", pretty, "Key") + } +} + +func TestKeyPrintMethodsErrorPaths(t *testing.T) { + key, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatalf("rsa.GenerateKey() error = %v, want nil", err) + } + + k := NewKey() + if err := k.SetPubKey(&key.PublicKey); err != nil { + t.Fatalf("Key.SetPubKey() error = %v, want nil", err) + } + + if err := k.PrintKMPubKey(AlgSHA1); err == nil { + t.Errorf("Key.PrintKMPubKey(AlgSHA1) error = nil, want non-nil") + } + + if err := k.PrintBPMPubKey(AlgRSA); err == nil { + t.Errorf("Key.PrintBPMPubKey(AlgRSA) error = nil, want non-nil") + } +} + +func TestBitSizeMethods(t *testing.T) { + t.Parallel() + + var bs BitSize + bs.SetInBytes(8) + if got := bs.InBits(); got != 64 { + t.Errorf("BitSize.InBits() after SetInBytes(8) = %d, want %d", got, 64) + } + bs.SetInBits(24) + if got := bs.InBytes(); got != 3 { + t.Errorf("BitSize.InBytes() after SetInBits(24) = %d, want %d", got, 3) + } + + var buf bytes.Buffer + n, err := bs.WriteTo(&buf) + if err != nil { + t.Fatalf("BitSize.WriteTo() error = %v, want nil", err) + } + if n != int64(bs.TotalSize()) { + t.Errorf("BitSize.WriteTo() bytes = %d, want %d", n, bs.TotalSize()) + } + + var got BitSize + n, err = (&got).ReadFrom(&buf) + if err == nil { + t.Fatalf("BitSize.ReadFrom() error = nil, want non-nil") + } + if n != int64(got.TotalSize()) { + t.Errorf("BitSize.ReadFrom() bytes = %d, want %d", n, got.TotalSize()) + } +} + +func ecdsaP256with32b(t *testing.T) *ecdsa.PrivateKey { + t.Helper() + + for { + k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("ecdsa.GenerateKey() error = %v, want nil", err) + } + if len(k.X.Bytes()) == 32 && len(k.Y.Bytes()) == 32 { + return k + } + } +} From 21fe735e5fe40bd346642551bc7c365b8bd59d38 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 14:19:56 +0200 Subject: [PATCH 17/40] feat(intel/metadata): adapt ChipsetACMInfo to use Common methods Signed-off-by: Michal Gorlas --- .../cbnt/chipset_ac_module_information.go | 184 +++++++++++++++++- ...chipset_ac_module_information_nocodegen.go | 38 ---- .../chipset_ac_module_information_test.go | 167 ++++++++++++++++ 3 files changed, 344 insertions(+), 45 deletions(-) delete mode 100644 pkg/intel/metadata/cbnt/chipset_ac_module_information_nocodegen.go create mode 100644 pkg/intel/metadata/cbnt/chipset_ac_module_information_test.go diff --git a/pkg/intel/metadata/cbnt/chipset_ac_module_information.go b/pkg/intel/metadata/cbnt/chipset_ac_module_information.go index 156f087a..8eade88b 100644 --- a/pkg/intel/metadata/cbnt/chipset_ac_module_information.go +++ b/pkg/intel/metadata/cbnt/chipset_ac_module_information.go @@ -1,11 +1,19 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:generate manifestcodegen - package cbnt +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) + +// See document 315168-017, A.1.2, Table 12, p.91 var chipsetACModuleInformationSignature = []byte{ 0xAA, 0x3A, 0xC0, 0x7F, 0xA7, 0x46, 0xDB, 0x18, 0x2E, 0xAC, 0x69, 0x8F, 0x8D, 0x41, 0x7F, 0x5A, @@ -13,6 +21,7 @@ var chipsetACModuleInformationSignature = []byte{ // ChipsetACModuleInformation represents Chipset AC Module Information Table parts for all versions type ChipsetACModuleInformation struct { + Common UUID [16]byte ChipsetACMType uint8 Version uint8 @@ -24,10 +33,171 @@ type ChipsetACModuleInformation struct { AcmVersion uint8 AcmRevision [3]uint8 ProcessorIDList uint32 + TPMInfoList uint32 +} + +// NewChipsetACModuleInformation returns a new instance of ChipsetACModuleInformation with +// all default values set. +func NewChipsetACModuleInformation() *ChipsetACModuleInformation { + s := &ChipsetACModuleInformation{} + return s +} + +// ParseChipsetACModuleInformation parses Chipset AC Module Information Table according to the version +func ParseChipsetACModuleInformation(r io.Reader) (ChipsetACModuleInformation, error) { + acm := NewChipsetACModuleInformation() + _, err := acm.ReadFrom(r) + if err != nil { + return ChipsetACModuleInformation{}, err + } + + if acm.Version >= 5 { + if !bytes.Equal(acm.UUID[:], chipsetACModuleInformationSignature) { + return ChipsetACModuleInformation{}, fmt.Errorf( + "incorrect UUID [%x], expected: [%x]", acm.UUID, chipsetACModuleInformationSignature) + } + + err = binary.Read(r, binary.LittleEndian, &acm.TPMInfoList) + if err != nil { + return ChipsetACModuleInformation{}, err + } + } + + return *acm, nil +} + +// ReadFrom reads the ChipsetACModuleInformation from 'r' in format defined in the document #575623. +func (s *ChipsetACModuleInformation) ReadFrom(r io.Reader) (int64, error) { + totalN, err := s.Common.ReadFrom(r, s) + if err != nil { + return 0, err + } + + return totalN, nil +} + +// WriteTo writes the ChipsetACModuleInformation into 'w' in format defined in +// the document #575623. +func (s *ChipsetACModuleInformation) WriteTo(w io.Writer) (int64, error) { + return s.Common.WriteTo(w, s) +} + +func (s *ChipsetACModuleInformation) Layout() []LayoutField { + return []LayoutField{ + { + ID: 0, + Name: "UUID", + Size: func() uint64 { return 16 }, + Value: func() any { return &s.UUID }, + Type: ManifestFieldArrayStatic, + }, + { + ID: 1, + Name: "Chipset ACM Type", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.ChipsetACMType }, + Type: ManifestFieldEndValue, + }, + { + ID: 2, + Name: "Version", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Version }, + Type: ManifestFieldEndValue, + }, + { + ID: 3, + Name: "Length", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.Length }, + Type: ManifestFieldEndValue, + }, + { + ID: 4, + Name: "Chipset ID List", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.ChipsetIDList }, + Type: ManifestFieldEndValue, + }, + { + ID: 5, + Name: "Os Sinit Data Ver", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.OsSinitDataVer }, + Type: ManifestFieldEndValue, + }, + { + ID: 6, + Name: "Min Mle Header Ver", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.MinMleHeaderVer }, + Type: ManifestFieldEndValue, + }, + { + ID: 7, + Name: "Capabilities", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.Capabilities }, + Type: ManifestFieldEndValue, + }, + { + ID: 8, + Name: "Acm Version", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.AcmVersion }, + Type: ManifestFieldEndValue, + }, + { + ID: 9, + Name: "Acm Revision", + Size: func() uint64 { return 3 }, + Value: func() any { return &s.AcmRevision }, + Type: ManifestFieldArrayStatic, + }, + { + ID: 10, + Name: "Processor ID List", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.ProcessorIDList }, + Type: ManifestFieldEndValue, + }, + { + ID: 11, + Name: "TPM Info List", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.TPMInfoList }, + Type: ManifestFieldEndValue, + }, + } +} + +func (s *ChipsetACModuleInformation) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("HashList: %v", err) + } + + return ret, nil +} + +func (s *ChipsetACModuleInformation) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("HashList: %v", err) + } + + return ret, nil +} + +func (s *ChipsetACModuleInformation) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) } -// ChipsetACModuleInformationV5 represents Chipset AC Module Information Table for version >= 5 -type ChipsetACModuleInformationV5 struct { - Base ChipsetACModuleInformation - TPMInfoList uint32 +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *ChipsetACModuleInformation) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return Common{}.PrettyString(depth, withHeader, s, "Chipset AC Module Information", opts...) } diff --git a/pkg/intel/metadata/cbnt/chipset_ac_module_information_nocodegen.go b/pkg/intel/metadata/cbnt/chipset_ac_module_information_nocodegen.go deleted file mode 100644 index f0e4031d..00000000 --- a/pkg/intel/metadata/cbnt/chipset_ac_module_information_nocodegen.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !manifestcodegen -// +build !manifestcodegen - -// -// To avoid errors "type ChipsetACModuleInformation has no field or method ReadFrom" -// with a build tag "!manifestcodegen" - -package cbnt - -import ( - "bytes" - "encoding/binary" - "fmt" - "io" -) - -// ParseChipsetACModuleInformation parses Chipset AC Module Information Table according to the version -func ParseChipsetACModuleInformation(r io.Reader) (int64, ChipsetACModuleInformationV5, error) { - var result ChipsetACModuleInformationV5 - total, err := result.Base.ReadFrom(r) - if !bytes.Equal(result.Base.UUID[:], chipsetACModuleInformationSignature) { - return 0, ChipsetACModuleInformationV5{}, fmt.Errorf( - "incorrect UUID [%x], expected: [%x]", result.Base.UUID, chipsetACModuleInformationSignature) - } - if err != nil { - return total, result, err - } - if result.Base.Version < 5 { - return total, result, nil - } - err = binary.Read(r, binary.LittleEndian, &result.TPMInfoList) - total += int64(binary.Size(result.TPMInfoList)) - return total, result, err -} diff --git a/pkg/intel/metadata/cbnt/chipset_ac_module_information_test.go b/pkg/intel/metadata/cbnt/chipset_ac_module_information_test.go new file mode 100644 index 00000000..2fcb2da4 --- /dev/null +++ b/pkg/intel/metadata/cbnt/chipset_ac_module_information_test.go @@ -0,0 +1,167 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbnt + +import ( + "bytes" + "encoding/binary" + "strings" + "testing" +) + +func TestChipsetACModuleInformationNew(t *testing.T) { + t.Parallel() + + got := NewChipsetACModuleInformation() + if got == nil { + t.Fatal("NewChipsetACModuleInformation() = nil, want non-nil") + } + want := ChipsetACModuleInformation{} + if *got != want { + t.Errorf("NewChipsetACModuleInformation() = %+v, want zero-value struct", *got) + } +} + +func TestChipsetACModuleInformationReadWriteRoundTrip(t *testing.T) { + t.Parallel() + + want := ChipsetACModuleInformation{ + UUID: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, + ChipsetACMType: 1, + Version: 4, + Length: 42, + ChipsetIDList: 100, + OsSinitDataVer: 101, + MinMleHeaderVer: 102, + Capabilities: 103, + AcmVersion: 2, + AcmRevision: [3]uint8{3, 4, 5}, + ProcessorIDList: 104, + } + + var buf bytes.Buffer + n, err := want.WriteTo(&buf) + if err != nil { + t.Fatalf("ChipsetACModuleInformation.WriteTo() error = %v, want nil", err) + } + if n != int64(want.TotalSize()) { + t.Errorf("ChipsetACModuleInformation.WriteTo() bytes = %d, want %d", n, want.TotalSize()) + } + + var got ChipsetACModuleInformation + n, err = got.ReadFrom(&buf) + if err != nil { + t.Fatalf("ChipsetACModuleInformation.ReadFrom() error = %v, want nil", err) + } + if n != int64(got.TotalSize()) { + t.Errorf("ChipsetACModuleInformation.ReadFrom() bytes = %d, want %d", n, got.TotalSize()) + } + + if got != want { + t.Errorf("ChipsetACModuleInformation round-trip = %+v, want %+v", got, want) + } +} + +func TestParseChipsetACModuleInformation(t *testing.T) { + t.Parallel() + + t.Run("version_lt_5", func(t *testing.T) { + acm := ChipsetACModuleInformation{Version: 4, Length: 0x1234} + var buf bytes.Buffer + if _, err := acm.WriteTo(&buf); err != nil { + t.Fatalf("ChipsetACModuleInformation.WriteTo() error = %v, want nil", err) + } + + got, err := ParseChipsetACModuleInformation(bytes.NewReader(buf.Bytes())) + if err != nil { + t.Fatalf("ParseChipsetACModuleInformation() error = %v, want nil", err) + } + if got.Version != 4 { + t.Errorf("ParseChipsetACModuleInformation() Version = %d, want %d", got.Version, 4) + } + }) + + t.Run("version_gte_5_reads_tpm_info_list", func(t *testing.T) { + acm := ChipsetACModuleInformation{Version: 5} + copy(acm.UUID[:], chipsetACModuleInformationSignature) + wantTPMInfoList := uint32(0xAABBCCDD) + + var buf bytes.Buffer + if _, err := acm.WriteTo(&buf); err != nil { + t.Fatalf("ChipsetACModuleInformation.WriteTo() error = %v, want nil", err) + } + if err := binary.Write(&buf, binary.LittleEndian, wantTPMInfoList); err != nil { + t.Fatalf("binary.Write(TPMInfoList) error = %v, want nil", err) + } + + got, err := ParseChipsetACModuleInformation(bytes.NewReader(buf.Bytes())) + if err != nil { + t.Fatalf("ParseChipsetACModuleInformation() error = %v, want nil", err) + } + if got.TPMInfoList != wantTPMInfoList { + t.Errorf("ParseChipsetACModuleInformation() TPMInfoList = 0x%x, want 0x%x", got.TPMInfoList, wantTPMInfoList) + } + }) + + t.Run("version_gte_5_invalid_uuid", func(t *testing.T) { + acm := ChipsetACModuleInformation{Version: 5} + acm.UUID = [16]byte{0xFF} + + var buf bytes.Buffer + if _, err := acm.WriteTo(&buf); err != nil { + t.Fatalf("ChipsetACModuleInformation.WriteTo() error = %v, want nil", err) + } + if err := binary.Write(&buf, binary.LittleEndian, uint32(1)); err != nil { + t.Fatalf("binary.Write(TPMInfoList) error = %v, want nil", err) + } + + if _, err := ParseChipsetACModuleInformation(bytes.NewReader(buf.Bytes())); err == nil { + t.Errorf("ParseChipsetACModuleInformation() error = nil, want non-nil") + } + }) +} + +func TestChipsetACModuleInformationMethods(t *testing.T) { + t.Parallel() + + acm := NewChipsetACModuleInformation() + + if got := len(acm.Layout()); got != 12 { + t.Errorf("len(ChipsetACModuleInformation.Layout()) = %d, want %d", got, 11) + } + + size0, err := acm.SizeOf(0) + if err != nil { + t.Fatalf("ChipsetACModuleInformation.SizeOf(0) error = %v, want nil", err) + } + if size0 != 16 { + t.Errorf("ChipsetACModuleInformation.SizeOf(0) = %d, want %d", size0, 16) + } + + offset10, err := acm.OffsetOf(10) + if err != nil { + t.Fatalf("ChipsetACModuleInformation.OffsetOf(10) error = %v, want nil", err) + } + if offset10 != 40 { + t.Errorf("ChipsetACModuleInformation.OffsetOf(10) = %d, want %d", offset10, 40) + } + + if _, err := acm.SizeOf(99); err == nil { + t.Errorf("ChipsetACModuleInformation.SizeOf(99) error = nil, want non-nil") + } + if _, err := acm.OffsetOf(99); err == nil { + t.Errorf("ChipsetACModuleInformation.OffsetOf(99) error = nil, want non-nil") + } + + var nilACM *ChipsetACModuleInformation + if got := nilACM.TotalSize(); got != 0 { + t.Errorf("(*ChipsetACModuleInformation)(nil).TotalSize() = %d, want %d", got, 0) + } + + pretty := acm.PrettyString(0, true) + if !strings.Contains(pretty, "Chipset AC Module Information") { + t.Errorf("ChipsetACModuleInformation.PrettyString() = %q, want to contain %q", pretty, "Chipset AC Module Information") + } +} From 0693e29d6a6c6deeee88f913176ae079969e4602 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 14:26:59 +0200 Subject: [PATCH 18/40] chore(intel/metadata): move consts definitions out of fit pkg Signed-off-by: Michal Gorlas --- pkg/intel/metadata/fit/consts/consts.go | 33 ------------------------- pkg/intel/metadata/fit/consts/fit.go | 11 --------- 2 files changed, 44 deletions(-) delete mode 100644 pkg/intel/metadata/fit/consts/consts.go delete mode 100644 pkg/intel/metadata/fit/consts/fit.go diff --git a/pkg/intel/metadata/fit/consts/consts.go b/pkg/intel/metadata/fit/consts/consts.go deleted file mode 100644 index 58904bed..00000000 --- a/pkg/intel/metadata/fit/consts/consts.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package consts - -const ( - // BasePhysAddr is the absolute physical address where the firmware image ends. - // - // See Figure 2.1 in https://www.intel.com/content/dam/www/public/us/en/documents/guides/fit-bios-specification.pdf - // - // Note: A firmware image grows towards lower addresses. So an image will be mapped to addresses: - // [ BasePhysAddr-length .. BasePhysAddr ) - // - // Note: SPI chip is mapped into this region. So we actually work directly with data of the SPI chip - // - // See also CalculatePhysAddrOfOffset(). - BasePhysAddr = 1 << 32 // "4GB" - - // FITPointerOffset is the offset of the physical address of the FIT pointer. - // See "1 Firmware Interface Table" in "Firmware Interface Table" specification: - // * https://www.intel.com/content/dam/www/public/us/en/documents/guides/fit-bios-specification.pdf - FITPointerOffset = 0x40 - - // FITPointerPhysAddr is the physical address of the FIT pointer. - // See "1 Firmware Interface Table" in "Firmware Interface Table" specification: - // * https://www.intel.com/content/dam/www/public/us/en/documents/guides/fit-bios-specification.pdf - FITPointerPhysAddr = BasePhysAddr - FITPointerOffset - - // FITPointerSize is the size of the FIT pointer. - // It is suggested to be 0x10 bytes because of "Figure 1-1" of the specification. - FITPointerSize = 0x10 -) diff --git a/pkg/intel/metadata/fit/consts/fit.go b/pkg/intel/metadata/fit/consts/fit.go deleted file mode 100644 index a6101acf..00000000 --- a/pkg/intel/metadata/fit/consts/fit.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package consts - -const ( - // FITHeadersMagic is the magic string, expected in the beginning of the - // first FIT entry - FITHeadersMagic = "_FIT_ " -) From 878ae36dc2f5c5ae97713867f54e99353fdae89b Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 14:30:42 +0200 Subject: [PATCH 19/40] feat(intel/metadata): adapt FIT pkg to merged BG/CBnT Signed-off-by: Michal Gorlas --- pkg/intel/metadata/fit/calc_offset.go | 8 ++-- .../metadata/fit/ent_boot_policy_manifest.go | 40 +++++++++++++------ .../metadata/fit/ent_key_manifest_record.go | 29 ++++++++------ pkg/intel/metadata/fit/errors.go | 4 +- 4 files changed, 51 insertions(+), 30 deletions(-) diff --git a/pkg/intel/metadata/fit/calc_offset.go b/pkg/intel/metadata/fit/calc_offset.go index 37434e97..d613fd8c 100644 --- a/pkg/intel/metadata/fit/calc_offset.go +++ b/pkg/intel/metadata/fit/calc_offset.go @@ -4,7 +4,7 @@ package fit -import "github.com/linuxboot/fiano/pkg/intel/metadata/fit/consts" +import "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" // CalculatePhysAddrFromOffset calculates the physical address (address to a // region mapped from the SPI chip) using an offset withtin an image, relatively @@ -15,7 +15,7 @@ import "github.com/linuxboot/fiano/pkg/intel/metadata/fit/consts" // CalculatePhysAddrFromOffset(0x01, 0x2000) == 0xffffe001 // CalculatePhysAddrFromOffset(0x40, 0x2000) == 0xffffe040 func CalculatePhysAddrFromOffset(offset uint64, imageSize uint64) uint64 { - startAddr := consts.BasePhysAddr - imageSize + startAddr := cbnt.BasePhysAddr - imageSize return startAddr + offset } @@ -28,7 +28,7 @@ func CalculatePhysAddrFromOffset(offset uint64, imageSize uint64) uint64 { // CalculateOffsetFromPhysAddr(0xffffffff, 0x1000) == 0xfff // CalculateOffsetFromPhysAddr(0xffffffc0, 0x1000) == 0xfc0 func CalculateOffsetFromPhysAddr(physAddr uint64, imageSize uint64) uint64 { - startAddr := consts.BasePhysAddr - imageSize + startAddr := cbnt.BasePhysAddr - imageSize return physAddr - startAddr } @@ -41,5 +41,5 @@ func CalculateOffsetFromPhysAddr(physAddr uint64, imageSize uint64) uint64 { // CalculateTailOffsetFromPhysAddr(0xffffffff) == 0x01 // CalculateTailOffsetFromPhysAddr(0xffffffc0) == 0x40 func CalculateTailOffsetFromPhysAddr(physAddr uint64) uint64 { - return consts.BasePhysAddr - physAddr + return cbnt.BasePhysAddr - physAddr } diff --git a/pkg/intel/metadata/fit/ent_boot_policy_manifest.go b/pkg/intel/metadata/fit/ent_boot_policy_manifest.go index 6073b4ac..8608738e 100644 --- a/pkg/intel/metadata/fit/ent_boot_policy_manifest.go +++ b/pkg/intel/metadata/fit/ent_boot_policy_manifest.go @@ -10,9 +10,8 @@ import ( "fmt" "io" - "github.com/linuxboot/fiano/pkg/intel/metadata/bg/bgbootpolicy" - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/bgheader" + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/bootpolicy" ) // EntryBootPolicyManifestRecord represents a FIT entry of type "Boot Policy Manifest" (0x0C) @@ -41,27 +40,44 @@ func (entry *EntryBootPolicyManifestRecord) Reader() *bytes.Reader { } // ParseData creates EntryBootPolicyManifestRecord from EntryBootPolicyManifest -func (entry *EntryBootPolicyManifestRecord) ParseData() (*bgbootpolicy.Manifest, *cbntbootpolicy.Manifest, error) { +func (entry *EntryBootPolicyManifestRecord) ParseData() (*cbntbootpolicy.Manifest, *cbntbootpolicy.Manifest, error) { r := bytes.NewReader(entry.DataSegmentBytes) - version, err := bgheader.DetectBGV(r) + version, err := cbnt.DetectBGV(r) if err != nil { return nil, nil, err } switch version { - case bgheader.Version10: - manifest := bgbootpolicy.NewManifest() + case cbnt.Version10: + manifest, err := cbntbootpolicy.NewManifest(cbnt.Version10) + if err != nil { + return nil, nil, nil + } + _, err = manifest.ReadFrom(r) + if err != nil && !errors.Is(err, io.EOF) { + return nil, nil, err + } + return &manifest, nil, nil + case cbnt.Version20: + manifest, err := cbntbootpolicy.NewManifest(cbnt.Version20) + if err != nil { + return nil, nil, err + } _, err = manifest.ReadFrom(r) if err != nil && !errors.Is(err, io.EOF) { return nil, nil, err } - return manifest, nil, nil - case bgheader.Version20: - manifest := cbntbootpolicy.NewManifest() + return nil, &manifest, nil + + case cbnt.Version21: + manifest, err := cbntbootpolicy.NewManifest(cbnt.Version21) + if err != nil { + return nil, nil, err + } _, err = manifest.ReadFrom(r) if err != nil && !errors.Is(err, io.EOF) { return nil, nil, err } - return nil, manifest, nil + return nil, &manifest, nil default: return nil, nil, fmt.Errorf("failed to parse BootPolicyManifest, err: %v", err) } @@ -69,7 +85,7 @@ func (entry *EntryBootPolicyManifestRecord) ParseData() (*bgbootpolicy.Manifest, // ParseBootPolicyManifest returns a boot policy manifest if it was able to // parse one. -func (table Table) ParseBootPolicyManifest(firmware []byte) (*bgbootpolicy.Manifest, *cbntbootpolicy.Manifest, error) { +func (table Table) ParseBootPolicyManifest(firmware []byte) (*cbntbootpolicy.Manifest, *cbntbootpolicy.Manifest, error) { hdr := table.First(EntryTypeBootPolicyManifest) if hdr == nil { return nil, nil, ErrNotFound{} diff --git a/pkg/intel/metadata/fit/ent_key_manifest_record.go b/pkg/intel/metadata/fit/ent_key_manifest_record.go index dbac730c..8d1d188e 100644 --- a/pkg/intel/metadata/fit/ent_key_manifest_record.go +++ b/pkg/intel/metadata/fit/ent_key_manifest_record.go @@ -10,9 +10,8 @@ import ( "fmt" "io" - "github.com/linuxboot/fiano/pkg/intel/metadata/bg/bgkey" - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntkey" - "github.com/linuxboot/fiano/pkg/intel/metadata/common/bgheader" + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + keymanifest "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/keymanifest" ) // EntryKeyManifestRecord represents a FIT entry of type "Key Manifest Record" (0x0B) @@ -41,27 +40,33 @@ func (entry *EntryKeyManifestRecord) Reader() *bytes.Reader { } // ParseData creates EntryKeyManifestRecord from EntryKeyManifest -func (entry *EntryKeyManifestRecord) ParseData() (*bgkey.Manifest, *cbntkey.Manifest, error) { +func (entry *EntryKeyManifestRecord) ParseData() (*keymanifest.Manifest, *keymanifest.Manifest, error) { r := bytes.NewReader(entry.DataSegmentBytes) - version, err := bgheader.DetectBGV(r) + version, err := cbnt.DetectBGV(r) if err != nil { return nil, nil, err } switch version { - case bgheader.Version10: - manifest := bgkey.NewManifest() + case cbnt.Version10: + manifest, err := keymanifest.NewManifest(cbnt.Version10) + if err != nil { + return nil, nil, err + } _, err = manifest.ReadFrom(r) if err != nil && !errors.Is(err, io.EOF) { return nil, nil, err } - return manifest, nil, nil - case bgheader.Version20: - manifest := cbntkey.NewManifest() + return &manifest, nil, nil + case cbnt.Version20: + manifest, err := keymanifest.NewManifest(cbnt.Version20) + if err != nil { + return nil, nil, err + } _, err = manifest.ReadFrom(r) if err != nil && !errors.Is(err, io.EOF) { return nil, nil, err } - return nil, manifest, nil + return nil, &manifest, nil default: return nil, nil, fmt.Errorf("failed to parse KeyManifest, err: %v", err) } @@ -69,7 +74,7 @@ func (entry *EntryKeyManifestRecord) ParseData() (*bgkey.Manifest, *cbntkey.Mani // ParseKeyManifest returns a key manifest if it was able to // parse one. -func (table Table) ParseKeyManifest(firmware []byte) (*bgkey.Manifest, *cbntkey.Manifest, error) { +func (table Table) ParseKeyManifest(firmware []byte) (*keymanifest.Manifest, *keymanifest.Manifest, error) { hdr := table.First(EntryTypeKeyManifestRecord) if hdr == nil { return nil, nil, ErrNotFound{} diff --git a/pkg/intel/metadata/fit/errors.go b/pkg/intel/metadata/fit/errors.go index 08ae7976..6c67d7c0 100644 --- a/pkg/intel/metadata/fit/errors.go +++ b/pkg/intel/metadata/fit/errors.go @@ -7,7 +7,7 @@ package fit import ( "fmt" - "github.com/linuxboot/fiano/pkg/intel/metadata/fit/consts" + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" ) // ErrACMInvalidKeySize means ACM entry has invalid key size @@ -47,7 +47,7 @@ type ErrExpectedFITHeadersMagic struct { func (err *ErrExpectedFITHeadersMagic) Error() string { return fmt.Sprintf("string '%s' was expected as the Address value of the FIT header entry, but received: '%s'", - consts.FITHeadersMagic, err.Received) + cbnt.FITHeadersMagic, err.Received) } // ErrNotFound literally means "not found". From b94ceacc63e00c9b1964b9ca3002748ba0e875c1 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 14:58:33 +0200 Subject: [PATCH 20/40] feat(intel/metadata): use BIOS flash area size from IFD if needed Currently the calculation to find FIT pointer starts (as per spec) with substracting 0x40 from the image size. On some boards (Intel CRB's for e.g but I also experienced similar issues on production boards) this will end in null dereference, since the BIOS flash area is not span over the whole image (i.e. there is some padding at the end of the image). This can be solved by comparing BIOS flash area size exposed in IFD against the image size, and replacing image size with BIOS flash area size in the calculation if these two do not match. Signed-off-by: Michal Gorlas --- pkg/intel/metadata/fit/entry.go | 50 +++++++---- pkg/intel/metadata/fit/entry_headers.go | 23 ++--- pkg/intel/metadata/fit/entry_test.go | 10 ++- pkg/intel/metadata/fit/get_entries.go | 4 +- pkg/intel/metadata/fit/table.go | 107 +++++++++++++++++------- 5 files changed, 130 insertions(+), 64 deletions(-) diff --git a/pkg/intel/metadata/fit/entry.go b/pkg/intel/metadata/fit/entry.go index 793f289a..5fd4e6f2 100644 --- a/pkg/intel/metadata/fit/entry.go +++ b/pkg/intel/metadata/fit/entry.go @@ -11,8 +11,8 @@ import ( "strings" "github.com/hashicorp/go-multierror" + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" "github.com/linuxboot/fiano/pkg/intel/metadata/fit/check" - "github.com/linuxboot/fiano/pkg/intel/metadata/fit/consts" "github.com/xaionaro-go/bytesextra" ) @@ -148,7 +148,7 @@ func (entries Entries) String() string { // // What will happen: // 1. The FIT headers will be written by offset headersOffset. -// 2. The FIT pointer will be written at consts.FITPointerOffset offset from the end of the image. +// 2. The FIT pointer will be written at cbnt.FITPointerOffset offset from the end of the image. // 3. Data referenced by FIT headers will be written at offsets accordingly to Address fields (in the headers). // // Consider calling Rehash() before Inject()/InjectTo() @@ -171,7 +171,7 @@ func (entries Entries) InjectTo(w io.WriteSeeker, headersOffset uint64) error { // Write FIT pointer - if _, err := w.Seek(-consts.FITPointerOffset, io.SeekEnd); err != nil { + if _, err := w.Seek(-cbnt.FITPointerOffset, io.SeekEnd); err != nil { return fmt.Errorf("unable to Seek(%d, %d) to write FIT pointer: %w", headersOffset, io.SeekStart, err) } pointerValue := CalculatePhysAddrFromOffset(headersOffset, uint64(imageSize)) @@ -227,25 +227,36 @@ func readBytesFromReader(r io.Reader, size uint64) ([]byte, error) { return result, nil } -// EntryDataSegmentSize returns the coordinates of the data segment size associates with the entry. -func EntryDataSegmentSize(entry Entry, firmware io.ReadSeeker) (uint64, error) { +func FirmwareSizeUsedFromSeeker(firmware io.ReadSeeker) (uint64, error) { + firmwareSize, err := firmware.Seek(0, io.SeekEnd) + if err != nil || firmwareSize < 0 { + return 0, fmt.Errorf("unable to determine firmware size; result: %d; err: %w", firmwareSize, err) + } + + firmwareSizeUsed := uint64(firmwareSize) + if ifdSize, ifdErr := flashSizeFromIFD(firmware, firmwareSizeUsed); ifdErr == nil && ifdSize > 0 && ifdSize <= firmwareSizeUsed { + firmwareSizeUsed = ifdSize + } + + return firmwareSizeUsed, nil +} + +func EntryDataSegmentSize(entry Entry, firmware io.ReadSeeker, firmwareSizeUsed uint64) (uint64, error) { if sizeGetter, ok := entry.(EntryCustomGetDataSegmentSizer); ok { return sizeGetter.CustomGetDataSegmentSize(firmware) - } else { - return entry.GetEntryBase().Headers.mostCommonGetDataSegmentSize(), nil } + return entry.GetEntryBase().Headers.mostCommonGetDataSegmentSize(), nil } -// EntryDataSegmentCoordinates returns the coordinates of the data segment coordinates associates with the entry. -func EntryDataSegmentCoordinates(entry Entry, firmware io.ReadSeeker) (uint64, uint64, error) { +func EntryDataSegmentCoordinates(entry Entry, firmware io.ReadSeeker, firmwareSizeUsed uint64) (uint64, uint64, error) { var err error - offset, addErr := entry.GetEntryBase().Headers.getDataSegmentOffset(firmware) + offset, addErr := entry.GetEntryBase().Headers.getDataSegmentOffset(firmwareSizeUsed) if addErr != nil { err = multierror.Append(err, fmt.Errorf("unable to get data segment offset: %w", err)) } - size, addErr := EntryDataSegmentSize(entry, firmware) + size, addErr := EntryDataSegmentSize(entry, firmware, firmwareSizeUsed) if addErr != nil { err = multierror.Append(err, fmt.Errorf("unable to get data segment size: %w", err)) } @@ -254,20 +265,23 @@ func EntryDataSegmentCoordinates(entry Entry, firmware io.ReadSeeker) (uint64, u } // If possible then make a slice of existing data; if not then copy. -func sliceOrCopyBytesFrom(r io.ReadSeeker, startIdx, endIdx uint64) ([]byte, error) { +func sliceOrCopyBytesFrom(r io.ReadSeeker, startIdx, endIdx, firmwareSizeUsed uint64) ([]byte, error) { switch r := r.(type) { case *bytesextra.ReadWriteSeeker: - if err := check.BytesRange(uint(len(r.Storage)), int(startIdx), int(endIdx)); err != nil { + if err := check.BytesRange(uint(firmwareSizeUsed), int(startIdx), int(endIdx)); err != nil { return nil, err } return r.Storage[startIdx:endIdx], nil default: + if err := check.BytesRange(uint(firmwareSizeUsed), int(startIdx), int(endIdx)); err != nil { + return nil, err + } return copyBytesFrom(r, startIdx, endIdx) } } -func entryInitDataSegmentBytes(entry Entry, firmware io.ReadSeeker) error { - dataSegmentOffset, dataSegmentSize, err := EntryDataSegmentCoordinates(entry, firmware) +func entryInitDataSegmentBytes(entry Entry, firmware io.ReadSeeker, firmwareSizeUsed uint64) error { + dataSegmentOffset, dataSegmentSize, err := EntryDataSegmentCoordinates(entry, firmware, firmwareSizeUsed) if err != nil { return fmt.Errorf("unable to get data segment coordinates of entry %T: %w", entry, err) } @@ -278,7 +292,7 @@ func entryInitDataSegmentBytes(entry Entry, firmware io.ReadSeeker) error { base := entry.GetEntryBase() - base.DataSegmentBytes, err = sliceOrCopyBytesFrom(firmware, dataSegmentOffset, dataSegmentOffset+dataSegmentSize) + base.DataSegmentBytes, err = sliceOrCopyBytesFrom(firmware, dataSegmentOffset, dataSegmentOffset+dataSegmentSize, firmwareSizeUsed) if err != nil { return fmt.Errorf("unable to copy data segment bytes from the firmware image (offset:%d, size:%d): %w", dataSegmentOffset, dataSegmentSize, err) } @@ -287,7 +301,7 @@ func entryInitDataSegmentBytes(entry Entry, firmware io.ReadSeeker) error { } // NewEntry returns a new entry using headers and firmware image -func NewEntry(hdr *EntryHeaders, firmware io.ReadSeeker) Entry { +func NewEntry(hdr *EntryHeaders, firmware io.ReadSeeker, firmwareSizeUsed uint64) Entry { entry := hdr.Type().newEntry() if entry == nil { entry = &EntryUnknown{} @@ -295,7 +309,7 @@ func NewEntry(hdr *EntryHeaders, firmware io.ReadSeeker) Entry { base := entry.GetEntryBase() base.Headers = *hdr - err := entryInitDataSegmentBytes(entry, firmware) + err := entryInitDataSegmentBytes(entry, firmware, firmwareSizeUsed) if err != nil { base.HeadersErrors = append(base.HeadersErrors, err) } diff --git a/pkg/intel/metadata/fit/entry_headers.go b/pkg/intel/metadata/fit/entry_headers.go index 59c821c8..ec6f05f7 100644 --- a/pkg/intel/metadata/fit/entry_headers.go +++ b/pkg/intel/metadata/fit/entry_headers.go @@ -300,12 +300,17 @@ func (f *TypeAndIsChecksumValid) UnmarshalJSON(b []byte) error { // GetEntry returns a full entry (headers + data) func (hdr EntryHeaders) GetEntry(firmware []byte) Entry { - return hdr.GetEntryFrom(bytesextra.NewReadWriteSeeker(firmware)) + rw := bytesextra.NewReadWriteSeeker(firmware) + firmwareSizeUsed := uint64(len(firmware)) + if ifdSize, ifdErr := flashSizeFromIFD(rw, firmwareSizeUsed); ifdErr == nil && ifdSize > 0 && ifdSize <= firmwareSizeUsed { + firmwareSizeUsed = ifdSize + } + return hdr.GetEntryFrom(rw, firmwareSizeUsed) } // GetEntryFrom returns a full entry (headers + data) -func (hdr EntryHeaders) GetEntryFrom(firmware io.ReadSeeker) Entry { - return NewEntry(hdr.copy(), firmware) +func (hdr EntryHeaders) GetEntryFrom(firmware io.ReadSeeker, firmwareSizeUsed uint64) Entry { + return NewEntry(hdr.copy(), firmware, firmwareSizeUsed) } // Type returns the type of the FIT entry @@ -365,15 +370,11 @@ func (hdr *EntryHeaders) CalculateChecksum() uint8 { return result } -// getDataSegmentCoordinates returns the offset of the data segment -// associated with the entry. -func (hdr *EntryHeaders) getDataSegmentOffset(firmware io.Seeker) (uint64, error) { - firmwareSize, err := firmware.Seek(0, io.SeekEnd) - if err != nil { - return 0, fmt.Errorf("unable to get the size of the firmware: %w", err) +func (hdr *EntryHeaders) getDataSegmentOffset(firmwareSizeUsed uint64) (uint64, error) { + if firmwareSizeUsed == 0 { + return 0, fmt.Errorf("firmware size is zero") } - - return hdr.Address.Offset(uint64(firmwareSize)), nil + return hdr.Address.Offset(firmwareSizeUsed), nil } // mostCommonGetDataSegmentCoordinates returns the length of the data segment diff --git a/pkg/intel/metadata/fit/entry_test.go b/pkg/intel/metadata/fit/entry_test.go index 818aca9f..13390953 100644 --- a/pkg/intel/metadata/fit/entry_test.go +++ b/pkg/intel/metadata/fit/entry_test.go @@ -10,7 +10,8 @@ import ( "strings" "testing" - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntkey" + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + keymanifest "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/keymanifest" "github.com/stretchr/testify/require" "github.com/xaionaro-go/bytesextra" ) @@ -51,7 +52,7 @@ func TestRehashEntry(t *testing.T) { // Validating that DataSize() calculates sizes consistently with RehashEntry() if entryType != EntryTypeStartupACModuleEntry { - dataSize, err := EntryDataSegmentSize(entry, nil) + dataSize, err := EntryDataSegmentSize(entry, nil, 0) require.NoError(t, err) if dataSize != 0 && dataSize != uint64(len(entry.GetEntryBase().DataSegmentBytes)) { t.Errorf("wrong DataSize 0x%X for type %s", dataSize, entryType) @@ -68,9 +69,10 @@ func getSampleEntries(t *testing.T) Entries { kmEntry := &EntryKeyManifestRecord{} { - km := cbntkey.NewManifest() + km, err := keymanifest.NewManifest(cbnt.Version20) + require.NoError(t, err) var buf bytes.Buffer - _, err := km.WriteTo(&buf) + _, err = km.WriteTo(&buf) require.NoError(t, err) kmEntry.DataSegmentBytes = buf.Bytes() } diff --git a/pkg/intel/metadata/fit/get_entries.go b/pkg/intel/metadata/fit/get_entries.go index 94a57709..50e75e50 100644 --- a/pkg/intel/metadata/fit/get_entries.go +++ b/pkg/intel/metadata/fit/get_entries.go @@ -18,10 +18,10 @@ func GetEntries(firmware []byte) (Entries, error) { // GetEntriesFrom returns parsed FIT-entries func GetEntriesFrom(firmware io.ReadSeeker) (Entries, error) { - table, err := GetTableFrom(firmware) + table, firmwareSizeUsed, err := GetTableFrom(firmware) if err != nil { return nil, fmt.Errorf("unable to get FIT table: %w", err) } - return table.GetEntriesFrom(firmware), nil + return table.GetEntriesFrom(firmware, firmwareSizeUsed), nil } diff --git a/pkg/intel/metadata/fit/table.go b/pkg/intel/metadata/fit/table.go index 63097b4b..5d7f84ab 100644 --- a/pkg/intel/metadata/fit/table.go +++ b/pkg/intel/metadata/fit/table.go @@ -11,8 +11,9 @@ import ( "io" "strings" + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" "github.com/linuxboot/fiano/pkg/intel/metadata/fit/check" - "github.com/linuxboot/fiano/pkg/intel/metadata/fit/consts" + "github.com/linuxboot/fiano/pkg/uefi" "github.com/xaionaro-go/bytesextra" ) @@ -22,13 +23,18 @@ type Table []EntryHeaders // GetEntries returns parsed FIT-entries func (table Table) GetEntries(firmware []byte) (result Entries) { - return table.GetEntriesFrom(bytesextra.NewReadWriteSeeker(firmware)) + rw := bytesextra.NewReadWriteSeeker(firmware) + firmwareSizeUsed := uint64(len(firmware)) + if ifdSize, ifdErr := flashSizeFromIFD(rw, firmwareSizeUsed); ifdErr == nil && ifdSize > 0 && ifdSize <= firmwareSizeUsed { + firmwareSizeUsed = ifdSize + } + return table.GetEntriesFrom(rw, firmwareSizeUsed) } -// GetEntriesFrom returns parsed FIT-entries -func (table Table) GetEntriesFrom(firmware io.ReadSeeker) (result Entries) { +// GetEntriesFrom returns parsed FIT-entries using provided firmware size. +func (table Table) GetEntriesFrom(firmware io.ReadSeeker, firmwareSizeUsed uint64) (result Entries) { for _, headers := range table { - result = append(result, headers.GetEntryFrom(firmware)) + result = append(result, headers.GetEntryFrom(firmware, firmwareSizeUsed)) } return } @@ -91,7 +97,7 @@ func (table Table) WriteTo(w io.Writer) (n int64, err error) { // WriteToFirmwareImage finds the position of FIT in a firmware image and writes the table there. func (table Table) WriteToFirmwareImage(w io.ReadWriteSeeker) (n int64, err error) { - startIdx, _, err := GetHeadersTableRangeFrom(w) + startIdx, _, _, err := GetHeadersTableRangeFrom(w) if err != nil { return 0, fmt.Errorf("unable to find the beginning of the FIT: %w", err) } @@ -131,14 +137,14 @@ func ParseTable(b []byte) (Table, error) { // GetPointerCoordinates returns the position of the FIT pointer within // the firmware. func GetPointerCoordinates(firmwareSize uint64) (startIdx, endIdx int64) { - startIdx = int64(firmwareSize) - consts.FITPointerOffset - endIdx = startIdx + consts.FITPointerSize + startIdx = int64(firmwareSize) - cbnt.FITPointerOffset + endIdx = startIdx + cbnt.FITPointerSize return } -// GetHeadersTableRangeFrom returns the starting and ending indexes of the FIT -// headers table within the firmware image. -func GetHeadersTableRangeFrom(firmware io.ReadSeeker) (startIdx, endIdx uint64, err error) { +// GetHeadersTableRangeFromWithSize returns the starting and ending indexes of the FIT +// headers table within the firmware image and firmware size used. +func GetHeadersTableRangeFrom(firmware io.ReadSeeker) (startIdx, endIdx, firmwareSizeUsed uint64, err error) { /* An example: @@ -180,22 +186,27 @@ func GetHeadersTableRangeFrom(firmware io.ReadSeeker) (startIdx, endIdx uint64, firmwareSize, err := firmware.Seek(0, io.SeekEnd) if err != nil || firmwareSize < 0 { - return 0, 0, fmt.Errorf("unable to determine firmware size; result: %d; err: %w", firmwareSize, err) + return 0, 0, 0, fmt.Errorf("unable to determine firmware size; result: %d; err: %w", firmwareSize, err) + } + + firmwareSizeUsed = uint64(firmwareSize) + if ifdSize, ifdErr := flashSizeFromIFD(firmware, firmwareSizeUsed); ifdErr == nil && ifdSize > 0 && ifdSize <= uint64(firmwareSize) { + firmwareSizeUsed = ifdSize } - fitPointerStartIdx, fitPointerEndIdx := GetPointerCoordinates(uint64(firmwareSize)) + fitPointerStartIdx, fitPointerEndIdx := GetPointerCoordinates(firmwareSizeUsed) - if err := check.BytesRange(uint(firmwareSize), int(fitPointerStartIdx), int(fitPointerEndIdx)); err != nil { - return 0, 0, fmt.Errorf("invalid fit pointer bytes range: %w", err) + if err := check.BytesRange(uint(firmwareSizeUsed), int(fitPointerStartIdx), int(fitPointerEndIdx)); err != nil { + return 0, 0, firmwareSizeUsed, fmt.Errorf("invalid fit pointer bytes range: %w", err) } - fitPointerBytes, err := sliceOrCopyBytesFrom(firmware, uint64(fitPointerStartIdx), uint64(fitPointerEndIdx)) + fitPointerBytes, err := sliceOrCopyBytesFrom(firmware, uint64(fitPointerStartIdx), uint64(fitPointerEndIdx), firmwareSizeUsed) if err != nil { - return 0, 0, fmt.Errorf("unable to get FIT pointer value: %w", err) + return 0, 0, firmwareSizeUsed, fmt.Errorf("unable to get FIT pointer value: %w", err) } fitPointerValue := binary.LittleEndian.Uint64(fitPointerBytes) fitPointerOffset := CalculateTailOffsetFromPhysAddr(fitPointerValue) - startIdx = uint64(firmwareSize) - fitPointerOffset + startIdx = firmwareSizeUsed - fitPointerOffset // OK, now we need to calculate the end of the headers... // @@ -203,7 +214,7 @@ func GetHeadersTableRangeFrom(firmware io.ReadSeeker) (startIdx, endIdx uint64, // size is the size of the table. So let's just use it. firstHeaderEndIdx := startIdx + uint64(entryHeadersSize) - if err = check.BytesRange(uint(firmwareSize), int(startIdx), int(firstHeaderEndIdx)); err != nil { + if err = check.BytesRange(uint(firmwareSizeUsed), int(startIdx), int(firstHeaderEndIdx)); err != nil { err = fmt.Errorf("invalid the first entry bytes range: %w", err) return } @@ -229,7 +240,7 @@ func GetHeadersTableRangeFrom(firmware io.ReadSeeker) (startIdx, endIdx uint64, err = fmt.Errorf("unable to read the Address value of the FIT header entry: %w", err) return } - if !bytes.Equal([]byte(consts.FITHeadersMagic), buf.Bytes()) { + if !bytes.Equal([]byte(cbnt.FITHeadersMagic), buf.Bytes()) { err = &ErrExpectedFITHeadersMagic{Received: buf.Bytes()} return } @@ -238,7 +249,7 @@ func GetHeadersTableRangeFrom(firmware io.ReadSeeker) (startIdx, endIdx uint64, // parseHeaders it. endIdx = startIdx + uint64(tableMeta.Size.Uint32()<<4) // See 4.2.5 - if err = check.BytesRange(uint(firmwareSize), int(startIdx), int(endIdx)); err != nil { + if err = check.BytesRange(uint(firmwareSizeUsed), int(startIdx), int(endIdx)); err != nil { err = fmt.Errorf("invalid entries bytes range: %w", err) return } @@ -246,27 +257,65 @@ func GetHeadersTableRangeFrom(firmware io.ReadSeeker) (startIdx, endIdx uint64, return } +func flashSizeFromIFD(firmware io.ReadSeeker, firmwareSize uint64) (uint64, error) { + if firmwareSize < uefi.FlashDescriptorLength { + return 0, fmt.Errorf("firmware size too small for flash descriptor: %d", firmwareSize) + } + + buf, err := sliceOrCopyBytesFrom(firmware, 0, uefi.FlashDescriptorLength, firmwareSize) + if err != nil { + return 0, fmt.Errorf("unable to read flash descriptor: %w", err) + } + + fd := uefi.FlashDescriptor{} + fd.SetBuf(buf) + if err := fd.ParseFlashDescriptor(); err != nil { + return 0, err + } + + var maxEnd uint64 + for _, fr := range fd.Region.FlashRegions { + if !fr.Valid() { + continue + } + end := uint64(fr.EndOffset()) + if end > maxEnd { + maxEnd = end + } + } + if maxEnd == 0 { + return 0, fmt.Errorf("no valid regions in flash descriptor") + } + + return maxEnd, nil +} + // GetTable returns the table of FIT entries of the firmware image. func GetTable(firmware []byte) (Table, error) { - return GetTableFrom(bytesextra.NewReadWriteSeeker(firmware)) + table, _, err := GetTableFrom(bytesextra.NewReadWriteSeeker(firmware)) + if err != nil { + return nil, err + } + + return table, nil } // GetTableFrom returns the table of FIT entries of the firmware image. -func GetTableFrom(firmware io.ReadSeeker) (Table, error) { - startIdx, endIdx, err := GetHeadersTableRangeFrom(firmware) +func GetTableFrom(firmware io.ReadSeeker) (Table, uint64, error) { + startIdx, endIdx, firmwareSizeUsed, err := GetHeadersTableRangeFrom(firmware) if err != nil { - return nil, fmt.Errorf("unable to locate the table coordinates (does the image contain FIT?): %w", err) + return nil, 0, fmt.Errorf("unable to locate the table coordinates (does the image contain FIT?): %w", err) } - tableBytes, err := sliceOrCopyBytesFrom(firmware, startIdx, endIdx) + tableBytes, err := sliceOrCopyBytesFrom(firmware, startIdx, endIdx, firmwareSizeUsed) if err != nil { - return nil, fmt.Errorf("unable to copy bytes from the firmware: %w", err) + return nil, 0, fmt.Errorf("unable to copy bytes from the firmware: %w", err) } result, err := ParseTable(tableBytes) if err != nil { - return nil, fmt.Errorf("unable to parse the table: %w", err) + return nil, 0, fmt.Errorf("unable to parse the table: %w", err) } - return result, nil + return result, firmwareSizeUsed, nil } From 689f6c6217459fc4eebe71133dc4ebf2f448af45 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 15:07:31 +0200 Subject: [PATCH 21/40] feat(intel/metadata): add SACMv5 and generalize R/W for SACMv3/4/5 Signed-off-by: Michal Gorlas --- .../fit/ent_startup_ac_module_entry.go | 144 +++++++++++++----- 1 file changed, 103 insertions(+), 41 deletions(-) diff --git a/pkg/intel/metadata/fit/ent_startup_ac_module_entry.go b/pkg/intel/metadata/fit/ent_startup_ac_module_entry.go index 90dd0df2..f06d1495 100644 --- a/pkg/intel/metadata/fit/ent_startup_ac_module_entry.go +++ b/pkg/intel/metadata/fit/ent_startup_ac_module_entry.go @@ -23,7 +23,12 @@ type EntrySACM struct{ EntryBase } var _ EntryCustomGetDataSegmentSizer = (*EntrySACM)(nil) func (entry *EntrySACM) CustomGetDataSegmentSize(firmware io.ReadSeeker) (uint64, error) { - offset, err := entry.Headers.getDataSegmentOffset(firmware) + firmwareSizeUsed, err := FirmwareSizeUsedFromSeeker(firmware) + if err != nil { + return 0, fmt.Errorf("unable to detect firmware size: %w", err) + } + + offset, err := entry.Headers.getDataSegmentOffset(firmwareSizeUsed) if err != nil { return 0, fmt.Errorf("unable to detect data segment offset: %w", err) } @@ -113,6 +118,9 @@ const ( // ACHeaderVersion4 is version "4.0 for SINIT ACM of BtG" ACHeaderVersion4 = ACModuleHeaderVersion(0x00040000) + + // ACHeaderVersion4 is version "5.0 for SINIT ACM of BtG" + ACHeaderVersion5 = ACModuleHeaderVersion(0x00050004) ) func (ver ACModuleHeaderVersion) GoString() string { @@ -346,6 +354,28 @@ func (entryData EntrySACMDataCommon) KeySizeBinaryOffset() uint { return 120 } +var entrySACMData0Size = uint(binary.Size(EntrySACMData0{})) + +type SACMDataRW interface { + EntrySACMData0 | EntrySACMData3 | EntrySACMData4 | EntrySACMData5 +} + +func readSACMData[T SACMDataRW](entryData *T, r io.Reader) (int64, error) { + err := binary.Read(r, binary.LittleEndian, entryData) + if err != nil { + return -1, err + } + return int64(binary.Size(*entryData)), nil +} + +func writeSACMData[T SACMDataRW](entryData *T, w io.Writer) (int64, error) { + err := binary.Write(w, binary.LittleEndian, entryData) + if err != nil { + return -1, err + } + return int64(binary.Size(*entryData)), nil +} + // EntrySACMData0 is the structure for ACM of version 0.0. type EntrySACMData0 struct { EntrySACMDataCommon @@ -356,8 +386,6 @@ type EntrySACMData0 struct { Scratch [572]byte } -var entrySACMData0Size = uint(binary.Size(EntrySACMData0{})) - // Read parses the ACM v0 headers func (entryData *EntrySACMData0) Read(b []byte) (int, error) { n, err := entryData.ReadFrom(bytesextra.NewReadWriteSeeker(b)) @@ -366,11 +394,7 @@ func (entryData *EntrySACMData0) Read(b []byte) (int, error) { // ReadFrom parses the ACM v0 headers func (entryData *EntrySACMData0) ReadFrom(r io.Reader) (int64, error) { - err := binary.Read(r, binary.LittleEndian, entryData) - if err != nil { - return -1, err - } - return int64(entrySACMData0Size), nil + return readSACMData(entryData, r) } // Write compiles the SACM v0 headers into a binary representation @@ -381,11 +405,7 @@ func (entryData *EntrySACMData0) Write(b []byte) (int, error) { // WriteTo compiles the SACM v0 headers into a binary representation func (entryData *EntrySACMData0) WriteTo(w io.Writer) (int64, error) { - err := binary.Write(w, binary.LittleEndian, entryData) - if err != nil { - return -1, err - } - return int64(entrySACMData0Size), nil + return writeSACMData(entryData, w) } // GetRSAPubKey returns the RSA public key @@ -427,19 +447,9 @@ type EntrySACMData3 struct { var entrySACMData3Size = uint(binary.Size(EntrySACMData3{})) -// Read parses the ACM v3 headers -func (entryData *EntrySACMData3) Read(b []byte) (int, error) { - n, err := entryData.ReadFrom(bytesextra.NewReadWriteSeeker(b)) - return int(n), err -} - // ReadFrom parses the ACM v3 headers func (entryData *EntrySACMData3) ReadFrom(r io.Reader) (int64, error) { - err := binary.Read(r, binary.LittleEndian, entryData) - if err != nil { - return -1, err - } - return int64(entrySACMData3Size), nil + return readSACMData(entryData, r) } // Write compiles the SACM v3 headers into a binary representation @@ -450,11 +460,7 @@ func (entryData *EntrySACMData3) Write(b []byte) (int, error) { // WriteTo compiles the SACM v3 headers into a binary representation func (entryData *EntrySACMData3) WriteTo(w io.Writer) (int64, error) { - err := binary.Write(w, binary.LittleEndian, entryData) - if err != nil { - return -1, err - } - return int64(entrySACMData3Size), nil + return writeSACMData(entryData, w) } // GetRSAPubKey returns the RSA public key @@ -497,8 +503,6 @@ type EntrySACMData4 struct { Scratch [3584]byte } -var entrySACMData4Size = uint(binary.Size(EntrySACMData4{})) - // Read parses the ACM v3 headers func (entryData *EntrySACMData4) Read(b []byte) (int, error) { n, err := entryData.ReadFrom(bytesextra.NewReadWriteSeeker(b)) @@ -507,11 +511,7 @@ func (entryData *EntrySACMData4) Read(b []byte) (int, error) { // ReadFrom parses the ACM v3 headers func (entryData *EntrySACMData4) ReadFrom(r io.Reader) (int64, error) { - err := binary.Read(r, binary.LittleEndian, entryData) - if err != nil { - return -1, err - } - return int64(entrySACMData3Size), nil + return readSACMData(entryData, r) } // Write compiles the SACM v3 headers into a binary representation @@ -522,11 +522,7 @@ func (entryData *EntrySACMData4) Write(b []byte) (int, error) { // WriteTo compiles the SACM v3 headers into a binary representation func (entryData *EntrySACMData4) WriteTo(w io.Writer) (int64, error) { - err := binary.Write(w, binary.LittleEndian, entryData) - if err != nil { - return -1, err - } - return int64(entrySACMData4Size), nil + return writeSACMData(entryData, w) } // GetRSAPubKey returns the RSA public key @@ -557,6 +553,67 @@ func (entryData *EntrySACMData4) GetXMSSSig() []byte { return entryData.XMSSSig[ // GetScratch returns the Scratch field value func (entryData *EntrySACMData4) GetScratch() []byte { return entryData.Scratch[:] } +type EntrySACMData5 struct { + EntrySACMDataCommon + + RSAPubKey [384]byte + RSASig [384]byte + XMSSPubKey [64]byte + XMSSSig [2692]byte + Reserved [60]byte + Scratch [3584]byte +} + +// Read parses the ACM v5 headers +func (entryData *EntrySACMData5) Read(b []byte) (int, error) { + n, err := entryData.ReadFrom(bytesextra.NewReadWriteSeeker(b)) + return int(n), err +} + +// ReadFrom parses the ACM v3 headers +func (entryData *EntrySACMData5) ReadFrom(r io.Reader) (int64, error) { + return readSACMData(entryData, r) +} + +// Write compiles the SACM v3 headers into a binary representation +func (entryData *EntrySACMData5) Write(b []byte) (int, error) { + n, err := entryData.WriteTo(bytesextra.NewReadWriteSeeker(b)) + return int(n), err +} + +// WriteTo compiles the SACM v3 headers into a binary representation +func (entryData *EntrySACMData5) WriteTo(w io.Writer) (int64, error) { + return writeSACMData(entryData, w) +} + +// GetRSAPubKey returns the RSA public key +func (entryData *EntrySACMData5) GetRSAPubKey() rsa.PublicKey { + pubKey := rsa.PublicKey{ + N: big.NewInt(0), + E: 0x10001, // see Table 9. "RSAPubExp" of https://www.intel.com/content/www/us/en/software-developers/txt-software-development-guide.html + } + pubKey.N.SetBytes(entryData.RSAPubKey[:]) + return pubKey +} + +// GetRSASig returns the RSA signature. +func (entryData *EntrySACMData5) GetRSASig() []byte { return entryData.RSASig[:] } + +// RSASigBinaryOffset returns the RSA signature offset +func (entryData *EntrySACMData5) RSASigBinaryOffset() uint64 { + return uint64(binary.Size(entryData.EntrySACMDataCommon)) + + uint64(binary.Size(entryData.RSAPubKey)) +} + +// GetXMSSPubKey returns the XMSS public key +func (entryData *EntrySACMData5) GetXMSSPubKey() []byte { return entryData.XMSSPubKey[:] } + +// GetXMSSSig returns the XMSS signature. +func (entryData *EntrySACMData5) GetXMSSSig() []byte { return entryData.XMSSSig[:] } + +// GetScratch returns the Scratch field value +func (entryData *EntrySACMData5) GetScratch() []byte { return entryData.Scratch[:] } + // Read parses the ACM func (entryData *EntrySACMData) Read(b []byte) (int, error) { n, err := entryData.ReadFrom(bytesextra.NewReadWriteSeeker(b)) @@ -612,6 +669,8 @@ func (entryData *EntrySACMData) GetCommon() *EntrySACMDataCommon { return &data.EntrySACMDataCommon case *EntrySACMData4: return &data.EntrySACMDataCommon + case *EntrySACMData5: + return &data.EntrySACMDataCommon } return nil } @@ -673,6 +732,9 @@ func ParseSACMData(r io.Reader) (*EntrySACMData, error) { case ACHeaderVersion4: result.EntrySACMDataInterface = &EntrySACMData4{EntrySACMDataCommon: common} requiredKeySize = uint64(len(EntrySACMData4{}.RSAPubKey)) + case ACHeaderVersion5: + result.EntrySACMDataInterface = &EntrySACMData5{EntrySACMDataCommon: common} + requiredKeySize = uint64(len(EntrySACMData5{}.RSAPubKey)) default: return result, &ErrUnknownACMHeaderVersion{ACHeaderVersion: common.HeaderVersion} } From fe4da9d2f826b704d8693f106a243e166c68f2aa Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 15:10:58 +0200 Subject: [PATCH 22/40] chore(fittool): update calls to intel/metadata/fit Signed-off-by: Michal Gorlas --- cmds/fittool/commands/addrawheaders/command.go | 2 +- cmds/fittool/commands/removeheaders/command.go | 2 +- cmds/fittool/commands/setrawheaders/command.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmds/fittool/commands/addrawheaders/command.go b/cmds/fittool/commands/addrawheaders/command.go index 9203d05a..834f4851 100644 --- a/cmds/fittool/commands/addrawheaders/command.go +++ b/cmds/fittool/commands/addrawheaders/command.go @@ -58,7 +58,7 @@ func (cmd *Command) Execute(args []string) error { return fmt.Errorf("unable to open the firmware image file '%s': %w", cmd.UEFIPath, err) } - table, err := fit.GetTableFrom(file) + table, _, err := fit.GetTableFrom(file) if err != nil { return fmt.Errorf("unable to get FIT from the firmware image: %w", err) } diff --git a/cmds/fittool/commands/removeheaders/command.go b/cmds/fittool/commands/removeheaders/command.go index 2b83c1bc..a0bbad04 100644 --- a/cmds/fittool/commands/removeheaders/command.go +++ b/cmds/fittool/commands/removeheaders/command.go @@ -43,7 +43,7 @@ func (cmd *Command) Execute(args []string) error { return fmt.Errorf("unable to open the firmware image file '%s': %w", cmd.UEFIPath, err) } - table, err := fit.GetTableFrom(file) + table, _, err := fit.GetTableFrom(file) if err != nil { return fmt.Errorf("unable to get FIT from the firmware image: %w", err) } diff --git a/cmds/fittool/commands/setrawheaders/command.go b/cmds/fittool/commands/setrawheaders/command.go index ae31e612..f8154c31 100644 --- a/cmds/fittool/commands/setrawheaders/command.go +++ b/cmds/fittool/commands/setrawheaders/command.go @@ -59,7 +59,7 @@ func (cmd *Command) Execute(args []string) error { return fmt.Errorf("unable to open the firmware image file '%s': %w", cmd.UEFIPath, err) } - table, err := fit.GetTableFrom(file) + table, _, err := fit.GetTableFrom(file) if err != nil { return fmt.Errorf("unable to get FIT from the firmware image: %w", err) } From 8d83223a142e7b4e2c555164936b9bceb6658689 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 15:15:35 +0200 Subject: [PATCH 23/40] feat(intel/metadata): merge BG/CBnT KM and adapt to use Common methods Merge Key Manifest for BG and CBnT. Given the differences, there are still two separate implementations of KM, these can, however, be accessed by the common constructor. While this commit adds a lots of code (sorry :D) there are no changes in the logic (as there was no changes in the 2.1 spec affecting KM). Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/keymanifest/hash.go | 209 ++++++++++ .../metadata/cbnt/keymanifest/manifest.go | 48 +++ .../metadata/cbnt/keymanifest/manifest_bg.go | 196 ++++++++++ .../cbnt/keymanifest/manifest_cbnt.go | 368 ++++++++++++++++++ .../cbnt/keymanifest/manifest_test.go | 29 ++ .../cbnt/keymanifest/testdata/km_bg.bin | Bin 0 -> 577 bytes .../cbnt/keymanifest/testdata/km_cbnt.bin | Bin 0 -> 641 bytes 7 files changed, 850 insertions(+) create mode 100644 pkg/intel/metadata/cbnt/keymanifest/hash.go create mode 100644 pkg/intel/metadata/cbnt/keymanifest/manifest.go create mode 100644 pkg/intel/metadata/cbnt/keymanifest/manifest_bg.go create mode 100644 pkg/intel/metadata/cbnt/keymanifest/manifest_cbnt.go create mode 100644 pkg/intel/metadata/cbnt/keymanifest/manifest_test.go create mode 100644 pkg/intel/metadata/cbnt/keymanifest/testdata/km_bg.bin create mode 100644 pkg/intel/metadata/cbnt/keymanifest/testdata/km_cbnt.bin diff --git a/pkg/intel/metadata/cbnt/keymanifest/hash.go b/pkg/intel/metadata/cbnt/keymanifest/hash.go new file mode 100644 index 00000000..92628020 --- /dev/null +++ b/pkg/intel/metadata/cbnt/keymanifest/hash.go @@ -0,0 +1,209 @@ +// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbntkey + +import ( + "encoding/binary" + "fmt" + "io" + "strings" + + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) + +// Hash is "KM hash Structure" defined in document #575623. +type Hash struct { + cbnt.Common + // Usage is the digest usage bitmask. + // + // More than one bit can be set to indicate shared digest usage. + // Usage of bit 0 is normative; other usages are informative. + Usage Usage `json:"hashUsage"` + + // Digest is the actual digest. + Digest cbnt.HashStructure `json:"hashStruct"` +} + +// Usage is the digest usage bitmask. +// +// More than one bit can be set to indicate shared digest usage. +// Usage of bit 0 is normative; other usages are informative. +type Usage uint64 + +const ( + // UsageBPMSigningPKD is the bit meaning the digest could be used as + // Boot Policy Manifest signing pubkey digest. + UsageBPMSigningPKD = Usage(1 << iota) + + // UsageFITPatchManifestSigningPKD is the bit meaning the digest could be used as + // FIT Patch Manifest signing pubkey digest. + UsageFITPatchManifestSigningPKD + + // UsageACMManifestSigningPKD is the bit meaning the digest could be used as + // ACM Manifest signing pubkey digest. + UsageACMManifestSigningPKD + + // UsageSDEVSigningPKD is the bit meaning the digest could be used as + // SDEV signing pubkey digest. + UsageSDEVSigningPKD + + // UsageReserved is a reserved bit + UsageReserved +) + +// String implements fmt.Stringer. +func (u Usage) String() string { + var result []string + for i := uint(0); i < 64; i++ { + f := Usage(1 << i) + if !u.IsSet(f) { + continue + } + var descr string + switch f { + case UsageBPMSigningPKD: + descr = "BPM_signing_pubkey_digest" + case UsageFITPatchManifestSigningPKD: + descr = "FIT_patch_manifest_signing_pubkey_digest" + case UsageACMManifestSigningPKD: + descr = "ACM_manifest_signing_pubkey_digest" + case UsageSDEVSigningPKD: + descr = "SDEV_signing_pubkey_digest" + case UsageReserved: + descr = "Reserved" + default: + descr = fmt.Sprintf("unexpected_bit_%d", i) + } + result = append(result, descr) + } + + return strings.Join(result, ",") +} + +// IsSet returns true if bits `f` are set in bitmask `u`. +func (u Usage) IsSet(f Usage) bool { + return u&f != 0 +} + +// Set sets/unsets the bits of `f` in bitmask `u`. +// +// To set the bits `v` should be true, to unset -- false. +func (u *Usage) Set(f Usage, v bool) { + if v { + *u |= f + } else { + *u &= ^f + } +} + +// NewHash returns a new instance of Hash with +// all default values set. +func NewHash() *Hash { + s := &Hash{} + // Recursively initializing a child structure: + // s.Digest = *cbnt.NewHashStructure() + // s.Rehash() + return s +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *Hash) Validate() error { + // Recursively validating a child structure: + // if err := s.Digest.Validate(); err != nil { + // return fmt.Errorf("error on field 'Digest': %w", err) + // } + + return nil +} + +// ReadFrom reads the Hash from 'r' in format defined in the document #575623. +func (s *Hash) ReadFrom(r io.Reader) (int64, error) { + totalN, err := s.Common.ReadFrom(r, s) + if err != nil { + return 0, err + } + + return totalN, nil +} + +// WriteTo writes the Hash into 'w' in format defined in +// the document #575623. +func (s *Hash) WriteTo(w io.Writer) (int64, error) { + return s.Common.WriteTo(w, s) +} + +func (s *Hash) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Usage", + Size: func() uint64 { return 8 }, + Value: func() any { return &s.Usage }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 1, + Name: "Digest", + Size: func() uint64 { return s.Digest.Common.TotalSize(&s.Digest) }, + Value: func() any { return &s.Digest }, + Type: cbnt.ManifestFieldSubStruct, + }, + } +} + +func (s *Hash) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + // normally it would be 0, but ret is already 0 if we land here + return ret, fmt.Errorf("Hash: %v", err) + } + + return ret, nil +} + +func (s *Hash) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("Hash: %v", err) + } + + return ret, nil +} + +// Size returns the total size of the Hash. +func (s *Hash) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *Hash) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return s.Common.PrettyString(depth, withHeader, s, "Hash", opts...) +} + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (u Usage) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return u.String() +} + +// TotalSize returns the total size measured through binary.Size. +func (u Usage) TotalSize() uint64 { + return uint64(binary.Size(u)) +} + +// WriteTo writes the Usage into 'w' in binary format. +func (u Usage) WriteTo(w io.Writer) (int64, error) { + return int64(u.TotalSize()), binary.Write(w, binary.LittleEndian, u) +} + +// ReadFrom reads the Usage from 'r' in binary format. +func (u Usage) ReadFrom(r io.Reader) (int64, error) { + return int64(u.TotalSize()), binary.Read(r, binary.LittleEndian, u) +} diff --git a/pkg/intel/metadata/cbnt/keymanifest/manifest.go b/pkg/intel/metadata/cbnt/keymanifest/manifest.go new file mode 100644 index 00000000..f1192381 --- /dev/null +++ b/pkg/intel/metadata/cbnt/keymanifest/manifest.go @@ -0,0 +1,48 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cbntkey provides Key Manifest representation. +package cbntkey + +import ( + "crypto" + "fmt" + + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" +) + +type Manifest interface { + ValidateBPMKey(bpmKS cbnt.KeySignature) error + SetSignature( + algo cbnt.Algorithm, + hashAlgo cbnt.Algorithm, + privKey crypto.Signer, + signedData []byte, + ) error + cbnt.Element + Print() +} + +func NewManifest(bgv cbnt.BootGuardVersion) (Manifest, error) { + switch bgv { + case cbnt.Version10: + s := &BGManifest{} + s.StructInfoBG = *cbnt.NewStructInfo(cbnt.Version10).(*cbnt.StructInfoBG) + s.Version = 0x10 + copy(s.ID[:], []byte(cbnt.StructureIDManifest)) + s.KeyAndSignature = *cbnt.NewKeySignature() + return s, nil + case cbnt.Version20, cbnt.Version21: + s := &CBnTManifest{} + s.StructInfoCBNT = *cbnt.NewStructInfo(cbnt.Version20).(*cbnt.StructInfoCBNT) + s.Version = 0x21 + copy(s.ID[:], []byte(cbnt.StructureIDManifest)) + s.KeyAndSignature = *cbnt.NewKeySignature() + return s, nil + default: + // This will never be the case in internal usage of NewManifest, + // though out of principle the error handling is here + return nil, fmt.Errorf("version not supported") + } +} diff --git a/pkg/intel/metadata/cbnt/keymanifest/manifest_bg.go b/pkg/intel/metadata/cbnt/keymanifest/manifest_bg.go new file mode 100644 index 00000000..adb57065 --- /dev/null +++ b/pkg/intel/metadata/cbnt/keymanifest/manifest_bg.go @@ -0,0 +1,196 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbntkey + +import ( + "bytes" + "crypto" + "fmt" + "io" + + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) + +type BGManifest struct { + cbnt.Common + cbnt.StructInfoBG `id:"__KEYM__" version:"0x10"` + KMVersion uint8 `json:"kmVersion"` + KMSVN cbnt.SVN `json:"kmSVN"` + KMID uint8 `json:"kmID"` + BPKey cbnt.HashStructure `json:"kmBPKey"` + KeyAndSignature cbnt.KeySignature `json:"kmKeySignature"` +} + +func (m *BGManifest) SetSignature( + algo cbnt.Algorithm, + hashAlgo cbnt.Algorithm, + privKey crypto.Signer, + signedData []byte, +) error { + err := m.KeyAndSignature.SetSignature(algo, algo, privKey, signedData) + if err != nil { + return fmt.Errorf("unable to set the signature: %w", err) + } + + return nil +} + +func (m *BGManifest) ValidateBPMKey(bpmKS cbnt.KeySignature) error { + h, err := m.BPKey.HashAlg.Hash() + if err != nil { + return fmt.Errorf("invalid hash algo %v: %w", m.BPKey.HashAlg, err) + } + + if len(m.BPKey.HashBuffer) != h.Size() { + return fmt.Errorf("invalid hash lenght: actual:%d expected:%d", len(m.BPKey.HashBuffer), h.Size()) + } + + switch bpmKS.Key.KeyAlg { + case cbnt.AlgRSA: + if _, err := h.Write(bpmKS.Key.Data[4:]); err != nil { + return fmt.Errorf("unable to hash: %w", err) + } + default: + return fmt.Errorf("unsupported key algorithm: %v", bpmKS.Key.KeyAlg) + } + digest := h.Sum(nil) + + if !bytes.Equal(m.BPKey.HashBuffer, digest) { + return fmt.Errorf("BPM key hash does not match the one in KM: actual:%X != in-KM:%X (hash algo: %v)", digest, m.BPKey.HashBuffer, m.BPKey.HashAlg) + } + + return nil +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (m *BGManifest) Validate() error { + // Recursively validating a child structure: + if err := m.KeyAndSignature.Validate(); err != nil { + return fmt.Errorf("error on field 'KeyAndSignature': %w", err) + } + + return nil +} + +// StructureIDManifest is the StructureID (in terms of +// the document #575623) of element 'Manifest'. +const StructureIDManifest = "__KEYM__" + +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (m *BGManifest) GetStructInfo() cbnt.StructInfo { + return m.StructInfoBG +} + +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (m *BGManifest) SetStructInfo(newStructInfo cbnt.StructInfo) { + m.StructInfoBG = newStructInfo.(cbnt.StructInfoBG) +} + +// ReadFrom reads the Manifest from 'r' in format defined in the document #575623. +func (m *BGManifest) ReadFrom(r io.Reader) (int64, error) { + return m.Common.ReadFrom(r, m) +} + +// WriteTo writes the Manifest into 'w' in format defined in +// the document #575623. +func (m *BGManifest) WriteTo(w io.Writer) (int64, error) { + return m.Common.WriteTo(w, m) +} + +func (m *BGManifest) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return m.StructInfoBG.TotalSize() }, + Value: func() any { return m.StructInfoBG }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: "KM Version", + Size: func() uint64 { return 1 }, + Value: func() any { return &m.KMVersion }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 2, + Name: "KMSVN", + Size: func() uint64 { return 1 }, + Value: func() any { return &m.KMSVN }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 3, + Name: "KMID", + Size: func() uint64 { return 1 }, + Value: func() any { return &m.KMID }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 4, + Name: "BP Key", + Size: func() uint64 { return m.BPKey.TotalSize() }, + Value: func() any { return &m.BPKey }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 5, + Name: "Key And Signature", + Size: func() uint64 { return m.KeyAndSignature.TotalSize() }, + Value: func() any { return &m.KeyAndSignature }, + Type: cbnt.ManifestFieldSubStruct, + }, + } +} + +func (m *BGManifest) SizeOf(id int) (uint64, error) { + ret, err := m.Common.SizeOf(m, id) + if err != nil { + return ret, fmt.Errorf("CBnTManifest: %v", err) + } + + return ret, nil +} + +func (m *BGManifest) OffsetOf(id int) (uint64, error) { + ret, err := m.Common.OffsetOf(m, id) + if err != nil { + return ret, fmt.Errorf("CBnTManifest: %v", err) + } + + return ret, nil +} + +// Size returns the total size of the Manifest. +func (m *BGManifest) TotalSize() uint64 { + if m == nil { + return 0 + } + + return m.Common.TotalSize(m) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (m *BGManifest) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return m.Common.PrettyString(depth, withHeader, m, "BG Key Manifest", opts...) +} + +func (m *BGManifest) Print() { + if len(m.KeyAndSignature.Signature.Data) < 1 { + fmt.Printf("%v\n", m.PrettyString(1, true, pretty.OptionOmitKeySignature(true))) + fmt.Printf(" --KeyAndSignature--\n\tKey Manifest not signed!\n\n") + } else { + fmt.Printf("%v\n", m.PrettyString(1, true, pretty.OptionOmitKeySignature(false))) + } +} diff --git a/pkg/intel/metadata/cbnt/keymanifest/manifest_cbnt.go b/pkg/intel/metadata/cbnt/keymanifest/manifest_cbnt.go new file mode 100644 index 00000000..05ebc345 --- /dev/null +++ b/pkg/intel/metadata/cbnt/keymanifest/manifest_cbnt.go @@ -0,0 +1,368 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbntkey + +import ( + "bytes" + "crypto" + "encoding/binary" + "fmt" + "io" + "strings" + + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) + +// PrettyString: CBnT Key Manifest +type CBnTManifest struct { + cbnt.Common + cbnt.StructInfoCBNT `id:"__KEYM__" version:"0x21" var0:"0" var1:"0"` + + // KeyManifestSignatureOffset is Key Manifest KeySignature offset. + // + // The original name is "KeySignatureOffset" (in #575623). + KeyManifestSignatureOffset uint16 `rehashValue:"KeyAndSignatureOffset()" json:"kmSigOffset,omitempty"` + + // Reserved2 is an alignment. + Reserved2 [3]byte `json:"kmReserved2,omitempty"` + + // Revision is the revision of the Key Manifest defined by the Platform + // Manufacturer. + Revision uint8 `json:"kmRevision"` + + // KMSVN is the Key Manifest Security Version Number. + KMSVN cbnt.SVN `json:"kmSVN"` + + // KMID is the Key Manifest Identifier. + KMID uint8 `json:"kmID"` + + // PubKeyHashAlg is the hash algorithm of OEM public key digest programmed + // into the FPF. + PubKeyHashAlg cbnt.Algorithm `json:"kmPubKeyHashAlg"` + + // Hash is the slice of KMHASH_STRUCT (KHS) structures (see table 5-3 + // of the document #575623). Describes BPM pubkey digest (among other). + Hash HashList `json:"kmHash"` + + // KeyAndSignature is the Key Manifest signature. + KeyAndSignature cbnt.KeySignature `json:"kmKeySignature"` +} + +type HashList []Hash + +func (l *HashList) Structures() []cbnt.Structure { + out := make([]cbnt.Structure, 0, len(*l)) + for i := range *l { + out = append(out, &(*l)[i]) + } + return out +} + +func (m *CBnTManifest) SetSignature( + algo cbnt.Algorithm, + hashAlgo cbnt.Algorithm, + privKey crypto.Signer, + signedData []byte, +) error { + err := m.KeyAndSignature.SetSignature(algo, hashAlgo, privKey, signedData) + if err != nil { + return fmt.Errorf("unable to set the signature: %w", err) + } + m.PubKeyHashAlg = m.KeyAndSignature.Signature.HashAlg + + return nil +} + +func (m *CBnTManifest) ValidateBPMKey(bpmKS cbnt.KeySignature) error { + hashCount := 0 + for _, hashEntry := range m.Hash { + if !hashEntry.Usage.IsSet(UsageBPMSigningPKD) { + continue + } + + h, err := hashEntry.Digest.HashAlg.Hash() + if err != nil { + return fmt.Errorf("invalid hash algo %v: %w", hashEntry.Digest.HashAlg, err) + } + + if len(hashEntry.Digest.HashBuffer) != h.Size() { + return fmt.Errorf("invalid hash lenght: actual:%d expected:%d", len(hashEntry.Digest.HashBuffer), h.Size()) + } + + switch bpmKS.Key.KeyAlg { + case cbnt.AlgRSA: + if _, err := h.Write(bpmKS.Key.Data[4:]); err != nil { + return fmt.Errorf("unable to hash: %w", err) + } + default: + return fmt.Errorf("unsupported key algorithm: %v", bpmKS.Key.KeyAlg) + } + digest := h.Sum(nil) + + if !bytes.Equal(hashEntry.Digest.HashBuffer, digest) { + return fmt.Errorf("BPM key hash does not match the one in KM: actual:%X != in-KM:%X (hash algo: %v)", digest, hashEntry.Digest.HashBuffer, hashEntry.Digest.HashAlg) + } + hashCount++ + } + + if hashCount == 0 { + return fmt.Errorf("no hash of BPM's key was found in KM") + } + + return nil +} + +func (m *CBnTManifest) Validate() error { + v, err := m.OffsetOf(8) + if err != nil { + return fmt.Errorf("error on field 'KeyAndSignature': %w", err) + } + expectedValue := uint16(v) + if m.KeyManifestSignatureOffset != expectedValue { + return fmt.Errorf("field 'KeyManifestSignatureOffset' expects write-value '%v', but has %v", expectedValue, m.KeyManifestSignatureOffset) + } + // Recursively validating a child structure: + if err := m.KeyAndSignature.Validate(); err != nil { + return fmt.Errorf("error on field 'KeyAndSignature': %w", err) + } + + return nil +} + +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (m *CBnTManifest) GetStructInfo() cbnt.StructInfo { + return m.StructInfoCBNT +} + +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (m *CBnTManifest) SetStructInfo(newStructInfo cbnt.StructInfo) { + m.StructInfoCBNT = newStructInfo.(cbnt.StructInfoCBNT) +} + +// ReadFrom reads the Manifest from 'r' in format defined in the document #575623. +func (m *CBnTManifest) ReadFrom(r io.Reader) (int64, error) { + return m.Common.ReadFrom(r, m) +} + +// RehashRecursive calls Rehash (see below) recursively. +func (m *CBnTManifest) RehashRecursive() { + m.Rehash() +} + +// Rehash sets values which are calculated automatically depending on the rest +// data. It is usually about the total size field of an element. +func (m *CBnTManifest) Rehash() { + m.Variable0 = 0 + m.ElementSize = 0 + v, err := m.OffsetOf(8) + if err != nil { + // TODO: this will never be true, but still lets think of how to handle + fmt.Println("offset fail (todo handle better)") + } + m.KeyManifestSignatureOffset = uint16(v) +} + +// WriteTo writes the Manifest into 'w' in format defined in +// the document #575623. +func (m *CBnTManifest) WriteTo(w io.Writer) (int64, error) { + m.Rehash() + return m.Common.WriteTo(w, m) +} + +func (m *CBnTManifest) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return m.StructInfoCBNT.TotalSize() }, + Value: func() any { return m.StructInfoCBNT }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: "Key Manifest Signature Offset", + Size: func() uint64 { return 2 }, + Value: func() any { return &m.KeyManifestSignatureOffset }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 2, + Name: "Reserved 2", + Size: func() uint64 { return 3 }, + Value: func() any { return &m.Reserved2 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 3, + Name: "Revision", + Size: func() uint64 { return 1 }, + Value: func() any { return &m.Revision }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 4, + Name: "KMSVN", + Size: func() uint64 { return 1 }, + Value: func() any { return &m.KMSVN }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 5, + Name: "KMID", + Size: func() uint64 { return 1 }, + Value: func() any { return &m.KMID }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 6, + Name: "Pub Key Hash Alg", + Size: func() uint64 { return 2 }, + Value: func() any { return &m.PubKeyHashAlg }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 7, + Name: fmt.Sprintf("Hash: Array of \"Key Manifest\" of length %d", len(m.Hash)), + Size: func() uint64 { + size := uint64(binary.Size(uint16(0))) + for idx := range m.Hash { + size += m.Hash[idx].TotalSize() + } + return size + }, + Value: func() any { return &m.Hash }, + Type: cbnt.ManifestFieldList, + ReadList: func(r io.Reader) (int64, error) { + var count uint16 + err := binary.Read(r, binary.LittleEndian, &count) + if err != nil { + return 0, fmt.Errorf("unable to read the count for field 'Hash': %w", err) + } + totalN := int64(binary.Size(count)) + m.Hash = make([]Hash, count) + for idx := range m.Hash { + n, err := m.Hash[idx].ReadFrom(r) + if err != nil { + return totalN, fmt.Errorf("unable to read field 'Hash[%d]': %w", idx, err) + } + totalN += int64(n) + } + return totalN, nil + }, + WriteList: func(w io.Writer) (int64, error) { + count := uint16(len(m.Hash)) + if err := binary.Write(w, binary.LittleEndian, &count); err != nil { + return 0, fmt.Errorf("unable to write the count for field 'Hash': %w", err) + } + totalN := int64(binary.Size(count)) + + for idx := range m.Hash { + n, err := m.Hash[idx].WriteTo(w) + if err != nil { + return totalN, fmt.Errorf("unable to write field 'Hash[%d]': %w", idx, err) + } + totalN += int64(n) + } + + return totalN, nil + }, + }, + { + ID: 8, + Name: "Key And Signature", + Size: func() uint64 { return m.KeyAndSignature.TotalSize() }, + Value: func() any { return &m.KeyAndSignature }, + Type: cbnt.ManifestFieldSubStruct, + }, + } +} + +func (m *CBnTManifest) SizeOf(id int) (uint64, error) { + ret, err := m.Common.SizeOf(m, id) + if err != nil { + return ret, fmt.Errorf("CBnTManifest: %v", err) + } + + return ret, nil +} + +func (m *CBnTManifest) OffsetOf(id int) (uint64, error) { + ret, err := m.Common.OffsetOf(m, id) + if err != nil { + return ret, fmt.Errorf("CBnTManifest: %v", err) + } + + return ret, nil +} + +// Size returns the total size of the Manifest. +func (m *CBnTManifest) TotalSize() uint64 { + if m == nil { + return 0 + } + + return m.Common.TotalSize(m) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (m *CBnTManifest) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + var lines []string + if withHeader { + lines = append(lines, pretty.Header(depth, "CBnT Key Manifest", m)) + } + if m == nil { + return strings.Join(lines, "\n") + } + + lines = append(lines, pretty.SubValue(depth+1, "Struct Info", "", &m.StructInfoCBNT, opts...)...) + lines = append(lines, pretty.SubValue(depth+1, "Key Manifest Signature Offset", "", &m.KeyManifestSignatureOffset, opts...)...) + lines = append(lines, pretty.SubValue(depth+1, "Reserved 2", "", &m.Reserved2, opts...)...) + lines = append(lines, pretty.SubValue(depth+1, "Revision", "", &m.Revision, opts...)...) + lines = append(lines, pretty.SubValue(depth+1, "KMSVN", "", &m.KMSVN, opts...)...) + lines = append(lines, pretty.SubValue(depth+1, "KMID", "", &m.KMID, opts...)...) + lines = append(lines, pretty.SubValue(depth+1, "Pub Key Hash Alg", "", &m.PubKeyHashAlg, opts...)...) + + lines = append(lines, pretty.Header( + depth+1, + fmt.Sprintf("Hash: Array of \"Key Manifest\" of length %d", len(m.Hash)), + m.Hash, + )) + for i := 0; i < len(m.Hash); i++ { + lines = append( + lines, + fmt.Sprintf("%sitem #%d: ", strings.Repeat(" ", int(depth+2)), i)+ + strings.TrimSpace(m.Hash[i].PrettyString(depth+2, true, opts...)), + ) + } + + if depth < 1 { + lines = append(lines, "") + } + + lines = append(lines, pretty.SubValue(depth+1, "Key And Signature", "", &m.KeyAndSignature, opts...)...) + + if depth < 2 { + lines = append(lines, "") + } + + return strings.Join(lines, "\n") +} + +// Print prints the Key Manifest. +func (m *CBnTManifest) Print() { + if len(m.KeyAndSignature.Signature.Data) < 1 { + fmt.Printf("%v\n", m.PrettyString(1, true, pretty.OptionOmitKeySignature(true))) + fmt.Printf(" --KeyAndSignature--\n\tKey Manifest not signed!\n\n") + } else { + fmt.Printf("%v\n", m.PrettyString(1, true, pretty.OptionOmitKeySignature(false))) + } +} diff --git a/pkg/intel/metadata/cbnt/keymanifest/manifest_test.go b/pkg/intel/metadata/cbnt/keymanifest/manifest_test.go new file mode 100644 index 00000000..3b478840 --- /dev/null +++ b/pkg/intel/metadata/cbnt/keymanifest/manifest_test.go @@ -0,0 +1,29 @@ +// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbntkey + +import ( + "testing" + + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/integration" +) + +func TestReadWriteBG(t *testing.T) { + m, err := NewManifest(cbnt.Version10) + if err != nil { + t.Fatalf("%v", err) + } + integration.ManifestReadWrite(t, m, "testdata/km_bg.bin") +} + +func TestReadWriteCBNT(t *testing.T) { + m, err := NewManifest(cbnt.Version20) + if err != nil { + t.Fatalf("%v", err) + } + integration.ManifestReadWrite(t, m, "testdata/km_cbnt.bin") + +} diff --git a/pkg/intel/metadata/cbnt/keymanifest/testdata/km_bg.bin b/pkg/intel/metadata/cbnt/keymanifest/testdata/km_bg.bin new file mode 100644 index 0000000000000000000000000000000000000000..829a943fc9111430fed59e748121c7c23c173345 GIT binary patch literal 577 zcmV-H0>1rUUrR+T0RRvH2mt^A0D~8w{W4T_xurF^OX>SZgSg)j((<9gNYaB|Bh{R(lQ%Zcq1(8#Wfb_fXy#6H1wMkP6q7H*sD$9pwMCq7vXT~yWr$d7hoSG<(`=^&@ zw0kpIa~c_u`ImNk=;q6*Klg5Q3Mmvjb{nUZpYz*JEa6<^w>w!C8}gxmTB=lZlF?in z@GtWicU~uUrnP}mGGj9_R0-hF$v1F7y1qD>>l7o3- z_=?|WU`%TmoD={M00;{J1%`on|0qy`D|;ec%X43lt;`ohT9lPWo1bDLRaeetUWANU zQSyu_?`TVCbe2s~?Whi%T^Wu|-MShUaC|}5y9r~A)>%al5NBwJ=WSd~gWF8iu=8o` z4q8&D@6*U{CxDX@-s^J#{@*OTziqi)nDSr;8vw0%N{pM119{YPS@OOBGjeWrUyd4F zj3|Z^@-Cp!78qT132RGE9T4IFnjM=VV%(cWf5#~Gq!Q}5ne<|n;ezKm)oiUuIt7MI z@Wb-x$*nxU@kF$AA{XhFGwZeOqu5PM#(Y*__WXPJV5KqrT#5N>l20RRvH2mt^A0C&#OXm=9|ncNB@$T+xej))L?#nz(!)xUbn zI^)QmVjZ{Jbb~bvsfka4$BELUmz|U0tW#^xa4I349huIUHbB4+#LbWc{Cb6ih3ODJ z8P|c*Oc8k5H~++`=^%Sd$>mD}EsA5fIvpvuZ7WtbU&6(pBHnpjT)Dw0wjKHC$9E++ z@tE>np|wgz7D$hK4Y$E2NVzqwu1;Mm#A>~Fq|Rc12`xcm9-=%(mrr3 zG-o)iEO00;{JH=mU|)%oStE{6qOO}=bLyWJC9Q1~_J zEVokAb#h@NT3QCzEaDLF9-=lMZ|W(*(nJjc=Ijdem!edp(+3YC*>5e z$s#bU=>e~mh^4*y{x}Hi_1qL2=}GXcYp`BtV^Tw!4dlF6>kTZ>Xa?#{4P~el_FTwm z69T~WMrACn86-a%YE Date: Thu, 23 Apr 2026 15:30:36 +0200 Subject: [PATCH 24/40] feat(intel/manifest): merged BPM and adaptations to Common methods Similarly as with KM, merge BG and CBnT BPM. Constructor returns version specific implementation of BPM. No logical changes apart from usage of Common for shared methods in the Manifest implementation. Signed-off-by: Michal Gorlas --- .../metadata/cbnt/bootpolicy/manifest.go | 1128 +++++++++++++++++ .../metadata/cbnt/bootpolicy/manifest_test.go | 36 + 2 files changed, 1164 insertions(+) create mode 100644 pkg/intel/metadata/cbnt/bootpolicy/manifest.go create mode 100644 pkg/intel/metadata/cbnt/bootpolicy/manifest_test.go diff --git a/pkg/intel/metadata/cbnt/bootpolicy/manifest.go b/pkg/intel/metadata/cbnt/bootpolicy/manifest.go new file mode 100644 index 00000000..cc37dec6 --- /dev/null +++ b/pkg/intel/metadata/cbnt/bootpolicy/manifest.go @@ -0,0 +1,1128 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cbntbootpolicy provides Boot Policy Manifest and its child +// structures representation +package cbntbootpolicy + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "fmt" + "io" + "strings" + + pkgbytes "github.com/linuxboot/fiano/pkg/bytes" + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" + "github.com/linuxboot/fiano/pkg/uefi" +) + +type Manifest interface { + cbnt.Manifest +} + +// NewManifest returns a new instance of Manifest with +// all default values set. +func NewManifest(bgv cbnt.BootGuardVersion) (Manifest, error) { + bpmh, err := NewBPMH(bgv) + if err != nil { + return nil, err + } + + pmse, err := NewSignature(bgv) + if err != nil { + return nil, err + } + + switch bgv { + case cbnt.Version10: + bgBPMH, ok := bpmh.(*BPMHBG) + if !ok { + return nil, fmt.Errorf("unexpected BPMH type %T for BG", bpmh) + } + m := &ManifestBG{BPMHBG: *bgBPMH, PMSE: *pmse} + m.Rehash() + return m, nil + case cbnt.Version20, cbnt.Version21: + cbntBPMH, ok := bpmh.(*BPMHCBnT) + if !ok { + return nil, fmt.Errorf("unexpected BPMH type %T for CBnT", bpmh) + } + m := &ManifestCBnT{BPMHCBnT: *cbntBPMH, PMSE: *pmse} + m.Rehash() + return m, nil + default: + return nil, fmt.Errorf("version not supported") + } +} + +// PrettyString: Boot Policy Manifest +type ManifestBG struct { + cbnt.Common + // PrettyString: BPMH: Header + BPMHBG `rehashValue:"rehashedBPMH()" json:"bpmHeader"` + SE []SEBG `json:"bpmSE"` + // PrettyString: PME: Platform Manufacturer + PME *PMBG `json:"bpmPME,omitempty"` + // PrettyString: PMSE: Signature + PMSE Signature `json:"bpmSignature"` +} + +func (s ManifestBG) MarshalJSON() ([]byte, error) { + type signatureJSON struct { + StructInfoID cbnt.StructureID `json:"StructInfoID"` + StructInfoVersion uint8 `json:"StructInfoVersion"` + SigKeySignature cbnt.KeySignature `json:"sigKeySignature"` + } + + type manifestBGJSON struct { + BPMHBG BPMHBG `json:"bpmHeader"` + SE []SEBG `json:"bpmSE"` + PME *PMBG `json:"bpmPME,omitempty"` + PMSE signatureJSON `json:"bpmSignature"` + } + + sigInfo := cbnt.StructInfoBG{} + if info, ok := s.PMSE.StructInfo.(cbnt.StructInfoBG); ok { + sigInfo = info + } + + out := manifestBGJSON{ + BPMHBG: s.BPMHBG, + SE: s.SE, + PME: s.PME, + PMSE: signatureJSON{ + StructInfoID: sigInfo.ID, + StructInfoVersion: sigInfo.Version, + SigKeySignature: s.PMSE.KeySignature, + }, + } + + return json.Marshal(out) +} + +func (s *ManifestBG) UnmarshalJSON(data []byte) error { + type signatureJSON struct { + StructInfoID cbnt.StructureID `json:"StructInfoID"` + StructInfoVersion uint8 `json:"StructInfoVersion"` + SigKeySignature cbnt.KeySignature `json:"sigKeySignature"` + } + + type manifestBGJSON struct { + BPMHBG BPMHBG `json:"bpmHeader"` + SE []SEBG `json:"bpmSE"` + PME *PMBG `json:"bpmPME,omitempty"` + PMSE signatureJSON `json:"bpmSignature"` + } + + var in manifestBGJSON + if err := json.Unmarshal(data, &in); err != nil { + return err + } + + s.BPMHBG = in.BPMHBG + s.SE = in.SE + s.PME = in.PME + + structInfo := cbnt.StructInfoBG{ + ID: in.PMSE.StructInfoID, + Version: in.PMSE.StructInfoVersion, + } + if structInfo.ID == (cbnt.StructureID{}) { + copy(structInfo.ID[:], []byte(StructureIDSignature)) + } + if structInfo.Version == 0 { + structInfo.Version = 0x10 + } + + s.PMSE = Signature{ + StructInfo: structInfo, + KeySignature: in.PMSE.SigKeySignature, + } + + return nil +} + +// PrettyString: Boot Policy Manifest +type ManifestCBnT struct { + cbnt.Common + // BPMH is the header of the boot policy manifest + // + // PrettyString: BPMH: Header + BPMHCBnT `rehashValue:"rehashedBPMH()" json:"bpmHeader"` + + SE []SECBnT `json:"bpmSE"` + TXTE *TXT `json:"bpmTXTE,omitempty"` + Res *Reserved `json:"bpmReserved,omitempty"` + + // PCDE is the platform configuration data element + // + // PrettyString: PCDE: Platform Config Data + PCDE *PCD `json:"bpmPCDE,omitempty"` + + // PME is the platform manufacturer element + // + // PrettyString: PME: Platform Manufacturer + PME *PMCBnT `json:"bpmPME,omitempty"` + + // PMSE is the signature element + // + // PrettyString: PMSE: Signature + PMSE Signature `json:"bpmSignature"` +} + +func (s ManifestCBnT) MarshalJSON() ([]byte, error) { + type signatureJSON struct { + StructInfoID cbnt.StructureID `json:"StructInfoID"` + StructInfoVersion uint8 `json:"StructInfoVersion"` + StructInfoVariable0 uint8 `json:"StructInfoVariable0"` + StructInfoElementSize uint16 `json:"StructInfoElementSize"` + SigKeySignature cbnt.KeySignature `json:"sigKeySignature"` + } + + type manifestCBnTJSON struct { + BPMHCBnT BPMHCBnT `json:"bpmHeader"` + SE []SECBnT `json:"bpmSE"` + TXTE *TXT `json:"bpmTXTE,omitempty"` + Res *Reserved `json:"bpmReserved,omitempty"` + PCDE *PCD `json:"bpmPCDE,omitempty"` + PME *PMCBnT `json:"bpmPME,omitempty"` + PMSE signatureJSON `json:"bpmSignature"` + } + + sigInfo := cbnt.StructInfoCBNT{} + if info, ok := s.PMSE.StructInfo.(cbnt.StructInfoCBNT); ok { + sigInfo = info + } + + out := manifestCBnTJSON{ + BPMHCBnT: s.BPMHCBnT, + SE: s.SE, + TXTE: s.TXTE, + Res: s.Res, + PCDE: s.PCDE, + PME: s.PME, + PMSE: signatureJSON{ + StructInfoID: sigInfo.ID, + StructInfoVersion: sigInfo.Version, + StructInfoVariable0: sigInfo.Variable0, + StructInfoElementSize: sigInfo.ElementSize, + SigKeySignature: s.PMSE.KeySignature, + }, + } + + return json.Marshal(out) +} + +func (s *ManifestCBnT) UnmarshalJSON(data []byte) error { + type signatureJSON struct { + StructInfoID cbnt.StructureID `json:"StructInfoID"` + StructInfoVersion uint8 `json:"StructInfoVersion"` + StructInfoVariable0 uint8 `json:"StructInfoVariable0"` + StructInfoElementSize uint16 `json:"StructInfoElementSize"` + SigKeySignature cbnt.KeySignature `json:"sigKeySignature"` + } + + type manifestCBnTJSON struct { + BPMHCBnT BPMHCBnT `json:"bpmHeader"` + SE []SECBnT `json:"bpmSE"` + TXTE *TXT `json:"bpmTXTE,omitempty"` + Res *Reserved `json:"bpmReserved,omitempty"` + PCDE *PCD `json:"bpmPCDE,omitempty"` + PME *PMCBnT `json:"bpmPME,omitempty"` + PMSE signatureJSON `json:"bpmSignature"` + } + + var in manifestCBnTJSON + if err := json.Unmarshal(data, &in); err != nil { + return err + } + + s.BPMHCBnT = in.BPMHCBnT + s.SE = in.SE + s.TXTE = in.TXTE + s.Res = in.Res + s.PCDE = in.PCDE + s.PME = in.PME + + structInfo := cbnt.StructInfoCBNT{ + ID: in.PMSE.StructInfoID, + Version: in.PMSE.StructInfoVersion, + Variable0: in.PMSE.StructInfoVariable0, + ElementSize: in.PMSE.StructInfoElementSize, + } + if structInfo.ID == (cbnt.StructureID{}) { + copy(structInfo.ID[:], []byte(StructureIDSignature)) + } + if structInfo.Version == 0 { + structInfo.Version = 0x20 + } + + s.PMSE = Signature{ + StructInfo: structInfo, + KeySignature: in.PMSE.SigKeySignature, + } + + return nil +} + +// fieldIndexByStructID returns the position index within +// structure Manifest of the field by its StructureID +// (see document #575623, an example of StructureID value is "__KEYM__"). +func (ManifestBG) fieldIndexByStructID(structID string) int { + switch structID { + case StructureIDBPMH: + return 0 + case StructureIDSE: + return 1 + case StructureIDPM: + return 2 + case StructureIDSignature: + return 3 + } + + return -1 +} + +// fieldNameByIndex returns the name of the field by its position number +// within structure Manifest. +func (ManifestBG) fieldNameByIndex(fieldIndex int) string { + switch fieldIndex { + case 0: + return "BPMH" + case 1: + return "SE" + case 2: + return "PME" + case 3: + return "PMSE" + } + + return fmt.Sprintf("invalidFieldIndex_%d", fieldIndex) +} + +// Validate (recursively) checks the structure if there are any unexpected values. +func (s *ManifestBG) Validate() error { + if err := s.BPMHBG.Validate(); err != nil { + return fmt.Errorf("error on field 'BPMH': %w", err) + } + expectedValue := s.rehashedBPMH() + if s.BPMHBG != expectedValue { + return fmt.Errorf("field 'BPMH' expects write-value '%v', but has %v", expectedValue, s.BPMHBG) + } + if err := s.PMSE.Validate(); err != nil { + return fmt.Errorf("error on field 'PMSE': %w", err) + } + + return nil +} + +func (s *ManifestBG) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "BPMH", + Size: func() uint64 { return s.BPMHBG.TotalSize() }, + Value: func() any { return &s.BPMHBG }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: fmt.Sprintf("SE: Array of \"Boot Policy Manifest\" of length %d", len(s.SE)), + Size: func() uint64 { + var size uint64 + for idx := range s.SE { + size += s.SE[idx].TotalSize() + } + return size + }, + Value: func() any { return &s.SE }, + Type: cbnt.ManifestFieldList, + WriteList: func(w io.Writer) (int64, error) { + totalN := int64(0) + for idx := range s.SE { + n, err := s.SE[idx].WriteTo(w) + if err != nil { + return totalN, fmt.Errorf("unable to write field 'SE[%d]': %w", idx, err) + } + totalN += int64(n) + } + return totalN, nil + }, + }, + { + ID: 2, + Name: "PME", + Size: func() uint64 { + if s.PME == nil { + return 0 + } + return s.PME.TotalSize() + }, + Value: func() any { + if s.PME == nil { + return nil + } + return s.PME + }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 3, + Name: "PMSE", + Size: func() uint64 { return s.PMSE.TotalSize() }, + Value: func() any { return &s.PMSE }, + Type: cbnt.ManifestFieldSubStruct, + }, + } +} + +func (s *ManifestBG) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("Manifest: %v", err) + } + return ret, nil +} + +func (s *ManifestBG) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("Manifest: %v", err) + } + return ret, nil +} + +// ReadFrom reads the Manifest from 'r' in format defined in the document #575623. +// Note that the BPM is a special case: we do not use common way of handling the reading here. +func (s *ManifestBG) ReadFrom(r io.Reader) (returnN int64, returnErr error) { + var missingFieldsByIndices = [4]bool{ + 0: true, + 3: true, + } + defer func() { + if returnErr != nil { + return + } + for fieldIndex, v := range missingFieldsByIndices { + if v { + returnErr = fmt.Errorf("field '%s' is missing", s.fieldNameByIndex(fieldIndex)) + break + } + } + }() + var totalN int64 + previousFieldIndex := int(-1) + for { + var structInfo cbnt.StructInfoBG + err := binary.Read(r, binary.LittleEndian, &structInfo) + if err == io.EOF || err == io.ErrUnexpectedEOF { + return totalN, nil + } + if err != nil { + return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) + } + structID := structInfo.ID.String() + fieldIndex := s.fieldIndexByStructID(structID) + if fieldIndex < 0 { + // Let's just warn about unknown struct, no need to fail completely + fmt.Printf("warning: unknown structure ID: %s\n", structID) + continue + } + totalN += int64(binary.Size(structInfo)) + if cbnt.StrictOrderCheck && fieldIndex < previousFieldIndex { + return totalN, fmt.Errorf("invalid order of fields (%d < %d): structure '%s' is out of order", fieldIndex, previousFieldIndex, structID) + } + missingFieldsByIndices[fieldIndex] = false + + var n int64 + switch structID { + case StructureIDBPMH: + if fieldIndex == previousFieldIndex { + return totalN, fmt.Errorf("field 'BPMH' is not a slice, but multiple elements found") + } + s.SetStructInfo(structInfo) + n, err = s.ReadFromHelper(r, false) + if err != nil { + return totalN, fmt.Errorf("unable to read field BPMH at %d: %w", totalN, err) + } + case StructureIDSE: + var el SEBG + el.SetStructInfo(structInfo) + n, err = el.ReadFromHelper(r, false) + s.SE = append(s.SE, el) + if err != nil { + return totalN, fmt.Errorf("unable to read field SE at %d: %w", totalN, err) + } + case StructureIDPM: + if fieldIndex == previousFieldIndex { + return totalN, fmt.Errorf("field 'PME' is not a slice, but multiple elements found") + } + s.PME = &PMBG{} + s.PME.SetStructInfo(structInfo) + n, err = s.PME.ReadFromHelper(r, false) + if err != nil { + return totalN, fmt.Errorf("unable to read field PME at %d: %w", totalN, err) + } + case StructureIDSignature: + if fieldIndex == previousFieldIndex { + return totalN, fmt.Errorf("field 'PMSE' is not a slice, but multiple elements found") + } + s.PMSE.SetStructInfo(structInfo) + n, err = s.PMSE.ReadFromHelper(r, false) + if err != nil { + return totalN, fmt.Errorf("unable to read field PMSE at %d: %w", totalN, err) + } + default: + return totalN, fmt.Errorf("there is no field with structure ID '%s' in Manifest", structInfo.ID) + } + totalN += n + previousFieldIndex = fieldIndex + } + +} + +func (s *ManifestBG) RehashRecursive() { + s.Rehash() +} + +func (s *ManifestBG) Rehash() { + s.BPMHBG = s.rehashedBPMH() +} + +func (s *ManifestBG) WriteTo(w io.Writer) (int64, error) { + s.Rehash() + return s.Common.WriteTo(w, s) +} + +func (s *ManifestBG) TotalSize() uint64 { + if s == nil { + return 0 + } + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *ManifestBG) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + var lines []string + if withHeader { + lines = append(lines, pretty.Header(depth, "Boot Policy Manifest", s)) + } + if s == nil { + return strings.Join(lines, "\n") + } + // ManifestFieldType is element + lines = append(lines, pretty.SubValue(depth+1, "BPMH: Header", "", &s.BPMHBG, opts...)...) + // ManifestFieldType is elementList + lines = append(lines, pretty.Header(depth+1, fmt.Sprintf("SE: Array of \"Boot Policy Manifest\" of length %d", len(s.SE)), s.SE)) + for i := 0; i < len(s.SE); i++ { + lines = append(lines, fmt.Sprintf("%sitem #%d: ", strings.Repeat(" ", int(depth+2)), i)+strings.TrimSpace(s.SE[i].PrettyString(depth+2, true))) + } + if depth < 1 { + lines = append(lines, "") + } + // ManifestFieldType is element + lines = append(lines, pretty.SubValue(depth+1, "PME: Platform Manufacturer", "", s.PME, opts...)...) + // ManifestFieldType is element + lines = append(lines, pretty.SubValue(depth+1, "PMSE: Signature", "", &s.PMSE, opts...)...) + if depth < 2 { + lines = append(lines, "") + } + return strings.Join(lines, "\n") +} + +func (s *ManifestBG) StructInfo() cbnt.StructInfo { + return s.StructInfoBG +} + +func (s *ManifestBG) GetStructInfo() cbnt.StructInfo { + return s.StructInfoBG +} + +func (s *ManifestBG) SetStructInfo(newStructInfo cbnt.StructInfo) { + s.StructInfoBG = newStructInfo.(cbnt.StructInfoBG) +} + +func (s *ManifestBG) ValidateIBB(firmware uefi.Firmware) error { + if s.SE[0].Digest.TotalSize() == 0 { + return fmt.Errorf("no IBB hashes") + } + + digest := s.SE[0].Digest + h, err := digest.HashAlg.Hash() + if err != nil { + return fmt.Errorf("invalid hash function: %v", digest.HashAlg) + } + + imgSize := uint64((len(firmware.Buf()))) + if ifdSize, ifdErr := FlashSizeIFD(firmware.Buf()); ifdErr == nil && ifdSize > 0 && ifdSize <= imgSize { + imgSize = ifdSize + } + + for _, r := range s.IBBDataRanges(imgSize) { + if _, err := h.Write(firmware.Buf()[r.Offset:r.End()]); err != nil { + return fmt.Errorf("unable to hash: %w", err) + } + } + hashValue := h.Sum(nil) + + if !bytes.Equal(hashValue, digest.HashBuffer) { + return fmt.Errorf("IBB %s hash mismatch: %X != %X", digest.HashAlg, hashValue, digest.HashBuffer) + } + + return nil +} + +// IBBDataRanges returns data ranges of IBB. +func (s *ManifestBG) IBBDataRanges(firmwareSize uint64) pkgbytes.Ranges { + return ibbDataRanges(s.SE[0].IBBSegments, firmwareSize) +} + +func (s *ManifestBG) rehashedBPMH() BPMHBG { + return s.BPMHBG +} + +func (s ManifestBG) Print() { + fmt.Printf("%v", s.BPMHBG.PrettyString(1, true)) + for _, item := range s.SE { + fmt.Printf("%v", item.PrettyString(1, true)) + } + + if s.PME != nil { + fmt.Printf("%v\n", s.PME.PrettyString(1, true)) + } else { + fmt.Println(" --PME--\n\tnot set!(optional)") + } + + if len(s.PMSE.Signature.Data) < 1 { + fmt.Printf("%v\n", s.PMSE.PrettyString(1, true, pretty.OptionOmitKeySignature(true))) + fmt.Printf(" --PMSE--\n\tBoot Policy Manifest not signed!\n\n") + } else { + fmt.Printf("%v\n", s.PMSE.PrettyString(1, true, pretty.OptionOmitKeySignature(false))) + } +} + +func (ManifestCBnT) fieldIndexByStructID(structID string) int { + switch structID { + case StructureIDBPMH: + return 0 + case StructureIDSE: + return 1 + case StructureIDTXT: + return 2 + case StructureIDReserved: + return 3 + case StructureIDPCD: + return 4 + case StructureIDPM: + return 5 + case StructureIDSignature: + return 6 + } + + return -1 +} + +func (ManifestCBnT) fieldNameByIndex(fieldIndex int) string { + switch fieldIndex { + case 0: + return "BPMH" + case 1: + return "SE" + case 2: + return "TXTE" + case 3: + return "Res" + case 4: + return "PCDE" + case 5: + return "PME" + case 6: + return "PMSE" + } + + return fmt.Sprintf("invalidFieldIndex_%d", fieldIndex) +} + +// Validate (recursively) checks the structure if there are any unexpected values. +func (s *ManifestCBnT) Validate() error { + if err := s.BPMHCBnT.Validate(); err != nil { + return fmt.Errorf("error on field 'BPMH': %w", err) + } + if s.BPMHCBnT != s.rehashedBPMH() { + return fmt.Errorf("field 'BPMH' expects write-value '%v', but has %v", s.rehashedBPMH(), s.BPMHCBnT) + } + if err := s.PMSE.Validate(); err != nil { + return fmt.Errorf("error on field 'PMSE': %w", err) + } + + if s.PCDE != nil { + if err := s.PCDE.Validate(); err != nil { + return fmt.Errorf("error on field 'PCDE': %w", err) + } + } + + return nil +} + +func (s *ManifestCBnT) Layout() []cbnt.LayoutField { + // All fields marked with omitempty have to be checked for being + // empty in the clousure for Value. Otherwise we risk some nasty errors + // even with valid (i.e. compliant with the spec) Manifests. + return []cbnt.LayoutField{ + { + ID: 0, + Name: "BPMH: Header", + Size: func() uint64 { return s.BPMHCBnT.TotalSize() }, + Value: func() any { return &s.BPMHCBnT }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: fmt.Sprintf("SE: Array of \"Boot Policy Manifest\" of length %d", len(s.SE)), + Size: func() uint64 { + var size uint64 + for idx := range s.SE { + size += s.SE[idx].TotalSize() + } + return size + }, + Value: func() any { return &s.SE }, + Type: cbnt.ManifestFieldList, + WriteList: func(w io.Writer) (int64, error) { + totalN := int64(0) + for idx := range s.SE { + n, err := s.SE[idx].WriteTo(w) + if err != nil { + return totalN, fmt.Errorf("unable to write field 'SE[%d]': %w", idx, err) + } + totalN += int64(n) + } + return totalN, nil + }, + }, + { + ID: 2, + Name: "TXTE", + Size: func() uint64 { + if s.TXTE == nil { + return 0 + } + return s.TXTE.TotalSize() + }, + Value: func() any { + if s.TXTE == nil { + return nil + } + return s.TXTE + }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 3, + Name: "Res", + Size: func() uint64 { + if s.Res == nil { + return 0 + } + return s.Res.TotalSize() + }, + Value: func() any { + if s.Res == nil { + return nil + } + return s.Res + }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 4, + Name: "PCDE: Platform Config Data", + Size: func() uint64 { + if s.PCDE == nil { + return 0 + } + return s.PCDE.TotalSize() + }, + Value: func() any { + if s.PCDE == nil { + return nil + } + return s.PCDE + }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 5, + Name: "PME: Platform Manufacturer", + Size: func() uint64 { + if s.PME == nil { + return 0 + } + return s.PME.TotalSize() + }, + Value: func() any { + if s.PME == nil { + return nil + } + return s.PME + }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 6, + Name: "PMSE: Signature", + Size: func() uint64 { return s.PMSE.TotalSize() }, + Value: func() any { return &s.PMSE }, + Type: cbnt.ManifestFieldSubStruct, + }, + } +} + +func (s *ManifestCBnT) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("Manifest: %v", err) + } + + return ret, nil +} + +func (s *ManifestCBnT) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("Manifest: %v", err) + } + + return ret, nil +} + +// ReadFrom reads the Manifest from 'r' in format defined in the document #575623. +// Same note as above: this is an exception from the rule of usijg common approach. +func (s *ManifestCBnT) ReadFrom(r io.Reader) (returnN int64, returnErr error) { + var missingFieldsByIndices = [7]bool{ + 0: true, + 6: true, + } + defer func() { + if returnErr != nil { + return + } + for fieldIndex, v := range missingFieldsByIndices { + if v { + returnErr = fmt.Errorf("field '%s' is missing", s.fieldNameByIndex(fieldIndex)) + break + } + } + }() + var totalN int64 + previousFieldIndex := int(-1) + for { + var structInfo cbnt.StructInfoCBNT + err := binary.Read(r, binary.LittleEndian, &structInfo) + if err == io.EOF || err == io.ErrUnexpectedEOF { + return totalN, nil + } + if err != nil { + return totalN, fmt.Errorf("unable to read structure info at %d: %w", totalN, err) + } + structID := structInfo.ID.String() + fieldIndex := s.fieldIndexByStructID(structID) + if fieldIndex < 0 { + fmt.Printf("warning: unknown structure ID: %s\n", structID) + continue + } + totalN += int64(binary.Size(structInfo)) + if cbnt.StrictOrderCheck && fieldIndex < previousFieldIndex { + return totalN, fmt.Errorf("invalid order of fields (%d < %d): structure '%s' is out of order", fieldIndex, previousFieldIndex, structID) + } + missingFieldsByIndices[fieldIndex] = false + + var n int64 + switch structID { + case StructureIDBPMH: + if fieldIndex == previousFieldIndex { + return totalN, fmt.Errorf("field 'BPMH' is not a slice, but multiple elements found") + } + s.SetStructInfo(structInfo) + n, err = s.ReadFromHelper(r, false) + if err != nil { + return totalN, fmt.Errorf("unable to read field BPMH at %d: %w", totalN, err) + } + case StructureIDSE: + var el SECBnT + el.SetStructInfo(structInfo) + n, err = el.ReadFromHelper(r, false) + s.SE = append(s.SE, el) + if err != nil { + return totalN, fmt.Errorf("unable to read field SE at %d: %w", totalN, err) + } + case StructureIDTXT: + if fieldIndex == previousFieldIndex { + return totalN, fmt.Errorf("field 'TXTE' is not a slice, but multiple elements found") + } + s.TXTE = &TXT{} + s.TXTE.SetStructInfo(structInfo) + n, err = s.TXTE.ReadFromHelper(r, false) + if err != nil { + return totalN, fmt.Errorf("unable to read field TXTE at %d: %w", totalN, err) + } + case StructureIDReserved: + if fieldIndex == previousFieldIndex { + return totalN, fmt.Errorf("field 'Res' is not a slice, but multiple elements found") + } + s.Res = &Reserved{} + s.Res.SetStructInfo(structInfo) + n, err = s.Res.ReadFromHelper(r, false) + if err != nil { + return totalN, fmt.Errorf("unable to read field Res at %d: %w", totalN, err) + } + case StructureIDPCD: + if fieldIndex == previousFieldIndex { + return totalN, fmt.Errorf("field 'PCDE' is not a slice, but multiple elements found") + } + s.PCDE = &PCD{} + s.PCDE.SetStructInfo(structInfo) + n, err = s.PCDE.ReadFromHelper(r, false) + if err != nil { + return totalN, fmt.Errorf("unable to read field PCDE at %d: %w", totalN, err) + } + case StructureIDPM: + if fieldIndex == previousFieldIndex { + return totalN, fmt.Errorf("field 'PME' is not a slice, but multiple elements found") + } + s.PME = &PMCBnT{} + s.PME.SetStructInfo(structInfo) + n, err = s.PME.ReadFromHelper(r, false) + if err != nil { + return totalN, fmt.Errorf("unable to read field PME at %d: %w", totalN, err) + } + case StructureIDSignature: + if fieldIndex == previousFieldIndex { + return totalN, fmt.Errorf("field 'PMSE' is not a slice, but multiple elements found") + } + s.PMSE.SetStructInfo(structInfo) + n, err = s.PMSE.ReadFromHelper(r, false) + if err != nil { + return totalN, fmt.Errorf("unable to read field PMSE at %d: %w", totalN, err) + } + default: + return totalN, fmt.Errorf("there is no field with structure ID '%s' in Manifest", structInfo.ID) + } + totalN += n + previousFieldIndex = fieldIndex + } +} + +func (s *ManifestCBnT) RehashRecursive() { + s.BPMHCBnT.Rehash() + for idx := range s.SE { + s.SE[idx].RehashRecursive() + } + if s.TXTE != nil { + s.TXTE.Rehash() + } + if s.Res != nil { + s.Res.Rehash() + } + if s.PCDE != nil { + s.PCDE.Rehash() + } + if s.PME != nil { + s.PME.Rehash() + } + s.Rehash() +} + +func (s *ManifestCBnT) Rehash() { + s.BPMHCBnT = s.rehashedBPMH() +} + +func (s *ManifestCBnT) WriteTo(w io.Writer) (int64, error) { + s.Rehash() + return s.Common.WriteTo(w, s) +} + +func (s *ManifestCBnT) TotalSize() uint64 { + if s == nil { + return 0 + } + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *ManifestCBnT) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + var lines []string + if withHeader { + lines = append(lines, pretty.Header(depth, "Boot Policy Manifest", s)) + } + if s == nil { + return strings.Join(lines, "\n") + } + // ManifestFieldType is element + lines = append(lines, pretty.SubValue(depth+1, "BPMH: Header", "", &s.BPMHCBnT, opts...)...) + // ManifestFieldType is elementList + lines = append(lines, pretty.Header(depth+1, fmt.Sprintf("SE: Array of \"Boot Policy Manifest\" of length %d", len(s.SE)), s.SE)) + for i := 0; i < len(s.SE); i++ { + lines = append(lines, fmt.Sprintf("%sitem #%d: ", strings.Repeat(" ", int(depth+2)), i)+strings.TrimSpace(s.SE[i].PrettyString(depth+2, true))) + } + if depth < 1 { + lines = append(lines, "") + } + // ManifestFieldType is element + lines = append(lines, pretty.SubValue(depth+1, "TXTE", "", s.TXTE, opts...)...) + // ManifestFieldType is element + lines = append(lines, pretty.SubValue(depth+1, "Res", "", s.Res, opts...)...) + // ManifestFieldType is element + lines = append(lines, pretty.SubValue(depth+1, "PCDE: Platform Config Data", "", s.PCDE, opts...)...) + // ManifestFieldType is element + lines = append(lines, pretty.SubValue(depth+1, "PME: Platform Manufacturer", "", s.PME, opts...)...) + // ManifestFieldType is element + lines = append(lines, pretty.SubValue(depth+1, "PMSE: Signature", "", &s.PMSE, opts...)...) + if depth < 2 { + lines = append(lines, "") + } + return strings.Join(lines, "\n") +} + +func (s *ManifestCBnT) StructInfo() cbnt.StructInfo { + return s.StructInfoCBNT +} + +func (s *ManifestCBnT) GetStructInfo() cbnt.StructInfo { + return s.StructInfoCBNT +} + +func (s *ManifestCBnT) SetStructInfo(newStructInfo cbnt.StructInfo) { + s.StructInfoCBNT = newStructInfo.(cbnt.StructInfoCBNT) +} + +// ValidateIBB returns an error if IBB segments does not match the signature. +func (s *ManifestCBnT) ValidateIBB(firmware uefi.Firmware) error { + if len(s.SE[0].DigestList.List) == 0 { + return fmt.Errorf("no IBB hashes") + } + + digest := s.SE[0].DigestList.List[0] + h, err := digest.HashAlg.Hash() + if err != nil { + return fmt.Errorf("invalid hash function: %v", digest.HashAlg) + } + + imgSize := uint64((len(firmware.Buf()))) + if ifdSize, ifdErr := FlashSizeIFD(firmware.Buf()); ifdErr == nil && ifdSize > 0 && ifdSize <= imgSize { + imgSize = ifdSize + } + + for _, r := range s.IBBDataRanges(imgSize) { + if _, err := h.Write(firmware.Buf()[r.Offset:r.End()]); err != nil { + return fmt.Errorf("unable to hash: %w", err) + } + } + hashValue := h.Sum(nil) + + if !bytes.Equal(hashValue, digest.HashBuffer) { + return fmt.Errorf("IBB %s hash mismatch: %X != %X", digest.HashAlg, hashValue, digest.HashBuffer) + } + + return nil +} + +// IBBDataRanges returns data ranges of IBB. +func (s *ManifestCBnT) IBBDataRanges(firmwareSize uint64) pkgbytes.Ranges { + return ibbDataRanges(s.SE[0].IBBSegments, firmwareSize) +} + +// Helper for IBBDataRanges. Moved to the separate func cause the logic is shared between +// CBnT and BG. +func ibbDataRanges(segments []IBBSegment, firmwareSize uint64) pkgbytes.Ranges { + var result pkgbytes.Ranges + + for _, seg := range segments { + if seg.Flags&1 == 1 { + continue + } + startIdx := CalculateOffsetFromPhysAddr(uint64(seg.Base), firmwareSize) + result = append(result, pkgbytes.Range{Offset: startIdx, Length: uint64(seg.Size)}) + } + + return result +} + +// CalculateOffsetFromPhysAddr calculates the offset within an image of a physical address. +func CalculateOffsetFromPhysAddr(physAddr uint64, imageSize uint64) uint64 { + const basePhysAddr = 1 << 32 + startAddr := basePhysAddr - imageSize + return physAddr - startAddr +} + +func FlashSizeIFD(buf []byte) (uint64, error) { + if uint64(len(buf)) < uefi.FlashDescriptorLength { + return 0, fmt.Errorf("buffer too small for flash descriptior: %d", len(buf)) + } + + fd := uefi.FlashDescriptor{} + fd.SetBuf(buf[:uefi.FlashDescriptorLength]) + if err := fd.ParseFlashDescriptor(); err != nil { + return 0, err + } + + var maxEnd uint64 + for _, fr := range fd.Region.FlashRegions { + if !fr.Valid() { + continue + } + end := uint64(fr.EndOffset()) + if end > maxEnd { + maxEnd = end + } + } + if maxEnd == 0 { + return 0, fmt.Errorf("no valid regions in flash descriptor") + } + + return maxEnd, nil + +} + +func (s *ManifestCBnT) rehashedBPMH() BPMHCBnT { + bpmh := s.BPMHCBnT + pmseOffs, _ := s.OffsetOf(6) + keySigOffs, _ := s.PMSE.OffsetOf(1) + bpmh.KeySignatureOffset = uint16(pmseOffs + keySigOffs) + return bpmh +} + +func (s ManifestCBnT) Print() { + fmt.Printf("%v", s.BPMHCBnT.PrettyString(1, true)) + for _, item := range s.SE { + fmt.Printf("%v", item.PrettyString(1, true)) + } + if s.TXTE != nil { + fmt.Printf("%v\n", s.TXTE.PrettyString(1, true)) + } else { + fmt.Printf(" --TXTE--\n\t not set!(optional)\n") + } + + if s.PCDE != nil { + fmt.Printf("%v\n", s.PCDE.PrettyString(1, true)) + } else { + fmt.Println(" --PCDE-- \n\tnot set!(optional)") + } + + if s.PME != nil { + fmt.Printf("%v\n", s.PME.PrettyString(1, true)) + } else { + fmt.Println(" --PME--\n\tnot set!(optional)") + } + + if len(s.PMSE.Signature.Data) < 1 { + fmt.Printf("%v\n", s.PMSE.PrettyString(1, true, pretty.OptionOmitKeySignature(true))) + fmt.Printf(" --PMSE--\n\tBoot Policy Manifest not signed!\n\n") + } else { + fmt.Printf("%v\n", s.PMSE.PrettyString(1, true, pretty.OptionOmitKeySignature(false))) + } +} diff --git a/pkg/intel/metadata/cbnt/bootpolicy/manifest_test.go b/pkg/intel/metadata/cbnt/bootpolicy/manifest_test.go new file mode 100644 index 00000000..a2996b8b --- /dev/null +++ b/pkg/intel/metadata/cbnt/bootpolicy/manifest_test.go @@ -0,0 +1,36 @@ +// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbntbootpolicy + +import ( + "testing" + + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/integration" +) + +func TestReadWriteBG(t *testing.T) { + m, err := NewManifest(cbnt.Version10) + if err != nil { + t.Fatalf("%v", err) + } + integration.ManifestReadWrite(t, m, "testdata/bpm10.bin") +} + +func TestReadWriteCBNT(t *testing.T) { + m, err := NewManifest(cbnt.Version20) + if err != nil { + t.Fatalf("%v", err) + } + integration.ManifestReadWrite(t, m, "testdata/bpm20.bin") +} + +func TestReadWriteCBNT21(t *testing.T) { + m, err := NewManifest(cbnt.Version21) + if err != nil { + t.Fatalf("%v", err) + } + integration.ManifestReadWrite(t, m, "testdata/bpm21.bin") +} From b0406d28772528ed6891ee49c7bb801a7d173641 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 15:37:08 +0200 Subject: [PATCH 25/40] feat(intel/metadata): adapt Reserved to use Common methods Signed-off-by: Michal Gorlas --- .../metadata/cbnt/bootpolicy/Reserved.go | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 pkg/intel/metadata/cbnt/bootpolicy/Reserved.go diff --git a/pkg/intel/metadata/cbnt/bootpolicy/Reserved.go b/pkg/intel/metadata/cbnt/bootpolicy/Reserved.go new file mode 100644 index 00000000..b4a0f03d --- /dev/null +++ b/pkg/intel/metadata/cbnt/bootpolicy/Reserved.go @@ -0,0 +1,143 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbntbootpolicy + +import ( + "fmt" + "io" + + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) + +type Reserved struct { + cbnt.Common + cbnt.StructInfoCBNT `id:"__PFRS__" version:"0x21" var0:"0" var1:"uint16(s.TotalSize())"` + ReservedData [32]byte `json:"ReservedData"` +} + +// NewReserved returns a new instance of Reserved with +// all default values set. +func NewReserved() *Reserved { + // Only present in CBnT, thus we assume StructInfoCBNT. + s := &Reserved{} + copy(s.ID[:], []byte(StructureIDReserved)) + s.Version = 0x21 + s.Rehash() + return s +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *Reserved) Validate() error { + + return nil +} + +func (s *Reserved) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return s.StructInfoCBNT.TotalSize() }, + Value: func() any { return &s.StructInfoCBNT }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: "Reserved Data", + Size: func() uint64 { return 32 }, + Value: func() any { return &s.ReservedData }, + Type: cbnt.ManifestFieldArrayStatic, + }, + } +} + +func (s *Reserved) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("Reserved: %v", err) + } + + return ret, nil +} + +func (s *Reserved) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("Reserved: %v", err) + } + + return ret, nil +} + +// StructureIDReserved is the StructureID (in terms of +// the document #575623) of element 'Reserved'. +const StructureIDReserved = "__PFRS__" + +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *Reserved) GetStructInfo() cbnt.StructInfo { + return s.StructInfoCBNT +} + +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *Reserved) SetStructInfo(newStructInfo cbnt.StructInfo) { + s.StructInfoCBNT = newStructInfo.(cbnt.StructInfoCBNT) +} + +// Dummy helper to comply with cbnt.Structure interface +func (s *Reserved) ReadFrom(r io.Reader) (int64, error) { + return s.ReadFromHelper(r, true) +} + +// ReadFrom reads the Reserved from 'r' in format defined in the document #575623. +func (s *Reserved) ReadFromHelper(r io.Reader, info bool) (int64, error) { + l := s.Layout() + + if !info { + l = l[1:] + } + + return s.Common.ReadFrom(r, cbnt.DummyLayout{Fields: l}) +} + +// RehashRecursive calls Rehash (see below) recursively. +func (s *Reserved) RehashRecursive() { + s.Rehash() +} + +// Rehash sets values which are calculated automatically depending on the rest +// data. It is usually about the total size field of an element. +func (s *Reserved) Rehash() { + s.Variable0 = 0 + s.ElementSize = uint16(s.TotalSize()) +} + +// WriteTo writes the Reserved into 'w' in format defined in +// the document #575623. +func (s *Reserved) WriteTo(w io.Writer) (int64, error) { + s.Rehash() + return s.Common.WriteTo(w, s) +} + +// Size returns the total size of the Reserved. +func (s *Reserved) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *Reserved) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return s.Common.PrettyString(depth, withHeader, s, "Reserved", opts...) +} From 4658099b97c33be61ca87880ca97bc7ebfc1a784 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 15:38:19 +0200 Subject: [PATCH 26/40] chore(intel/metadata): add BPM structure's ids Moved these out to the separate file for readabilty. Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/bootpolicy/consts.go | 39 ++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 pkg/intel/metadata/cbnt/bootpolicy/consts.go diff --git a/pkg/intel/metadata/cbnt/bootpolicy/consts.go b/pkg/intel/metadata/cbnt/bootpolicy/consts.go new file mode 100644 index 00000000..98cea6ae --- /dev/null +++ b/pkg/intel/metadata/cbnt/bootpolicy/consts.go @@ -0,0 +1,39 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbntbootpolicy + +const ( + // StructureIDBPMH is the StructureID (in terms of + // the document #575623) of element 'BPMH'. + StructureIDBPMH = "__ACBP__" + + // StructureIDPCD is the StructureID (in terms of + // the document #575623) of element 'PCD'. + StructureIDPCD = "__PCDS__" + + // StructureIDPDRS is the StructureID of the PDRS + // record embedded in PCD data. + StructureIDPDRS = "__PDRS__" + + // StructureIDCNBS is the StructureID of the CNBS + // record embedded in PCD data. + StructureIDCNBS = "__CNBS__" + + // StructureIDPM is the StructureID (in terms of + // the document #575623) of element 'PM'. + StructureIDPM = "__PMDA__" + + // StructureIDSE is the StructureID (in terms of + // the document #575623) of element 'SE'. + StructureIDSE = "__IBBS__" + + // StructureIDSignature is the StructureID (in terms of + // the document #575623) of element 'Signature'. + StructureIDSignature = "__PMSG__" + + // StructureIDTXT is the StructureID (in terms of + // the document #575623) of element 'TXT'. + StructureIDTXT = "__TXTS__" +) From 68af5ddecc4a0e169013aae645b49a00a0439646 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 19:13:10 +0200 Subject: [PATCH 27/40] feat(intel/metadata): adapt BPMH to use Common methods Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/bootpolicy/bpmh.go | 411 +++++++++++++++++++++ 1 file changed, 411 insertions(+) create mode 100644 pkg/intel/metadata/cbnt/bootpolicy/bpmh.go diff --git a/pkg/intel/metadata/cbnt/bootpolicy/bpmh.go b/pkg/intel/metadata/cbnt/bootpolicy/bpmh.go new file mode 100644 index 00000000..454fd971 --- /dev/null +++ b/pkg/intel/metadata/cbnt/bootpolicy/bpmh.go @@ -0,0 +1,411 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbntbootpolicy + +import ( + "encoding/binary" + "fmt" + "io" + "strings" + + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) + +type BPMH interface { + cbnt.Structure +} + +// NewBPMH returns a new instance of BPMH with +// all default values set. +func NewBPMH(bgv cbnt.BootGuardVersion) (BPMH, error) { + switch bgv { + case cbnt.Version10: + s := &BPMHBG{} + copy(s.ID[:], []byte(StructureIDBPMH)) + s.Version = 0x10 + return s, nil + case cbnt.Version20: + s := &BPMHCBnT{} + copy(s.ID[:], []byte(StructureIDBPMH)) + s.Version = 0x23 + s.Rehash() + return s, nil + case cbnt.Version21: + s := &BPMHCBnT{} + copy(s.ID[:], []byte(StructureIDBPMH)) + s.Version = 0x24 + s.Rehash() + return s, nil + default: + return nil, fmt.Errorf("version not supported") + } +} + +// BPMH is the header of boot policy manifest +type BPMHCBnT struct { + cbnt.Common + cbnt.StructInfoCBNT `id:"__ACBP__" version:"0x23" var0:"0x20" var1:"uint16(s.TotalSize())"` + + KeySignatureOffset uint16 `json:"bpmhKeySignatureOffset"` + + BPMRevision uint8 `json:"bpmhRevision"` + + // BPMSVN is BPM security version number + // + // PrettyString: BPM SVN + BPMSVN cbnt.SVN `json:"bpmhSNV"` + + // ACMSVNAuth is authorized ACM security version number + // + // PrettyString: ACM SVN Auth + ACMSVNAuth cbnt.SVN `json:"bpmhACMSVN"` + + Reserved0 [1]byte `require:"0" json:"bpmhReserved0,omitempty"` + + NEMDataStack Size4K `json:"bpmhNEMStackSize"` +} + +func (s *BPMHCBnT) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return s.StructInfoCBNT.TotalSize() }, + Value: func() any { return &s.StructInfoCBNT }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: "Key Signature Offset", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.KeySignatureOffset }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 2, + Name: "BPM Revision", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.BPMRevision }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 3, + Name: "BPM SVN", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.BPMSVN }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 4, + Name: "ACM SVN Auth", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.ACMSVNAuth }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 5, + Name: "Reserved 0", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Reserved0 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 6, + Name: "NEM Data Stack", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.NEMDataStack }, + Type: cbnt.ManifestFieldEndValue, + }, + } +} + +func (s *BPMHCBnT) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("BPMH: %v", err) + } + + return ret, nil +} + +func (s *BPMHCBnT) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("BPMH: %v", err) + } + + return ret, nil +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *BPMHCBnT) Validate() error { + // See tag "require" + for idx := range s.Reserved0 { + if s.Reserved0[idx] != 0 { + return fmt.Errorf("'Reserved0[%d]' is expected to be 0, but it is %v", idx, s.Reserved0[idx]) + } + } + + return nil +} + +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *BPMHCBnT) GetStructInfo() cbnt.StructInfo { + return s.StructInfoCBNT +} + +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *BPMHCBnT) SetStructInfo(newStructInfo cbnt.StructInfo) { + s.StructInfoCBNT = newStructInfo.(cbnt.StructInfoCBNT) +} + +// Has to be here to fullfil Structure interface requirements. +// Reads the whole data. +func (s *BPMHCBnT) ReadFrom(r io.Reader) (int64, error) { + return s.ReadFromHelper(r, true) +} + +// ReadFrom reads the BPMH from 'r' in format defined in the document #575623. +func (s *BPMHCBnT) ReadFromHelper(r io.Reader, info bool) (int64, error) { + l := s.Layout() + + if !info { + l = l[1:] + } + + return s.Common.ReadFrom(r, cbnt.DummyLayout{Fields: l}) +} + +// RehashRecursive calls Rehash (see below) recursively. +func (s *BPMHCBnT) RehashRecursive() { + s.Rehash() +} + +// Rehash sets values which are calculated automatically depending on the rest +// data. It is usually about the total size field of an element. +func (s *BPMHCBnT) Rehash() { + s.Variable0 = 0x20 + s.ElementSize = uint16(s.Common.TotalSize(s)) +} + +// WriteTo writes the BPMH into 'w' in format defined in +// the document #575623. +func (s *BPMHCBnT) WriteTo(w io.Writer) (int64, error) { + s.Rehash() + return s.Common.WriteTo(w, s) +} + +// Size returns the total size of the BPMH. +func (s *BPMHCBnT) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *BPMHCBnT) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return s.Common.PrettyString(depth, withHeader, s, "BPMH", opts...) +} + +type BPMHBG struct { + cbnt.StructInfoBG `id:"__ACBP__" version:"0x10"` + + HdrStructVersion uint8 `json:"HdrStructVersion"` + + PMBPMVersion uint8 `json:"bpmhRevision"` + + // PrettyString: BPM SVN + BPMSVN cbnt.SVN `json:"bpmhSNV"` + // PrettyString: ACM SVN Auth + ACMSVNAuth cbnt.SVN `json:"bpmhACMSVN"` + + Reserved0 [1]byte `require:"0" json:"bpmhReserved0,omitempty"` + + NEMDataStack Size4K `json:"bpmhNEMStackSize"` +} + +func (s *BPMHBG) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return s.StructInfoBG.TotalSize() }, + Value: func() any { return &s.StructInfoBG }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: "Hdr Structure Version", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.HdrStructVersion }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 2, + Name: "PMBPM Version", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.PMBPMVersion }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 3, + Name: "BPM SVN", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.BPMSVN }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 4, + Name: "ACM SVN Auth", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.ACMSVNAuth }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 5, + Name: "Reserved 0", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Reserved0 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 6, + Name: "NEM Data Stack", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.NEMDataStack }, + Type: cbnt.ManifestFieldEndValue, + }, + } +} + +func (s *BPMHBG) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("BPMH: %v", err) + } + + return ret, nil +} + +func (s *BPMHBG) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("BPMH: %v", err) + } + + return ret, nil +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *BPMHBG) Validate() error { + for idx := range s.Reserved0 { + if s.Reserved0[idx] != 0 { + return fmt.Errorf("'Reserved0[%d]' is expected to be 0, but it is %v", idx, s.Reserved0[idx]) + } + } + + return nil +} + +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *BPMHBG) GetStructInfo() cbnt.StructInfo { + return s.StructInfoBG +} + +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *BPMHBG) SetStructInfo(newStructInfo cbnt.StructInfo) { + s.StructInfoBG = newStructInfo.(cbnt.StructInfoBG) +} + +// Has to be here to fullfil Structure interface requirements. +// Reads the whole data. +func (s *BPMHBG) ReadFrom(r io.Reader) (int64, error) { + return s.ReadFromHelper(r, true) +} + +// ReadFrom reads the BPMH from 'r' in format defined in the document #575623. +func (s *BPMHBG) ReadFromHelper(r io.Reader, info bool) (int64, error) { + l := s.Layout() + + if !info { + l = l[1:] + } + + return s.Common.ReadFrom(r, cbnt.DummyLayout{Fields: l}) +} + +// WriteTo writes the BPMH into 'w' in format defined in +// the document #575623. +func (s *BPMHBG) WriteTo(w io.Writer) (int64, error) { + return s.Common.WriteTo(w, s) +} + +// Size returns the total size of the BPMH. +func (s *BPMHBG) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *BPMHBG) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return s.Common.PrettyString(depth, withHeader, s, "BPMH", opts...) +} + +type Size4K uint16 + +// InBytes returns the size in bytes. +func (v Size4K) InBytes() uint32 { + return uint32(v) * 4096 +} + +// NewSize4K returns the given size as multiple of 4K +func NewSize4K(size uint32) Size4K { + return Size4K(size / 4096) +} + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (v Size4K) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + var lines []string + if withHeader { + lines = append(lines, pretty.Header(depth, "Size 4 K", v)) + } + lines = append(lines, pretty.SubValue(depth+1, "In Bytes", "", v.InBytes(), opts...)...) + return strings.Join(lines, "\n") +} + +// TotalSize returns the total size measured through binary.Size. +func (v Size4K) TotalSize() uint64 { + return uint64(binary.Size(v)) +} + +// WriteTo writes the Size4K into 'w' in binary format. +func (v Size4K) WriteTo(w io.Writer) (int64, error) { + return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) +} + +// ReadFrom reads the Size4K from 'r' in binary format. +func (v Size4K) ReadFrom(r io.Reader) (int64, error) { + return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) +} From 7fa74c0f124e27209a6b012b4678a690a66cade3 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 19:14:42 +0200 Subject: [PATCH 28/40] feat(intel/metadata): adapt PM to use Common methods Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/bootpolicy/pm.go | 292 +++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 pkg/intel/metadata/cbnt/bootpolicy/pm.go diff --git a/pkg/intel/metadata/cbnt/bootpolicy/pm.go b/pkg/intel/metadata/cbnt/bootpolicy/pm.go new file mode 100644 index 00000000..beea619a --- /dev/null +++ b/pkg/intel/metadata/cbnt/bootpolicy/pm.go @@ -0,0 +1,292 @@ +// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbntbootpolicy + +import ( + "encoding/binary" + "fmt" + "io" + + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) + +type PM interface { + cbnt.Structure +} + +// NewPM returns a new instance of PM with +// all default values set. +func NewPM(bgv cbnt.BootGuardVersion) (PM, error) { + switch bgv { + case cbnt.Version10: + s := &PMBG{} + copy(s.ID[:], []byte(StructureIDPM)) + s.Version = 0x10 + return s, nil + case cbnt.Version20, cbnt.Version21: + s := &PMCBnT{} + copy(s.ID[:], []byte(StructureIDPM)) + s.Version = 0x20 + s.Rehash() + return s, nil + default: + return nil, fmt.Errorf("version not supported") + } +} + +type PMCBnT struct { + cbnt.Common + cbnt.StructInfoCBNT `id:"__PMDA__" version:"0x20" var0:"0" var1:"uint16(s.TotalSize())"` + Reserved0 [2]byte `require:"0" json:"pcReserved0,omitempty"` + DataSize [2]byte `json:"pcDataSize"` + Data []byte `json:"pcData"` +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *PMCBnT) Validate() error { + // See tag "require" + for idx := range s.Reserved0 { + if s.Reserved0[idx] != 0 { + return fmt.Errorf("'Reserved0[%d]' is expected to be 0, but it is %v", idx, s.Reserved0[idx]) + } + } + + return nil +} + +func (s *PMCBnT) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return s.StructInfoCBNT.TotalSize() }, + Value: func() any { return &s.StructInfoCBNT }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: "Reserved 0", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.Reserved0 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 2, + Name: "Data Size", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.DataSize }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 3, + Name: "Data", + Size: func() uint64 { + size := uint64(binary.Size(uint16(0))) + size += uint64(binary.Size(s.DataSize)) + return size + }, + Value: func() any { return &s.Data }, + Type: cbnt.ManifestFieldArrayDynamicWithPrefix, + }, + } +} + +func (s *PMCBnT) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("PM: %v", err) + } + + return ret, nil +} + +func (s *PMCBnT) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("PM: %v", err) + } + + return ret, nil +} + +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *PMCBnT) GetStructInfo() cbnt.StructInfo { + return s.StructInfoCBNT +} + +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *PMCBnT) SetStructInfo(newStructInfo cbnt.StructInfoCBNT) { + s.StructInfoCBNT = newStructInfo +} + +// Has to be here to fullfil Structure interface requirements. +// Reads the whole data. +func (s *PMCBnT) ReadFrom(r io.Reader) (int64, error) { + return s.ReadFromHelper(r, true) +} + +// ReadFrom reads the PM from 'r' in format defined in the document #575623. +func (s *PMCBnT) ReadFromHelper(r io.Reader, info bool) (int64, error) { + l := s.Layout() + + if !info { + l = l[1:] + } + + return s.Common.ReadFrom(r, cbnt.DummyLayout{Fields: l}) +} + +// RehashRecursive calls Rehash (see below) recursively. +func (s *PMCBnT) RehashRecursive() { + s.Rehash() +} + +// Rehash sets values which are calculated automatically depending on the rest +// data. It is usually about the total size field of an element. +func (s *PMCBnT) Rehash() { + s.Variable0 = 0 + s.ElementSize = uint16(s.Common.TotalSize(s)) +} + +// WriteTo writes the PM into 'w' in format defined in +// the document #575623. +func (s *PMCBnT) WriteTo(w io.Writer) (int64, error) { + s.Rehash() + return s.Common.WriteTo(w, s) +} + +// Size returns the total size of the PM. +func (s *PMCBnT) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *PMCBnT) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return s.Common.PrettyString(depth, withHeader, s, "PM", opts...) +} + +type PMBG struct { + cbnt.StructInfoBG `id:"__PMDA__" version:"0x10"` + DataSize uint16 `json:"pcDataSize"` + Data []byte `json:"pcData"` +} + +func (s *PMBG) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return s.StructInfoBG.TotalSize() }, + Value: func() any { return &s.StructInfoBG }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: "Data Size", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.DataSize }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 2, + Name: "Data", + Size: func() uint64 { + size := uint64(binary.Size(uint16(0))) + size += uint64(s.DataSize) + return size + }, + Value: func() any { return &s.Data }, + Type: cbnt.ManifestFieldArrayDynamicWithPrefix, + }, + } +} + +func (s *PMBG) Validate() error { + // dummy + return nil +} + +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *PMBG) GetStructInfo() cbnt.StructInfo { + return s.StructInfoBG +} + +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *PMBG) SetStructInfo(newStructInfo cbnt.StructInfo) { + s.StructInfoBG = newStructInfo.(cbnt.StructInfoBG) +} + +// Has to be here to fullfil Structure interface requirements. +// Reads the whole data. +func (s *PMBG) ReadFrom(r io.Reader) (int64, error) { + return s.ReadFromHelper(r, true) +} + +// ReadFrom reads the PM from 'r' in format defined in the document #575623. +func (s *PMBG) ReadFromHelper(r io.Reader, info bool) (int64, error) { + l := s.Layout() + + if !info { + l = l[1:] + } + + return s.Common.ReadFrom(r, cbnt.DummyLayout{Fields: l}) +} + +// WriteTo writes the PM into 'w' in format defined in +// the document #575623. +func (s *PMBG) WriteTo(w io.Writer) (int64, error) { + return s.Common.WriteTo(w, s) +} + +func (s *PMBG) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("PM: %v", err) + } + + return ret, nil +} + +func (s *PMBG) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("PM: %v", err) + } + + return ret, nil +} + +// Size returns the total size of the PM. +func (s *PMBG) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *PMBG) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return s.Common.PrettyString(depth, withHeader, s, "PM", opts...) +} From 45730f4dc3fc658a33ea57e62d757354bae933eb Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 19:17:52 +0200 Subject: [PATCH 29/40] chore(intel/metadata): move txt_control_flags to merged bootpolicy pkg No logic changes. Signed-off-by: Michal Gorlas --- .../cbnt/bootpolicy/txt_control_flags.go | 240 ++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 pkg/intel/metadata/cbnt/bootpolicy/txt_control_flags.go diff --git a/pkg/intel/metadata/cbnt/bootpolicy/txt_control_flags.go b/pkg/intel/metadata/cbnt/bootpolicy/txt_control_flags.go new file mode 100644 index 00000000..17054eb2 --- /dev/null +++ b/pkg/intel/metadata/cbnt/bootpolicy/txt_control_flags.go @@ -0,0 +1,240 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbntbootpolicy + +import ( + "encoding/binary" + "fmt" + "io" + "strings" + + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) + +const ( + // + CachingTypeWriteProtect = CachingType(iota) + CachingTypeWriteBack + CachingTypeReserved0 + CachingTypeReserved1 +) + +const ( + ExecutionProfileA = ExecutionProfile(iota) + ExecutionProfileB + ExecutionProfileC +) + +const ( + MemoryScrubbingPolicyDefault = MemoryScrubbingPolicy(iota) + MemoryScrubbingPolicyBIOS + MemoryScrubbingPolicySACM +) + +const ( + BackupActionPolicyDefault = BackupActionPolicy(iota) + BackupActionPolicyForceMemoryPowerDown + BackupActionPolicyForceBtGUnbreakableShutdown +) + +const ( + ResetAUXControlResetAUXIndex = ResetAUXControl(iota) + ResetAUXControlDeleteAUXIndex +) + +type BackupActionPolicy uint8 + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (v BackupActionPolicy) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return v.String() +} + +// TotalSize returns the total size measured through binary.Size. +func (v BackupActionPolicy) TotalSize() uint64 { + return uint64(binary.Size(v)) +} + +// WriteTo writes the BackupActionPolicy into 'w' in binary format. +func (v BackupActionPolicy) WriteTo(w io.Writer) (int64, error) { + return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) +} + +// ReadFrom reads the BackupActionPolicy from 'r' in binary format. +func (v BackupActionPolicy) ReadFrom(r io.Reader) (int64, error) { + return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) +} + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (v ExecutionProfile) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return v.String() +} + +type ExecutionProfile uint8 + +// TotalSize returns the total size measured through binary.Size. +func (v ExecutionProfile) TotalSize() uint64 { + return uint64(binary.Size(v)) +} + +// WriteTo writes the ExecutionProfile into 'w' in binary format. +func (v ExecutionProfile) WriteTo(w io.Writer) (int64, error) { + return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) +} + +// ReadFrom reads the ExecutionProfile from 'r' in binary format. +func (v ExecutionProfile) ReadFrom(r io.Reader) (int64, error) { + return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) +} + +type MemoryScrubbingPolicy uint8 + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (v MemoryScrubbingPolicy) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return v.String() +} + +// TotalSize returns the total size measured through binary.Size. +func (v MemoryScrubbingPolicy) TotalSize() uint64 { + return uint64(binary.Size(v)) +} + +// WriteTo writes the MemoryScrubbingPolicy into 'w' in binary format. +func (v MemoryScrubbingPolicy) WriteTo(w io.Writer) (int64, error) { + return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) +} + +// ReadFrom reads the MemoryScrubbingPolicy from 'r' in binary format. +func (v MemoryScrubbingPolicy) ReadFrom(r io.Reader) (int64, error) { + return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) +} + +type ResetAUXControl uint8 + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (v ResetAUXControl) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return v.String() +} + +// TotalSize returns the total size measured through binary.Size. +func (v ResetAUXControl) TotalSize() uint64 { + return uint64(binary.Size(v)) +} + +// WriteTo writes the ResetAUXControl into 'w' in binary format. +func (v ResetAUXControl) WriteTo(w io.Writer) (int64, error) { + return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) +} + +// ReadFrom reads the ResetAUXControl from 'r' in binary format. +func (v ResetAUXControl) ReadFrom(r io.Reader) (int64, error) { + return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) +} + +type TXTControlFlags uint32 + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (flags TXTControlFlags) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + var lines []string + if withHeader { + lines = append(lines, pretty.Header(depth, "TXT Control Flags", flags)) + } + lines = append(lines, pretty.SubValue(depth+1, "Execution Profile", "", flags.ExecutionProfile(), opts...)...) + lines = append(lines, pretty.SubValue(depth+1, "Memory Scrubbing Policy", "", flags.MemoryScrubbingPolicy(), opts...)...) + lines = append(lines, pretty.SubValue(depth+1, "Backup Action Policy", "", flags.BackupActionPolicy(), opts...)...) + if flags.IsSACMRequestedToExtendStaticPCRs() { + lines = append(lines, pretty.SubValue(depth+1, "Is SACM Requested To Extend Static PC Rs", "Default setting. S-ACM is requested to extend static PCRs", true, opts...)...) + } else { + lines = append(lines, pretty.SubValue(depth+1, "Is SACM Requested To Extend Static PC Rs", "S-ACM is not requested to extend static PCRs", false, opts...)...) + } + lines = append(lines, pretty.SubValue(depth+1, "Reset AUX Control", "", flags.ResetAUXControl(), opts...)...) + return strings.Join(lines, "\n") +} + +// TotalSize returns the total size measured through binary.Size. +func (flags TXTControlFlags) TotalSize() uint64 { + return uint64(binary.Size(flags)) +} + +// WriteTo writes the TXTControlFlags into 'w' in binary format. +func (flags TXTControlFlags) WriteTo(w io.Writer) (int64, error) { + return int64(flags.TotalSize()), binary.Write(w, binary.LittleEndian, flags) +} + +// ReadFrom reads the TXTControlFlags from 'r' in binary format. +func (flags TXTControlFlags) ReadFrom(r io.Reader) (int64, error) { + return int64(flags.TotalSize()), binary.Read(r, binary.LittleEndian, flags) +} + +func (flags TXTControlFlags) ExecutionProfile() ExecutionProfile { + return ExecutionProfile(flags & 0x1f) +} + +// String just implements fmt.Stringer. +func (v ExecutionProfile) String() string { + switch v { + case ExecutionProfileA: + return `A (use default selection based on differentation between clients, UP, and MP servers)` + case ExecutionProfileB: + return `B (use "Server model": rely on BIOS to configure topoligy; do not use ACHECK)` + case ExecutionProfileC: + return `C (use "Client model": do not measure BIOS into D-PCRs; use ACHECK-based alias check)` + } + return fmt.Sprintf("unexpected_execution_profile_value_0x%02X", uint8(v)) +} + +func (flags TXTControlFlags) MemoryScrubbingPolicy() MemoryScrubbingPolicy { + return MemoryScrubbingPolicy((flags >> 5) & 0x3) +} + +// String implements fmt.Stringer. +func (v MemoryScrubbingPolicy) String() string { + switch v { + case MemoryScrubbingPolicyDefault: + return "BIOS if verified or backup action othersize" + case MemoryScrubbingPolicyBIOS: + return "BIOS" + case MemoryScrubbingPolicySACM: + return "S-ACM" + } + return fmt.Sprintf("unexpected_value_0x%02X", uint8(v)) +} + +func (flags TXTControlFlags) BackupActionPolicy() BackupActionPolicy { + return BackupActionPolicy((flags >> 7) & 0x3) +} + +// String implements fmt.Stringer. +func (v BackupActionPolicy) String() string { + switch v { + case BackupActionPolicyDefault: + return "memory power down if profile D or BtG unbreakable shutdown otherwise" + case BackupActionPolicyForceMemoryPowerDown: + return "memory power down" + case BackupActionPolicyForceBtGUnbreakableShutdown: + return "BtG unbreakable shutdown" + } + return fmt.Sprintf("unexpected_value_0x%02X", uint8(v)) +} + +// PrettyString-true: Default setting. S-ACM is requested to extend static PCRs +// PrettyString-false: S-ACM is not requested to extend static PCRs +func (flags TXTControlFlags) IsSACMRequestedToExtendStaticPCRs() bool { + return (flags>>9)&0x01 == 0 +} + +func (flags TXTControlFlags) ResetAUXControl() ResetAUXControl { + return ResetAUXControl((flags >> 31) & 0x01) +} + +// String implements fmt.Stringer. +func (v ResetAUXControl) String() string { + switch v { + case ResetAUXControlResetAUXIndex: + return "AUX reset leaf will reset AUX index" + case ResetAUXControlDeleteAUXIndex: + return "AUX reset leaf will delete AUX index" + } + return fmt.Sprintf("unexpected_value_0x%02X", uint8(v)) +} From 144e8ce2f969d36f976be32845a0d869dff63d0d Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 19:20:31 +0200 Subject: [PATCH 30/40] feat(intel/metadata): adapt BPM.Signature to use Common methods Signed-off-by: Michal Gorlas --- .../metadata/cbnt/bootpolicy/signature.go | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 pkg/intel/metadata/cbnt/bootpolicy/signature.go diff --git a/pkg/intel/metadata/cbnt/bootpolicy/signature.go b/pkg/intel/metadata/cbnt/bootpolicy/signature.go new file mode 100644 index 00000000..65997a47 --- /dev/null +++ b/pkg/intel/metadata/cbnt/bootpolicy/signature.go @@ -0,0 +1,144 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbntbootpolicy + +import ( + "fmt" + "io" + + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) + +type Signature struct { + cbnt.Common + cbnt.StructInfo `id:"__PMSG__" version:"0x20"` + cbnt.KeySignature `json:"sigKeySignature"` +} + +// NewSignature returns a new instance of Signature with +// all default values set. +func NewSignature(bgv cbnt.BootGuardVersion) (*Signature, error) { + switch bgv { + case cbnt.Version10: + s := &Signature{StructInfo: cbnt.NewStructInfo(bgv)} + copy(s.StructInfo.(*cbnt.StructInfoBG).ID[:], []byte(StructureIDSignature)) + s.StructInfo.(*cbnt.StructInfoBG).Version = 0x10 + // Recursively initializing a child structure: + s.KeySignature = *cbnt.NewKeySignature() + return s, nil + case cbnt.Version20, cbnt.Version21: + s := &Signature{StructInfo: cbnt.NewStructInfo(bgv)} + copy(s.StructInfo.(*cbnt.StructInfoCBNT).ID[:], []byte(StructureIDSignature)) + s.StructInfo.(*cbnt.StructInfoCBNT).Version = 0x20 + s.StructInfo.(*cbnt.StructInfoCBNT).ElementSize = 0 + s.StructInfo.(*cbnt.StructInfoCBNT).Variable0 = 0 + // Recursively initializing a child structure: + s.KeySignature = *cbnt.NewKeySignature() + return s, nil + default: + return nil, fmt.Errorf("version not supported") + } +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *Signature) Validate() error { + // Recursively validating a child structure: + if err := s.KeySignature.Validate(); err != nil { + return fmt.Errorf("error on field 'KeySignature': %w", err) + } + + return nil +} + +func (s *Signature) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return s.StructInfo.TotalSize() }, + Value: func() any { return s.StructInfo }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: "Key Signature", + Size: func() uint64 { return s.KeySignature.TotalSize() }, + Value: func() any { return &s.KeySignature }, + Type: cbnt.ManifestFieldSubStruct, + }, + } +} + +func (s *Signature) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("Signature: %v", err) + } + + return ret, nil +} + +func (s *Signature) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("Signature: %v", err) + } + + return ret, nil +} + +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *Signature) GetStructInfo() cbnt.StructInfo { + return s.StructInfo +} + +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *Signature) SetStructInfo(newStructInfo cbnt.StructInfo) { + s.StructInfo = newStructInfo +} + +// Dummy helper to satisfy cbnt.Structure Interface +func (s *Signature) ReadFrom(r io.Reader, info bool) (int64, error) { + return s.ReadFromHelper(r, info) +} + +// ReadFrom reads the Signature from 'r' in format defined in the document #575623. +func (s *Signature) ReadFromHelper(r io.Reader, info bool) (int64, error) { + l := s.Layout() + + if !info { + l = l[1:] + } + + return s.Common.ReadFrom(r, cbnt.DummyLayout{Fields: l}) +} + +// WriteTo writes the Signature into 'w' in format defined in +// the document #575623. +func (s *Signature) WriteTo(w io.Writer) (int64, error) { + return s.Common.WriteTo(w, s) +} + +// Size returns the total size of the Signature. +func (s *Signature) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *Signature) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return s.Common.PrettyString(depth, withHeader, s, "Signature", opts...) +} From cc71938e8798c7af5090aab9979a3ac0cf4e523d Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 19:21:38 +0200 Subject: [PATCH 31/40] feat(intel/metadata): adapt TXT to use Common methods Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/bootpolicy/txt.go | 330 ++++++++++++++++++++++ 1 file changed, 330 insertions(+) create mode 100644 pkg/intel/metadata/cbnt/bootpolicy/txt.go diff --git a/pkg/intel/metadata/cbnt/bootpolicy/txt.go b/pkg/intel/metadata/cbnt/bootpolicy/txt.go new file mode 100644 index 00000000..a8786158 --- /dev/null +++ b/pkg/intel/metadata/cbnt/bootpolicy/txt.go @@ -0,0 +1,330 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbntbootpolicy + +import ( + "encoding/binary" + "fmt" + "io" + "time" + + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) + +// TXT is the TXT element +type TXT struct { + cbnt.Common + cbnt.StructInfoCBNT `id:"__TXTS__" version:"0x21" var0:"0" var1:"uint16(s.TotalSize())"` + Reserved0 [1]byte `require:"0" json:"txtReserved0,omitempty"` + SetNumber [1]byte `require:"0" json:"txtSetNumer,omitempty"` + SInitMinSVNAuth uint8 `default:"0" json:"txtSVN"` + Reserved1 [1]byte `require:"0" json:"txtReserved1,omitempty"` + ControlFlags TXTControlFlags `json:"txtFlags"` + PwrDownInterval Duration16In5Sec `json:"txtPwrDownInterval"` + // PrettyString: PTT CMOS Offset 0 + PTTCMOSOffset0 uint8 `default:"126" json:"txtPTTCMOSOffset0"` + // PrettyString: PTT CMOS Offset 1 + PTTCMOSOffset1 uint8 `default:"127" json:"txtPTTCMOSOffset1"` + ACPIBaseOffset uint16 `default:"0x400" json:"txtACPIBaseOffset,omitempty"` + Reserved2 [2]byte `json:"txtReserved2,omitempty"` + // PrettyString: ACPI MMIO Offset + PwrMBaseOffset uint32 `default:"0xFE000000" json:"txtPwrMBaseOffset,omitempty"` + DigestList cbnt.HashList `json:"txtDigestList"` + Reserved3 [3]byte `require:"0" json:"txtReserved3,omitempty"` + + SegmentCount uint8 `require:"0" json:"txtSegmentCount,omitempty"` +} + +// NewTXT returns a new instance of TXT with +// all default values set. +func NewTXT() *TXT { + s := &TXT{} + copy(s.ID[:], []byte(StructureIDTXT)) + s.Version = 0x21 + // Set through tag "default": + s.SInitMinSVNAuth = 0 + // Set through tag "default": + s.PTTCMOSOffset0 = 126 + // Set through tag "default": + s.PTTCMOSOffset1 = 127 + // Set through tag "default": + s.ACPIBaseOffset = 0x400 + // Set through tag "default": + s.PwrMBaseOffset = 0xFE000000 + // Recursively initializing a child structure: + s.DigestList = *cbnt.NewHashList() + // Set through tag "required": + s.SegmentCount = 0 + s.Rehash() + return s +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *TXT) Validate() error { + // See tag "require" + for idx := range s.Reserved0 { + if s.Reserved0[idx] != 0 { + return fmt.Errorf("'Reserved0[%d]' is expected to be 0, but it is %v", idx, s.Reserved0[idx]) + } + } + // See tag "require" + for idx := range s.SetNumber { + if s.SetNumber[idx] != 0 { + return fmt.Errorf("'SetNumber[%d]' is expected to be 0, but it is %v", idx, s.SetNumber[idx]) + } + } + // See tag "require" + for idx := range s.Reserved1 { + if s.Reserved1[idx] != 0 { + return fmt.Errorf("'Reserved1[%d]' is expected to be 0, but it is %v", idx, s.Reserved1[idx]) + } + } + // Recursively validating a child structure: + if err := s.DigestList.Validate(); err != nil { + return fmt.Errorf("error on field 'DigestList': %w", err) + } + // See tag "require" + for idx := range s.Reserved3 { + if s.Reserved3[idx] != 0 { + return fmt.Errorf("'Reserved3[%d]' is expected to be 0, but it is %v", idx, s.Reserved3[idx]) + } + } + // See tag "require" + if s.SegmentCount != 0 { + return fmt.Errorf("field 'SegmentCount' expects value '0', but has %v", s.SegmentCount) + } + + return nil +} + +func (s *TXT) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return s.StructInfoCBNT.TotalSize() }, + Value: func() any { return &s.StructInfoCBNT }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: "Reserved 0", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Reserved0 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 2, + Name: "Set Number", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.SetNumber }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 3, + Name: "S Init Min SVN Auth", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.SInitMinSVNAuth }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 4, + Name: "Reserved 1", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Reserved1 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 5, + Name: "Control Flags", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.ControlFlags }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 6, + Name: "Pwr Down Interval", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.PwrDownInterval }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 7, + Name: "PTT CMOS Offset 0", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.PTTCMOSOffset0 }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 8, + Name: "PTT CMOS Offset 1", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.PTTCMOSOffset1 }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 9, + Name: "ACPI Base Offset", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.ACPIBaseOffset }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 10, + Name: "Reserved 2", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.Reserved2 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 11, + Name: "ACPI MMIO Offset", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.PwrMBaseOffset }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 12, + Name: "Digest List", + Size: func() uint64 { return s.DigestList.TotalSize() }, + Value: func() any { return &s.DigestList }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 13, + Name: "Reserved 3", + Size: func() uint64 { return 3 }, + Value: func() any { return &s.Reserved3 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 14, + Name: "Segment Count", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.SegmentCount }, + Type: cbnt.ManifestFieldEndValue, + }, + } +} + +func (s *TXT) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("TXT: %v", err) + } + + return ret, nil +} + +func (s *TXT) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("TXT: %v", err) + } + + return ret, nil +} + +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *TXT) GetStructInfo() cbnt.StructInfoCBNT { + return s.StructInfoCBNT +} + +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *TXT) SetStructInfo(newStructInfo cbnt.StructInfoCBNT) { + s.StructInfoCBNT = newStructInfo +} + +// Dummy helper to comply with requirements of cbnt.Structure interface +func (s *TXT) ReadFrom(r io.Reader) (int64, error) { + return s.ReadFromHelper(r, true) +} + +// ReadFrom reads the TXT from 'r' in format defined in the document #575623. +func (s *TXT) ReadFromHelper(r io.Reader, info bool) (int64, error) { + l := s.Layout() + + if !info { + l = l[1:] + } + + return s.Common.ReadFrom(r, cbnt.DummyLayout{Fields: l}) +} + +// RehashRecursive calls Rehash (see below) recursively. +func (s *TXT) RehashRecursive() { + s.DigestList.Rehash() + s.Rehash() +} + +// Rehash sets values which are calculated automatically depending on the rest +// data. It is usually about the total size field of an element. +func (s *TXT) Rehash() { + s.Variable0 = 0 + s.ElementSize = uint16(s.TotalSize()) +} + +// WriteTo writes the TXT into 'w' in format defined in +// the document #575623. +func (s *TXT) WriteTo(w io.Writer) (int64, error) { + s.Rehash() + return s.Common.WriteTo(w, s) +} + +// Size returns the total size of the TXT. +func (s *TXT) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *TXT) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return s.Common.PrettyString(depth, withHeader, s, "TXT", opts...) +} + +type Duration16In5Sec uint16 + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (d Duration16In5Sec) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return d.String() +} + +// TotalSize returns the total size measured through binary.Size. +func (d Duration16In5Sec) TotalSize() uint64 { + return uint64(binary.Size(d)) +} + +// WriteTo writes the Duration16In5Sec into 'w' in binary format. +func (d Duration16In5Sec) WriteTo(w io.Writer) (int64, error) { + return int64(d.TotalSize()), binary.Write(w, binary.LittleEndian, d) +} + +// ReadFrom reads the Duration16In5Sec from 'r' in binary format. +func (d Duration16In5Sec) ReadFrom(r io.Reader) (int64, error) { + return int64(d.TotalSize()), binary.Read(r, binary.LittleEndian, d) +} + +// Duration calculates a given time in multiple of 5 seconds. +func (d Duration16In5Sec) Duration() time.Duration { + return time.Second * 5 * time.Duration(d) +} + +func (d Duration16In5Sec) String() string { + if d == 0 { + return "0 (infinite)" + } + return fmt.Sprintf("%d (%s)", d, d.Duration().String()) +} From 3794d5602b6bff0cadbe2a5407ddb0ec0e6ad0db Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 19:45:25 +0200 Subject: [PATCH 32/40] feat(intel/metadata): adapt SE to use Common methods Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/bootpolicy/se.go | 977 +++++++++++++++++++++++ 1 file changed, 977 insertions(+) create mode 100644 pkg/intel/metadata/cbnt/bootpolicy/se.go diff --git a/pkg/intel/metadata/cbnt/bootpolicy/se.go b/pkg/intel/metadata/cbnt/bootpolicy/se.go new file mode 100644 index 00000000..2863f57b --- /dev/null +++ b/pkg/intel/metadata/cbnt/bootpolicy/se.go @@ -0,0 +1,977 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbntbootpolicy + +import ( + "encoding/binary" + "fmt" + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" + "io" + "math" + "strings" + "time" +) + +// IBBSegment defines a single IBB segment +type IBBSegment struct { + cbnt.Common + Reserved [2]byte `require:"0" json:"ibbSegReserved"` + Flags uint16 `json:"ibbSegFlags"` + Base uint32 `json:"ibbSegBase"` + Size uint32 `json:"ibbSegSize"` +} + +// NewIBBSegment returns a new instance of IBBSegment with +// all default values set. +func NewIBBSegment() *IBBSegment { + s := &IBBSegment{} + return s +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *IBBSegment) Validate() error { + // See tag "require" + for idx := range s.Reserved { + if s.Reserved[idx] != 0 { + return fmt.Errorf("'Reserved[%d]' is expected to be 0, but it is %v", idx, s.Reserved[idx]) + } + } + + return nil +} + +func (s *IBBSegment) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Reserved", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.Reserved }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 1, + Name: "Flags", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.Flags }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 2, + Name: "Base", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.Base }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 3, + Name: "Size", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.Size }, + Type: cbnt.ManifestFieldEndValue, + }, + } +} + +func (s *IBBSegment) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("IBBSegment: %v", err) + } + + return ret, nil +} + +func (s *IBBSegment) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("IBBSegment: %v", err) + } + + return ret, nil +} + +// ReadFrom reads the IBBSegment from 'r' in format defined in the document #575623. +func (s *IBBSegment) ReadFrom(r io.Reader) (int64, error) { + return s.Common.ReadFrom(r, s) +} + +// WriteTo writes the IBBSegment into 'w' in format defined in +// the document #575623. +func (s *IBBSegment) WriteTo(w io.Writer) (int64, error) { + return s.Common.WriteTo(w, s) +} + +// Size returns the total size of the IBBSegment. +func (s *IBBSegment) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *IBBSegment) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return s.Common.PrettyString(depth, withHeader, s, "IBB Segment", opts...) +} + +type SE interface { + cbnt.Structure +} + +// SE is an IBB segments element +// +// PrettyString: IBB Segments Element +type SECBnT struct { + cbnt.Common + cbnt.StructInfoCBNT `id:"__IBBS__" version:"0x20" var0:"0" var1:"uint16(s.TotalSize())"` + Reserved0 [1]byte `require:"0" json:"seReserved0,omitempty"` + SetNumber uint8 `require:"0" json:"seSetNumber,omitempty"` + Reserved1 [1]byte `require:"0" json:"seReserved1,omitempty"` + PBETValue PBETValue `json:"sePBETValue"` + Flags SEFlags `json:"seFlags"` + + // IBBMCHBAR + // PrettyString: IBB MCHBAR + IBBMCHBAR uint64 `json:"seIBBMCHBAR"` + + // VTdBAR + // PrettyString: VT-d BAR + VTdBAR uint64 `json:"seVTdBAR"` + + // DMAProtBase0 + // PrettyString: DMA Protection 0 Base Address + DMAProtBase0 uint32 `json:"seDMAProtBase0"` + + // DMAProtLimit0 + // PrettyString: DMA Protection 0 Limit Address + DMAProtLimit0 uint32 `json:"seDMAProtLimit0"` + + // DMAProtBase1 + // PrettyString: DMA Protection 1 Base Address + DMAProtBase1 uint64 `json:"seDMAProtBase1"` + + // DMAProtLimit1 + // PrettyString: DMA Protection 2 Limit Address + DMAProtLimit1 uint64 `json:"seDMAProtLimit1"` + + PostIBBHash cbnt.HashStructure `json:"sePostIBBHash"` + + IBBEntryPoint uint32 `json:"seIBBEntry"` + + DigestList cbnt.HashList `json:"seDigestList"` + + OBBHash cbnt.HashStructure `json:"seOBBHash"` + + Reserved2 [3]byte `require:"0" json:"seReserved2,omitempty"` + + IBBSegments []IBBSegment `countType:"uint8" json:"seIBBSegments,omitempty"` +} + +// NewSE returns a new instance of SE with +// all default values set. +func NewSE(bgv cbnt.BootGuardVersion) (SE, error) { + switch bgv { + case cbnt.Version10: + s := &SEBG{} + // See 'default' in HashStructure for BG in legacy package + hashAlg := 0x0b + copy(s.ID[:], []byte(StructureIDSE)) + s.Version = 0x10 + // Recursively initializing a child structure: + s.PostIBBHash = *cbnt.NewHashStructureFill(cbnt.Algorithm(hashAlg)) + // Recursively initializing a child structure: + s.Digest = *cbnt.NewHashStructure(cbnt.Algorithm(hashAlg)) + return s, nil + case cbnt.Version20, cbnt.Version21: + s := &SECBnT{} + // See 'default' in HashStructure for CBNT + hashAlg := 0x10 + copy(s.ID[:], []byte(StructureIDSE)) + // Yes, conditional statement inside of switch case + // seems hacky. But it saves us from revriting the whole + // block an changing just one value (version) + if bgv == cbnt.Version20 { + s.Version = 0x20 + } else { + s.Version = 0x21 + } + // Set through tag "required": + s.SetNumber = 0 + // Recursively initializing a child structure: + s.PostIBBHash = *cbnt.NewHashStructure(cbnt.Algorithm(hashAlg)) + // Recursively initializing a child structure: + s.DigestList = *cbnt.NewHashList() + // Recursively initializing a child structure: + s.OBBHash = *cbnt.NewHashStructure(cbnt.Algorithm(hashAlg)) + s.Rehash() + return s, nil + + default: + return nil, fmt.Errorf("version not supported") + } +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *SECBnT) Validate() error { + // See tag "require" + for idx := range s.Reserved0 { + if s.Reserved0[idx] != 0 { + return fmt.Errorf("'Reserved0[%d]' is expected to be 0, but it is %v", idx, s.Reserved0[idx]) + } + } + // See tag "require" + if s.SetNumber != 0 { + return fmt.Errorf("field 'SetNumber' expects value '0', but has %v", s.SetNumber) + } + // See tag "require" + for idx := range s.Reserved1 { + if s.Reserved1[idx] != 0 { + return fmt.Errorf("'Reserved1[%d]' is expected to be 0, but it is %v", idx, s.Reserved1[idx]) + } + } + // Recursively validating a child structure: + if err := s.DigestList.Validate(); err != nil { + return fmt.Errorf("error on field 'DigestList': %w", err) + } + // See tag "require" + for idx := range s.Reserved2 { + if s.Reserved2[idx] != 0 { + return fmt.Errorf("'Reserved2[%d]' is expected to be 0, but it is %v", idx, s.Reserved2[idx]) + } + } + + return nil +} + +func (s *SECBnT) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return s.StructInfoCBNT.TotalSize() }, + Value: func() any { return &s.StructInfoCBNT }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: "Reserved 0", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Reserved0 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 2, + Name: "Set Number", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.SetNumber }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 3, + Name: "Reserved 1", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Reserved1 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 4, + Name: "PBET Value", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.PBETValue }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 5, + Name: "Flags", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.Flags }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 6, + Name: "IBB MCHBAR", + Size: func() uint64 { return 8 }, + Value: func() any { return &s.IBBMCHBAR }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 7, + Name: "VT-d BAR", + Size: func() uint64 { return 8 }, + Value: func() any { return &s.VTdBAR }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 8, + Name: "DMA Protection 0 Base Address", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.DMAProtBase0 }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 9, + Name: "DMA Protection 0 Limit Address", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.DMAProtLimit0 }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 10, + Name: "DMA Protection 1 Base Address", + Size: func() uint64 { return 8 }, + Value: func() any { return &s.DMAProtBase1 }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 11, + Name: "DMA Protection 2 Limit Address", + Size: func() uint64 { return 8 }, + Value: func() any { return &s.DMAProtLimit1 }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 12, + Name: "Post IBB Hash", + Size: func() uint64 { return s.PostIBBHash.TotalSize() }, + Value: func() any { return &s.PostIBBHash }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 13, + Name: "IBB Entry Point", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.IBBEntryPoint }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 14, + Name: "Digest List", + Size: func() uint64 { return s.DigestList.TotalSize() }, + Value: func() any { return &s.DigestList }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 15, + Name: "OBB Hash", + Size: func() uint64 { return s.OBBHash.TotalSize() }, + Value: func() any { return &s.OBBHash }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 16, + Name: "Reserved 2", + Size: func() uint64 { return 3 }, + Value: func() any { return &s.Reserved2 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 17, + Name: fmt.Sprintf("IBBSegments: Array of \"IBB Segments Element\" of length %d", len(s.IBBSegments)), + Size: func() uint64 { + size := uint64(binary.Size(uint8(0))) + for idx := range s.IBBSegments { + size += s.IBBSegments[idx].TotalSize() + } + return size + }, + Value: func() any { return &s.IBBSegments }, + Type: cbnt.ManifestFieldList, + ReadList: func(r io.Reader) (int64, error) { + var count uint8 + if err := binary.Read(r, binary.LittleEndian, &count); err != nil { + return 0, fmt.Errorf("unable to read the count for field 'IBBSegments': %w", err) + } + totalN := int64(binary.Size(count)) + s.IBBSegments = make([]IBBSegment, count) + for idx := range s.IBBSegments { + n, err := s.IBBSegments[idx].ReadFrom(r) + if err != nil { + return totalN, fmt.Errorf("unable to read field 'IBBSegments[%d]': %w", idx, err) + } + totalN += int64(n) + } + return totalN, nil + }, + WriteList: func(w io.Writer) (int64, error) { + count := uint8(len(s.IBBSegments)) + if err := binary.Write(w, binary.LittleEndian, &count); err != nil { + return 0, fmt.Errorf("unable to write the count for field 'IBBSegments': %w", err) + } + totalN := int64(binary.Size(count)) + for idx := range s.IBBSegments { + n, err := s.IBBSegments[idx].WriteTo(w) + if err != nil { + return totalN, fmt.Errorf("unable to write field 'IBBSegments[%d]': %w", idx, err) + } + totalN += int64(n) + } + return totalN, nil + }, + }, + } +} + +func (s *SECBnT) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("SE: %v", err) + } + + return ret, nil +} + +func (s *SECBnT) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("SE: %v", err) + } + + return ret, nil +} + +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *SECBnT) GetStructInfo() cbnt.StructInfo { + return s.StructInfoCBNT +} + +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *SECBnT) SetStructInfo(newStructInfo cbnt.StructInfo) { + s.StructInfoCBNT = newStructInfo.(cbnt.StructInfoCBNT) +} + +// Has to be here to fullfil the reuirements of cbnt.Structure +func (s *SECBnT) ReadFrom(r io.Reader) (int64, error) { + return s.ReadFromHelper(r, true) +} + +// ReadFrom reads the SE from 'r' in format defined in the document #575623. +func (s *SECBnT) ReadFromHelper(r io.Reader, info bool) (int64, error) { + l := s.Layout() + + if !info { + l = l[1:] + } + + return s.Common.ReadFrom(r, cbnt.DummyLayout{Fields: l}) +} + +// RehashRecursive calls Rehash (see below) recursively. +func (s *SECBnT) RehashRecursive() { + s.DigestList.Rehash() + s.Rehash() +} + +// Rehash sets values which are calculated automatically depending on the rest +// data. It is usually about the total size field of an element. +func (s *SECBnT) Rehash() { + s.Variable0 = 0 + s.ElementSize = uint16(s.TotalSize()) +} + +// WriteTo writes the SE into 'w' in format defined in +// the document #575623. +func (s *SECBnT) WriteTo(w io.Writer) (int64, error) { + s.Rehash() + return s.Common.WriteTo(w, s) +} + +// Size returns the total size of the SE. +func (s *SECBnT) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *SECBnT) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + base := s.Common.PrettyString(depth, withHeader, s, "IBB Segments Element", opts...) + var lines []string + lines = append(lines, base) + + lines = append(lines, pretty.Header(depth+1, fmt.Sprintf("IBBSegments: Array of \"IBB Segments Element\" of length %d", len(s.IBBSegments)), s.IBBSegments)) + for i := 0; i < len(s.IBBSegments); i++ { + lines = append(lines, fmt.Sprintf("%sitem #%d: ", strings.Repeat(" ", int(depth+2)), i)+strings.TrimSpace(s.IBBSegments[i].PrettyString(depth+2, true))) + } + + if depth < 1 { + lines = append(lines, "") + } + if depth < 2 { + lines = append(lines, "") + } + + return strings.Join(lines, "\n") +} + +// SE for BG +// PrettyString: IBB Segments Element +type SEBG struct { + cbnt.Common + cbnt.StructInfoBG `id:"__IBBS__" version:"0x10"` + Reserved0 [1]byte `require:"0" json:"seReserved0,omitempty"` + Reserved1 [1]byte `require:"0" json:"seReserved1,omitempty"` + PBETValue PBETValue `json:"sePBETValue"` + Flags SEFlags `json:"seFlags"` + // PrettyString: IBB MCHBAR + IBBMCHBAR uint64 `json:"seIBBMCHBAR"` + // PrettyString: VT-d BAR + VTdBAR uint64 `json:"seVTdBAR"` + // PrettyString: DMA Protection 0 Base Address + PMRLBase uint32 `json:"seDMAProtBase0"` + // PrettyString: DMA Protection 0 Limit Address + PMRLLimit uint32 `json:"seDMAProtLimit0"` + // PrettyString: DMA Protection 1 Base Address + Reserved2 [8]byte `json:"seDMAProtBase1"` + // PrettyString: DMA Protection 2 Limit Address + Reserved3 [8]byte `json:"seDMAProtLimit1"` + + PostIBBHash cbnt.HashStructureFill `json:"sePostIBBHash"` + + IBBEntryPoint uint32 `json:"seIBBEntry"` + + Digest cbnt.HashStructure `json:"seDigestList"` + + IBBSegments []IBBSegment `countType:"uint8" json:"seIBBSegments,omitempty"` +} + +func (s *SEBG) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return s.StructInfoBG.TotalSize() }, + Value: func() any { return &s.StructInfoBG }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: "Reserved 0", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Reserved0 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 2, + Name: "Reserved 1", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.Reserved1 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 3, + Name: "PBET Value", + Size: func() uint64 { return 1 }, + Value: func() any { return &s.PBETValue }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 4, + Name: "Flags", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.Flags }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 5, + Name: "IBB MCHBAR", + Size: func() uint64 { return 8 }, + Value: func() any { return &s.IBBMCHBAR }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 6, + Name: "VT-d BAR", + Size: func() uint64 { return 8 }, + Value: func() any { return &s.VTdBAR }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 7, + Name: "PMRL Base", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.PMRLBase }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 8, + Name: "PMRL Limit", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.PMRLLimit }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 9, + Name: "Reserved 2", + Size: func() uint64 { return 8 }, + Value: func() any { return &s.Reserved2 }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 10, + Name: "Reserved 3", + Size: func() uint64 { return 8 }, + Value: func() any { return &s.Reserved3 }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 11, + Name: "Post IBB Hash", + Size: func() uint64 { return s.PostIBBHash.TotalSize() }, + Value: func() any { return &s.PostIBBHash }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 12, + Name: "IBB Entry Point", + Size: func() uint64 { return 4 }, + Value: func() any { return &s.IBBEntryPoint }, + Type: cbnt.ManifestFieldEndValue, + }, + { + ID: 13, + Name: "Digest", + Size: func() uint64 { return s.Digest.TotalSize() }, + Value: func() any { return &s.Digest }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 14, + Name: fmt.Sprintf("IBBSegments: Array of \"IBB Segments Element\" of length %d", len(s.IBBSegments)), + Size: func() uint64 { + size := uint64(binary.Size(uint8(0))) + for idx := range s.IBBSegments { + size += s.IBBSegments[idx].TotalSize() + } + return size + }, + Value: func() any { return &s.IBBSegments }, + Type: cbnt.ManifestFieldList, + ReadList: func(r io.Reader) (int64, error) { + var count uint8 + if err := binary.Read(r, binary.LittleEndian, &count); err != nil { + return 0, fmt.Errorf("unable to read the count for field 'IBBSegments': %w", err) + } + totalN := int64(binary.Size(count)) + s.IBBSegments = make([]IBBSegment, count) + for idx := range s.IBBSegments { + n, err := s.IBBSegments[idx].ReadFrom(r) + if err != nil { + return totalN, fmt.Errorf("unable to read field 'IBBSegments[%d]': %w", idx, err) + } + totalN += int64(n) + } + return totalN, nil + }, + WriteList: func(w io.Writer) (int64, error) { + count := uint8(len(s.IBBSegments)) + if err := binary.Write(w, binary.LittleEndian, &count); err != nil { + return 0, fmt.Errorf("unable to write the count for field 'IBBSegments': %w", err) + } + totalN := int64(binary.Size(count)) + for idx := range s.IBBSegments { + n, err := s.IBBSegments[idx].WriteTo(w) + if err != nil { + return totalN, fmt.Errorf("unable to write field 'IBBSegments[%d]': %w", idx, err) + } + totalN += int64(n) + } + return totalN, nil + }, + }, + } +} + +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *SEBG) GetStructInfo() cbnt.StructInfo { + return s.StructInfoBG +} + +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *SEBG) SetStructInfo(newStructInfo cbnt.StructInfo) { + s.StructInfoBG = newStructInfo.(cbnt.StructInfoBG) +} + +// Has to be here to fullfil the reuirements of cbnt.Structure +func (s *SEBG) ReadFrom(r io.Reader) (int64, error) { + return s.ReadFromHelper(r, true) +} + +// ReadFrom reads the SE from 'r' in format defined in the document #575623. +func (s *SEBG) ReadFromHelper(r io.Reader, info bool) (int64, error) { + l := s.Layout() + + if !info { + l = l[1:] + } + + return s.Common.ReadFrom(r, cbnt.DummyLayout{Fields: l}) +} + +// WriteTo writes the SE into 'w' in format defined in +// the document #575623. +func (s *SEBG) WriteTo(w io.Writer) (int64, error) { + return s.Common.WriteTo(w, s) +} + +func (s *SEBG) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("SE: %v", err) + } + + return ret, nil +} + +func (s *SEBG) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("SE: %v", err) + } + + return ret, nil +} + +// Size returns the total size of the SE. +func (s *SEBG) TotalSize() uint64 { + if s == nil { + return 0 + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *SEBG) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + base := s.Common.PrettyString(depth, withHeader, s, "IBB Segments Element", opts...) + var lines []string + lines = append(lines, base) + + lines = append(lines, pretty.Header(depth+1, fmt.Sprintf("IBBSegments: Array of \"IBB Segments Element\" of length %d", len(s.IBBSegments)), s.IBBSegments)) + for i := 0; i < len(s.IBBSegments); i++ { + lines = append(lines, fmt.Sprintf("%sitem #%d: ", strings.Repeat(" ", int(depth+2)), i)+strings.TrimSpace(s.IBBSegments[i].PrettyString(depth+2, true))) + } + + if depth < 1 { + lines = append(lines, "") + } + if depth < 2 { + lines = append(lines, "") + } + + return strings.Join(lines, "\n") +} + +// CachingType +type CachingType uint8 + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (v CachingType) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return v.String() +} + +// TotalSize returns the total size measured through binary.Size. +func (v CachingType) TotalSize() uint64 { + return uint64(binary.Size(v)) +} + +// WriteTo writes the CachingType into 'w' in binary format. +func (v CachingType) WriteTo(w io.Writer) (int64, error) { + return int64(v.TotalSize()), binary.Write(w, binary.LittleEndian, v) +} + +// ReadFrom reads the CachingType from 'r' in binary format. +func (v CachingType) ReadFrom(r io.Reader) (int64, error) { + return int64(v.TotalSize()), binary.Read(r, binary.LittleEndian, v) +} + +// PBETValue +type PBETValue uint8 + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (pbet PBETValue) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + var lines []string + if withHeader { + lines = append(lines, pretty.Header(depth, "PBET Value", pbet)) + } + lines = append(lines, pretty.SubValue(depth+1, "PBET Value", "", pbet.PBETValue(), opts...)...) + return strings.Join(lines, "\n") +} + +// TotalSize returns the total size measured through binary.Size. +func (pbet PBETValue) TotalSize() uint64 { + return uint64(binary.Size(pbet)) +} + +// WriteTo writes the PBETValue into 'w' in binary format. +func (pbet PBETValue) WriteTo(w io.Writer) (int64, error) { + return int64(pbet.TotalSize()), binary.Write(w, binary.LittleEndian, pbet) +} + +// ReadFrom reads the PBETValue from 'r' in binary format. +func (pbet PBETValue) ReadFrom(r io.Reader) (int64, error) { + return int64(pbet.TotalSize()), binary.Read(r, binary.LittleEndian, pbet) +} + +// SEFlags +type SEFlags uint32 + +// PrettyString returns the bits of the flags in an easy-to-read format. +func (flags SEFlags) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + var lines []string + if withHeader { + lines = append(lines, pretty.Header(depth, "SE Flags", flags)) + } + lines = append(lines, pretty.SubValue(depth+1, "Reserved 0", "", flags.Reserved0(), opts...)...) + if flags.SupportsTopSwapRemediation() { + lines = append(lines, pretty.SubValue(depth+1, "Supports Top Swap Remediation", "BIOS supports Top Swap remediation action", true, opts...)...) + } else { + lines = append(lines, pretty.SubValue(depth+1, "Supports Top Swap Remediation", "BIOS does not support Top Swap remediation action", false, opts...)...) + } + if flags.TPMFailureLeavesHierarchiesEnabled() { + lines = append(lines, pretty.SubValue(depth+1, "TPM Failure Leaves Hierarchies Enabled", "Leave Hierarchies enabled. Cap all PCRs on failure.", true, opts...)...) + } else { + lines = append(lines, pretty.SubValue(depth+1, "TPM Failure Leaves Hierarchies Enabled", "Do not leave enabled. Disable all Hierarchies or deactivate on failure.", false, opts...)...) + } + if flags.AuthorityMeasure() { + lines = append(lines, pretty.SubValue(depth+1, "Authority Measure", "Extend Authority Measurements into the Authority PCR 7", true, opts...)...) + } else { + lines = append(lines, pretty.SubValue(depth+1, "Authority Measure", "Do not extend into the Authority PCR 7", false, opts...)...) + } + if flags.Locality3Startup() { + lines = append(lines, pretty.SubValue(depth+1, "Locality 3 Startup", "Issue TPM Start-up from Locality 3", true, opts...)...) + } else { + lines = append(lines, pretty.SubValue(depth+1, "Locality 3 Startup", "Disabled", false, opts...)...) + } + if flags.DMAProtection() { + lines = append(lines, pretty.SubValue(depth+1, "DMA Protection", "Enable DMA Protection", true, opts...)...) + } else { + lines = append(lines, pretty.SubValue(depth+1, "DMA Protection", "Disable DMA Protection", false, opts...)...) + } + return strings.Join(lines, "\n") +} + +// TotalSize returns the total size measured through binary.Size. +func (flags SEFlags) TotalSize() uint64 { + return uint64(binary.Size(flags)) +} + +// WriteTo writes the SEFlags into 'w' in binary format. +func (flags SEFlags) WriteTo(w io.Writer) (int64, error) { + return int64(flags.TotalSize()), binary.Write(w, binary.LittleEndian, flags) +} + +// ReadFrom reads the SEFlags from 'r' in binary format. +func (flags SEFlags) ReadFrom(r io.Reader) (int64, error) { + return int64(flags.TotalSize()), binary.Read(r, binary.LittleEndian, flags) +} + +// PBETValue returns the raw value of the timer setting. +func (pbet PBETValue) PBETValue() uint8 { + return uint8(pbet) & 0x0f +} + +// Duration returns the value as time.Duration. +func (pbet PBETValue) Duration() time.Duration { + v := pbet.PBETValue() + if v == 0 { + return math.MaxInt64 + } + return time.Second * time.Duration(5+v) +} + +// SetDuration sets the value using standard time.Duration as the input. +func (pbet *PBETValue) SetDuration(duration time.Duration) time.Duration { + v := duration.Nanoseconds()/time.Second.Nanoseconds() - 5 + if v <= 0 { + v = 1 + } + if v >= 16 { + v = 0 + } + *pbet = PBETValue(v) + + return pbet.Duration() +} + +// Reserved0 +func (flags SEFlags) Reserved0() uint32 { + return uint32(flags & 0xffffffe0) +} + +// SupportsTopSwapRemediation +// +// PrettyString-true: BIOS supports Top Swap remediation action +// PrettyString-false: BIOS does not support Top Swap remediation action +func (flags SEFlags) SupportsTopSwapRemediation() bool { + return flags&0x10 != 0 +} + +// TPMFailureLeavesHierarchiesEnabled +// +// PrettyString-true: Leave Hierarchies enabled. Cap all PCRs on failure. +// PrettyString-false: Do not leave enabled. Disable all Hierarchies or deactivate on failure. +func (flags SEFlags) TPMFailureLeavesHierarchiesEnabled() bool { + return flags&0x08 != 0 +} + +// AuthorityMeasure +// +// NOTE: PCR[7] is disabled from MTL onwards +// +// PrettyString-true: Extend Authority Measurements into the Authority PCR 7 +// PrettyString-false: Do not extend into the Authority PCR 7 +func (flags SEFlags) AuthorityMeasure() bool { + return flags&0x04 != 0 +} + +// Locality3Startup +// +// PrettyString-true: Issue TPM Start-up from Locality 3 +// PrettyString-false: Disabled +func (flags SEFlags) Locality3Startup() bool { + return flags&0x02 != 0 +} + +// DMAProtection +// +// PrettyString-true: Enable DMA Protection +// PrettyString-false: Disable DMA Protection +func (flags SEFlags) DMAProtection() bool { + return flags&0x01 != 0 +} + +// String implements fmt.Stringer. +func (v CachingType) String() string { + switch v { + case CachingTypeWriteProtect: + return "write_protect" + case CachingTypeWriteBack: + return "write_back" + case CachingTypeReserved0: + return "value_0x02" + case CachingTypeReserved1: + return "value_0x03" + } + return fmt.Sprintf("unexpected_value_0x%02X", uint8(v)) +} From 106411875ca721163e38148ee7fa2b0122d5c578 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 20:16:48 +0200 Subject: [PATCH 33/40] feat(intel/metadata): adapt PCD to use Common methods Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/bootpolicy/pcd.go | 525 ++++++++++++++++++++++ 1 file changed, 525 insertions(+) create mode 100644 pkg/intel/metadata/cbnt/bootpolicy/pcd.go diff --git a/pkg/intel/metadata/cbnt/bootpolicy/pcd.go b/pkg/intel/metadata/cbnt/bootpolicy/pcd.go new file mode 100644 index 00000000..3ab32de3 --- /dev/null +++ b/pkg/intel/metadata/cbnt/bootpolicy/pcd.go @@ -0,0 +1,525 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cbntbootpolicy + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "strings" + + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" +) + +// PCD holds various Platform Config Data. +type PCD struct { + cbnt.Common + cbnt.StructInfoCBNT `id:"__PCDS__" version:"0x20" var0:"0" var1:"uint16(s.TotalSize())"` + Reserved0 [2]byte `json:"pcdReserved0,omitempty"` + SizeOfData [2]byte `json:"pcdSizeOfData,omitempty"` + Data []byte `json:"pcdData"` + PDRS *PDRS `json:"pcdPDRS,omitempty"` + CNBS *CNBS `json:"pcdCNBS,omitempty"` +} + +// NewPCD returns a new instance of PCD with +// all default values set. +func NewPCD() *PCD { + s := &PCD{} + copy(s.ID[:], []byte(StructureIDPCD)) + s.Version = 0x20 + s.Rehash() + return s +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *PCD) Validate() error { + if s.Version < 0x22 { + return nil + } + + if s.PDRS != nil { + if err := s.PDRS.Validate(); err != nil { + return fmt.Errorf("error on field 'PDRS': %w", err) + } + } + if s.CNBS != nil { + if err := s.CNBS.Validate(); err != nil { + return fmt.Errorf("error on field 'CNBS': %w", err) + } + } + return nil +} + +func (s *PCD) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return s.StructInfoCBNT.TotalSize() }, + Value: func() any { return &s.StructInfoCBNT }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: "Reserved 0", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.Reserved0 }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 2, + Name: "Size Of Data", + Size: func() uint64 { return 2 }, + Value: func() any { return &s.SizeOfData }, + Type: cbnt.ManifestFieldArrayStatic, + }, + { + ID: 3, + Name: "Data", + Size: func() uint64 { + size := binary.LittleEndian.Uint16(s.SizeOfData[:]) + if size == 0 && len(s.Data) != 0 { + size = uint16(len(s.Data)) + } + if s.ElementSize != 0 { + resSize, err := s.SizeOf(1) + if err != nil { + return uint64(size) + } + + sodSize, err := s.SizeOf(2) + if err != nil { + return uint64(size) + } + base := s.StructInfoCBNT.TotalSize() + resSize + sodSize + guessedSize := base + uint64(size) + if guessedSize != uint64(s.ElementSize) { + size = s.StructInfoCBNT.ElementSize - uint16(s.StructInfoCBNT.TotalSize()) - uint16(resSize) - uint16(sodSize) + } + } + return uint64(size) + }, + Value: func() any { return &s.Data }, + Type: cbnt.ManifestFieldArrayDynamicWithSize, + }, + } +} + +func (s *PCD) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("PCD: %v", err) + } + + return ret, nil +} + +func (s *PCD) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("PCD: %v", err) + } + + return ret, nil +} + +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *PCD) GetStructInfo() cbnt.StructInfo { + return s.StructInfoCBNT +} + +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *PCD) SetStructInfo(newStructInfo cbnt.StructInfo) { + s.StructInfoCBNT = newStructInfo.(cbnt.StructInfoCBNT) +} + +// Dummy helper to comply with cbnt.Structure interface +func (s *PCD) ReadFrom(r io.Reader) (int64, error) { + return s.ReadFromHelper(r, true) +} + +// ReadFrom reads the PCD from 'r' in format defined in the document #575623. +func (s *PCD) ReadFromHelper(r io.Reader, info bool) (int64, error) { + l := s.Layout() + + if !info { + l = l[1:] + } + + n, err := s.Common.ReadFrom(r, cbnt.DummyLayout{Fields: l}) + if err != nil { + return n, err + } + + if s.Version > 0x21 { + rn := bytes.NewReader(s.Data) + structInfoSize := binary.Size(cbnt.StructInfoCBNT{}) + + for rn.Len() >= structInfoSize { + var structInfo cbnt.StructInfoCBNT + if err := binary.Read(rn, binary.LittleEndian, &structInfo); err != nil { + return n, err + } + + switch structInfo.ID.String() { + case StructureIDPDRS: + p := NewPDRS() + p.SetStructInfo(structInfo) + if _, err := p.ReadFromHelper(rn, false); err != nil { + return n, err + } + s.PDRS = p + case StructureIDCNBS: + c := NewCNBS() + c.SetStructInfo(structInfo) + if _, err := c.ReadFromHelper(rn, false); err != nil { + return n, err + } + s.CNBS = c + default: + return n, nil + } + } + } + + return n, nil + +} + +// RehashRecursive calls Rehash (see below) recursively. +func (s *PCD) RehashRecursive() { + s.Rehash() +} + +// Rehash sets values which are calculated automatically depending on the rest +// data. It is usually about the total size field of an element. +func (s *PCD) Rehash() { + if s.Version > 0x21 && len(s.Data) == 0 { + var out bytes.Buffer + if s.PDRS != nil { + _, _ = s.PDRS.WriteTo(&out) + } + if s.CNBS != nil { + _, _ = s.CNBS.WriteTo(&out) + } + if out.Len() > 0 { + s.Data = out.Bytes() + binary.LittleEndian.PutUint16(s.SizeOfData[:], uint16(len(s.Data))) + } + } + s.Variable0 = 0 + s.ElementSize = uint16(s.StructInfoCBNT.TotalSize() + 2 + 2 + uint64(len(s.Data))) +} + +// WriteTo writes the PCD into 'w' in format defined in +// the document #575623. +func (s *PCD) WriteTo(w io.Writer) (int64, error) { + s.Rehash() + return s.Common.WriteTo(w, s) +} + +// Size returns the total size of the PCD. +func (s *PCD) TotalSize() uint64 { + if s == nil { + return 0 + } + + if s.ElementSize != 0 { + return uint64(s.ElementSize) + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *PCD) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + base := s.Common.PrettyString(depth, withHeader, s, "PCD", opts...) + + var lines []string + lines = append(lines, base) + if s.Version > 0x21 && s.PDRS != nil { + lines = append(lines, s.PDRS.PrettyString(depth, true, opts...)) + } + if s.Version > 0x21 && s.CNBS != nil { + lines = append(lines, s.CNBS.PrettyString(depth, true, opts...)) + } + + return strings.Join(lines, "\n") +} + +// PDRS +type PDRS struct { + cbnt.Common + cbnt.StructInfoCBNT `id:"__PDRS__" version:"0x20" var0:"0" var1:"uint16(s.TotalSize())"` + Data []byte `json:"pdrsData"` +} + +// NewPDRS returns a new instance of PDRS with all default values set. +func NewPDRS() *PDRS { + s := &PDRS{} + copy(s.ID[:], []byte(StructureIDPDRS)) + s.Version = 0x20 + s.Rehash() + return s +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *PDRS) Validate() error { + return nil +} + +func (s *PDRS) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return s.StructInfoCBNT.TotalSize() }, + Value: func() any { return &s.StructInfoCBNT }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: "Data", + Size: func() uint64 { + if s.ElementSize != 0 { + return uint64(s.ElementSize) + } + return uint64(len(s.Data)) + }, + Value: func() any { return &s.Data }, + Type: cbnt.ManifestFieldArrayDynamicWithSize, + }, + } +} + +func (s *PDRS) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("PDRS: %v", err) + } + + return ret, nil +} + +func (s *PDRS) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("PDRS: %v", err) + } + + return ret, nil +} + +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *PDRS) GetStructInfo() cbnt.StructInfo { + return s.StructInfoCBNT +} + +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *PDRS) SetStructInfo(newStructInfo cbnt.StructInfo) { + s.StructInfoCBNT = newStructInfo.(cbnt.StructInfoCBNT) +} + +// ReadFrom reads the PDRS from 'r' in format defined in the document #575623. +func (s *PDRS) ReadFrom(r io.Reader) (int64, error) { + return s.ReadFromHelper(r, true) +} + +// ReadFrom reads the PDRS from 'r' in format defined in the document #575623. +func (s *PDRS) ReadFromHelper(r io.Reader, info bool) (int64, error) { + l := s.Layout() + + if !info { + l = l[1:] + } + + return s.Common.ReadFrom(r, cbnt.DummyLayout{Fields: l}) +} + +// RehashRecursive calls Rehash (see below) recursively. +func (s *PDRS) RehashRecursive() { + s.Rehash() +} + +// Rehash sets values which are calculated automatically depending on the rest +// data. It is usually about the total size field of an element. +func (s *PDRS) Rehash() { + s.Variable0 = 0 + s.ElementSize = uint16(len(s.Data)) +} + +// WriteTo writes the PDRS into 'w' in format defined in +// the document #575623. +func (s *PDRS) WriteTo(w io.Writer) (int64, error) { + s.Rehash() + return s.Common.WriteTo(w, s) +} + +// Size returns the total size of the PDRS. +func (s *PDRS) TotalSize() uint64 { + if s == nil { + return 0 + } + + if s.ElementSize != 0 { + return uint64(s.StructInfo().TotalSize()) + uint64(s.ElementSize) + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *PDRS) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return s.Common.PrettyString(depth, withHeader, s, "PDRS", opts...) +} + +// CNBS +type CNBS struct { + cbnt.Common + cbnt.StructInfoCBNT `id:"__CNBS__" version:"0x20" var0:"0" var1:"12"` + BufferData IBBSegment `json:"seIBBSegment"` +} + +// NewCNBS returns a new instance of CNBS with all default values set. +func NewCNBS() *CNBS { + s := &CNBS{} + copy(s.ID[:], []byte(StructureIDCNBS)) + s.Version = 0x20 + s.Rehash() + return s +} + +// Validate (recursively) checks the structure if there are any unexpected +// values. It returns an error if so. +func (s *CNBS) Validate() error { + if err := s.BufferData.Validate(); err != nil { + return fmt.Errorf("error on field 'BufferData': %w", err) + } + + return nil +} + +func (s *CNBS) Layout() []cbnt.LayoutField { + return []cbnt.LayoutField{ + { + ID: 0, + Name: "Struct Info", + Size: func() uint64 { return s.StructInfoCBNT.TotalSize() }, + Value: func() any { return &s.StructInfoCBNT }, + Type: cbnt.ManifestFieldSubStruct, + }, + { + ID: 1, + Name: "Buffer Data", + Size: func() uint64 { return s.BufferData.TotalSize() }, + Value: func() any { return &s.BufferData }, + Type: cbnt.ManifestFieldSubStruct, + }, + } +} + +func (s *CNBS) SizeOf(id int) (uint64, error) { + ret, err := s.Common.SizeOf(s, id) + if err != nil { + return ret, fmt.Errorf("CNBS: %v", err) + } + + return ret, nil +} + +func (s *CNBS) OffsetOf(id int) (uint64, error) { + ret, err := s.Common.OffsetOf(s, id) + if err != nil { + return ret, fmt.Errorf("CNBS: %v", err) + } + + return ret, nil +} + +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *CNBS) GetStructInfo() cbnt.StructInfo { + return s.StructInfoCBNT +} + +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). +func (s *CNBS) SetStructInfo(newStructInfo cbnt.StructInfo) { + s.StructInfoCBNT = newStructInfo.(cbnt.StructInfoCBNT) +} + +// ReadFrom reads the CNBS from 'r' in format defined in the document #575623. +func (s *CNBS) ReadFrom(r io.Reader) (int64, error) { + return s.ReadFromHelper(r, true) +} + +// ReadFrom reads the CNBS from 'r' in format defined in the document #575623. +func (s *CNBS) ReadFromHelper(r io.Reader, info bool) (int64, error) { + l := s.Layout() + + if !info { + l = l[1:] + } + + return s.Common.ReadFrom(r, cbnt.DummyLayout{Fields: l}) +} + +// RehashRecursive calls Rehash (see below) recursively. +func (s *CNBS) RehashRecursive() { + s.Rehash() +} + +// Rehash sets values which are calculated automatically depending on the rest +// data. It is usually about the total size field of an element. +func (s *CNBS) Rehash() { + s.Variable0 = 0 + s.ElementSize = uint16(s.BufferData.TotalSize()) +} + +// WriteTo writes the CNBS into 'w' in format defined in +// the document #575623. +func (s *CNBS) WriteTo(w io.Writer) (int64, error) { + s.Rehash() + return s.Common.WriteTo(w, s) +} + +// Size returns the total size of the CNBS. +func (s *CNBS) TotalSize() uint64 { + if s == nil { + return 0 + } + + if s.ElementSize != 0 { + return uint64(s.StructInfo().TotalSize()) + uint64(s.ElementSize) + } + + return s.Common.TotalSize(s) +} + +// PrettyString returns the content of the structure in an easy-to-read format. +func (s *CNBS) PrettyString(depth uint, withHeader bool, opts ...pretty.Option) string { + return s.Common.PrettyString(depth, withHeader, s, "CNBS", opts...) +} From 91522cbc9231a6db4ceaf84aab8d9a8e0be86070 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 20:18:37 +0200 Subject: [PATCH 34/40] chore(intel/metadata): add BPM dumps for all spec versions Signed-off-by: Michal Gorlas --- .../metadata/cbnt/bootpolicy/testdata/bpm10.bin | Bin 0 -> 732 bytes .../metadata/cbnt/bootpolicy/testdata/bpm20.bin | Bin 0 -> 973 bytes .../metadata/cbnt/bootpolicy/testdata/bpm21.bin | Bin 0 -> 1517 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 pkg/intel/metadata/cbnt/bootpolicy/testdata/bpm10.bin create mode 100644 pkg/intel/metadata/cbnt/bootpolicy/testdata/bpm20.bin create mode 100644 pkg/intel/metadata/cbnt/bootpolicy/testdata/bpm21.bin diff --git a/pkg/intel/metadata/cbnt/bootpolicy/testdata/bpm10.bin b/pkg/intel/metadata/cbnt/bootpolicy/testdata/bpm10.bin new file mode 100644 index 0000000000000000000000000000000000000000..bdf6301e0aaed3d6771ed19d2b10d714e7a53bbb GIT binary patch literal 732 zcma!#cXW0Nh>sUwWB>vdhWL0-C#PT_pMim&86?DT@gJCCxCx~pJaiJMo*?+}|Nnn( z1_g%Zw|4@M&7XDmVaU?HsB_0v7Bao@uAjTGMLWks?s&OpCKJS@5C0n)`N2$w{{R0E z6fgiC7vSsS2y`3=0|(qTkYKPoP!Q+^0R|3621bUTdS>y=pH)}i{C}YG6~FqCsPM*_ zt8YE-adq>wj4xR$^ve44oP(}ge&^&zd`Ud{)P0fT!8dYpDhb>n_AMJYQiWN$X6)*J zr^2(2JK=lUk`iZ$$BcXa+Da^2nk{0sV)^c)`>gj~NN4)8>ooHZu)r?!PwAal+$ck#SFI=BS_S3b~><<8{S85hu@~JurN5MkKE$jHFN(7+fU@9E?e93QX1Ai~JNz`)NABrt&hQ0N1)Fi0%} zSoHt@|1%g^7`Pb}7a!jP}~m@@jWND@-P@MoPPSgDoFg~w94bNE(Xt5P&s-^B3-}e+TEV* zD%r2zeLdD>yRoaf@!xOvC(37xG;JA$fcC9F)6Tz$C!lhw=kzJ&ay_b#mmBggS7JEG zX+E=fopOdN$bCS-0-+B4Z&<4jW*#X0@ZSL<$iPth;eP{^-OvhTSMf8%$A?6OfWt%s zri#Iap{|~R70mqyH4vySz%2-?x45n_g#Pry2k!k~db2-BcxO(*`A`%a9U_j!2C3~PEJO>Z@JFN8uw4$>j^A9`u6GO zsu^C_3k3B<3|2FIsZM#n{7d(gNsqMhvYhjCS#CZOuT1xR^1<<{llz8~)34h3eVuIl zSdQV}MvFb&e%teMTlUZV z{uZ?Hh6pGixETcgrM0IwMjqLnbj`lrSS-aseXYmLvg6)6UQAJ#yRE&~|KhZQi0f<{ zoq>!uQ+CZRBOw^P5D|^ z3LUN)Ecn{pb4GOg*>Y{4XE_diJ}fhBm94*gKEgcluM&dr|-Z literal 0 HcmV?d00001 diff --git a/pkg/intel/metadata/cbnt/bootpolicy/testdata/bpm21.bin b/pkg/intel/metadata/cbnt/bootpolicy/testdata/bpm21.bin new file mode 100644 index 0000000000000000000000000000000000000000..92be30493ff03688610b12f156ada83e27add78d GIT binary patch literal 1517 zcmeHF`BPI@7`HpC0hwpsfnR93EJ@-J6lZ*2)2(lt* zgK;?wMh?gW2=Z`t_JtrbV1oewXkJAd0OOKv005RD4u!=XY8#|lu+1U}k_QxkIv@e; zeOkmftFQBBhRS(?lzcstIYYNze#%V$2K{-cb-ac`O-@m#6(dmrH-IE?>oW=-Bgh2TS5!v=hf&%_y1V+II{~Nwi~^<=BM+1z$mKg}MhR%j0Ge5} z5NY^Ot+%hclt;6OK^b)n`jcFK$@6@|5yf(xOqD4g-=O4sxdD%6LS$Q)GR!dMvkJH$ z9XH>Gg#SHO5%G3RH8HohW?EmYwnp$B@GgpJdU!;=dSIl!mVDt9F9h>_h*km1J44Y) zVn3Wwcr{(5_e&PhJyv+q;9#m!>X6sVCN}kLA?`?=#PI^QLnL+4Y;^Px-_rvE=(>nGIpKzXd!Ro+lacN6zE!UVO>$2{0zH zTe2MgaW`|Ic^J&D^#$E_3@=;uqDFR`F8PSyz3x+68xvaGbzSL4sDqWew{R7)%Cp2T z7NE?gjq*?%N9@qlIny5_X#A-!@rqZbVXJPY$h9-pE&9a+p4TPG^jS~gT0gzg zD8+x^lFp%LD|_vmn=?4=^VVbeb$>-_81gdU;Ae49ZU}z5Y&k0zN1J2a86lSYwXgx+ zu|KcvLrq)UFt5V`Ryt{0($qsY?fN#jKwp@(OuFLMalJh)%I|hpv(0M(hfl{{%jeJ# zlFggrW~Cj>EYcR0l%HhMkh&U2!M*1uW`IJ77EfSj;6KNDwVCe`SoSH`zFe@Vkp)uPp(a zID(x^*&_A}eHUq|9tN-7O0?3Es+Xbf>$a8}$tI3f6wlTme0|71J)}o`Ut( zPs8NPL!&np^~~>WP`^rJSBG6JvC&D15)K8Pa<02$(O$0qu}+{kd@g6oN?!HKb6_?~ Kt}SXYto;|m*JO_X literal 0 HcmV?d00001 From 198d3a5ed133c437e91051d3d61443903cec62be Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Thu, 23 Apr 2026 20:20:29 +0200 Subject: [PATCH 35/40] fix(intel/metadata): bpmdump example Signed-off-by: Michal Gorlas --- pkg/intel/metadata/common/examples/cmd/bpmdump/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/intel/metadata/common/examples/cmd/bpmdump/main.go b/pkg/intel/metadata/common/examples/cmd/bpmdump/main.go index 0aa50460..55747789 100644 --- a/pkg/intel/metadata/common/examples/cmd/bpmdump/main.go +++ b/pkg/intel/metadata/common/examples/cmd/bpmdump/main.go @@ -9,7 +9,7 @@ import ( "log" "os" - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/cbntbootpolicy" + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt/bootpolicy" ) func assertNoError(err error) { @@ -22,7 +22,7 @@ func main() { f, err := os.Open(os.Args[1]) assertNoError(err) - m := &cbntbootpolicy.Manifest{} + m := &cbntbootpolicy.ManifestCBnT{} _, err = m.ReadFrom(f) assertNoError(err) From a7581700a68978b783be654692fab1b609ebbc92 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Fri, 24 Apr 2026 20:13:26 +0200 Subject: [PATCH 36/40] chore(intel/metadata): remove unittest/read_write.go Will be replaced in the follow-up commit with the integration tests. Signed-off-by: Michal Gorlas --- .../metadata/common/unittest/read_write.go | 59 ------------------- 1 file changed, 59 deletions(-) delete mode 100644 pkg/intel/metadata/common/unittest/read_write.go diff --git a/pkg/intel/metadata/common/unittest/read_write.go b/pkg/intel/metadata/common/unittest/read_write.go deleted file mode 100644 index bd03a3e8..00000000 --- a/pkg/intel/metadata/common/unittest/read_write.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2017-2021 the LinuxBoot Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package unittest - -import ( - "bytes" - "os" - "testing" - - "github.com/linuxboot/fiano/pkg/intel/metadata/bg" - "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" - "github.com/stretchr/testify/require" -) - -func CBNTManifestReadWrite(t *testing.T, m cbnt.Manifest, testDataFilePath string) { - testData, err := os.ReadFile(testDataFilePath) - require.NoError(t, err) - - nR, err := m.ReadFrom(bytes.NewReader(append(testData, []byte(`extra bytes`)...))) - require.NoError(t, err) - require.Equal(t, int64(len(testData)), nR) - require.Equal(t, nR, int64(m.TotalSize())) - - prettyString := m.PrettyString(0, true) - - var out bytes.Buffer - nW, err := m.WriteTo(&out) - require.NoError(t, err) - - newPrettyString := m.PrettyString(0, true) - require.Equal(t, prettyString, newPrettyString, newPrettyString) - require.Equal(t, string(testData), out.String()) - require.Equal(t, nW, nR) - require.Equal(t, nW, int64(out.Len())) -} - -func BGManifestReadWrite(t *testing.T, m bg.Manifest, testDataFilePath string) { - testData, err := os.ReadFile(testDataFilePath) - require.NoError(t, err) - - nR, err := m.ReadFrom(bytes.NewReader(testData)) - require.NoError(t, err) - require.Equal(t, int64(len(testData)), nR) - require.Equal(t, nR, int64(m.TotalSize())) - - prettyString := m.PrettyString(0, true) - - var out bytes.Buffer - nW, err := m.WriteTo(&out) - require.NoError(t, err) - - newPrettyString := m.PrettyString(0, true) - require.Equal(t, prettyString, newPrettyString, newPrettyString) - require.Equal(t, string(testData), out.String()) - require.Equal(t, nW, nR) - require.Equal(t, nW, int64(out.Len())) -} From 7ce450a02a6462d23f6fca6cafdbb787418531b4 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Fri, 24 Apr 2026 20:17:24 +0200 Subject: [PATCH 37/40] feat(intel/metadata): add integration tests for BPM and KM Signed-off-by: Michal Gorlas --- .../metadata/common/integration/README.md | 42 ++++ .../metadata/common/integration/read_write.go | 181 ++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 pkg/intel/metadata/common/integration/README.md create mode 100644 pkg/intel/metadata/common/integration/read_write.go diff --git a/pkg/intel/metadata/common/integration/README.md b/pkg/intel/metadata/common/integration/README.md new file mode 100644 index 00000000..619249f8 --- /dev/null +++ b/pkg/intel/metadata/common/integration/README.md @@ -0,0 +1,42 @@ +# Integration Tests + +Since the majority of types share the same methods, most tests can be generalized. + +For each manifest there are sample binaries corresponding to different versions: + - `cbnt/bootpolicy/testdata/bpm10.bin` - BPM complying with Boot Guard 1.0 + - `cbnt/bootpolicy/testdata/bpm20.bin` - BPM complying with CBnT 2.0 + - `cbnt/bootpolicy/testdata/bpm21.bin` - BPM complying with CBnT 2.1 + - `cbnt/keymanifest/testdata/km_bg.bin` - KM complying with Boot Guard 1.0 + - `cbnt/keymanifest/testdata/km_cbnt.bin` - KM complying with CBnT 2.x + +The integration test entrypoint is `ManifestReadWrite()` from `common/integration/read_write.go`. +It reads the provided binary into a Manifest implementation and then validates the full read/write contract: + +- reads exactly the manifest bytes and ignores trailing data +- verifies `SizeOf()` and `OffsetOf()` for all top-level fields +- verifies `GetStructInfo()` and `SetStructInfo()` accessors +- validates manifest invariants via `Validate()` +- verifies `TotalSize()` matches bytes consumed by `ReadFrom()` +- checks `Print()` output against signed/unsigned expected patterns +- serializes with `WriteTo()` and verifies a byte-for-byte round trip against the original input from `ReadFrom()` +- recursively verifies size/offset behavior for nested structures and structure lists + +The helper also checks that `PrettyString()` output is stable before and after serialization (note: it the coverage is low here given that the output is hard to generalize). + +## Adding integration tests for a new manifest version + +1. Add the sample binary to the package `testdata/` directory. +2. Instantiate the manifest with the right version in `manifest_test.go`. +3. Call `integration.ManifestReadWrite(t, m, "testdata/.bin")`. + +Example: + +```go +func TestReadWriteCBNT2x(t *testing.T) { + m, err := NewManifest(cbnt.Version2x) + if err != nil { + t.Fatalf("%v", err) + } + integration.ManifestReadWrite(t, m, "testdata/bpm2x.bin") +} +``` diff --git a/pkg/intel/metadata/common/integration/read_write.go b/pkg/intel/metadata/common/integration/read_write.go new file mode 100644 index 00000000..8ff365c0 --- /dev/null +++ b/pkg/intel/metadata/common/integration/read_write.go @@ -0,0 +1,181 @@ +// Copyright 2017-2026 the LinuxBoot Authors. All rights reserved +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package integration + +import ( + "bytes" + "fmt" + "io" + "os" + "strings" + "testing" + + "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" + "github.com/linuxboot/fiano/pkg/intel/metadata/common/pretty" + "github.com/stretchr/testify/require" +) + +func sizeList(m cbnt.Manifest) map[int]uint64 { + var ret map[int]uint64 + ret = make(map[int]uint64) + + for i, f := range m.Layout() { + ret[i] = f.Size() + } + + return ret +} + +func sizeAndOffset(t *testing.T, list map[int]uint64, m cbnt.Manifest) uint64 { + // Sizes + for i := 0; i < len(m.Layout()); i++ { + s, err := m.SizeOf(i) + require.NoError(t, err) + require.Equal(t, list[i], s) + } + + // Offsets + s, err := m.OffsetOf(0) + require.NoError(t, err) + require.Equal(t, uint64(0), s) + + prev := list[0] + for i := 1; i < len(m.Layout()); i++ { + s, err := m.OffsetOf(i) + require.NoError(t, err) + require.Equal(t, prev, s) + prev += list[i] + } + + return prev +} + +func ManifestReadWrite(t *testing.T, m cbnt.Manifest, testDataFilePath string) { + testData, err := os.ReadFile(testDataFilePath) + require.NoError(t, err) + + nR, err := m.ReadFrom(bytes.NewReader(append(testData, []byte(`extra bytes`)...))) + require.NoError(t, err) + require.Equal(t, int64(len(testData)), nR) + + // We have to read the values AFTER the read, otherwise all the fields of dynamic + // type will be incorrect (obviously). + list := sizeList(m) + + sizeAndOffset(t, list, m) + + // Getters + l := m.Layout() + field0 := l[0] + val := field0.Value + + // So same as above we don't know here what exact type we are testing, but we know it should implement getter and setter. + // Thus we can make sneaky type assertion to an interface that only has these methids, and let the test fail + // if the actual type that we are testing does not contain this methods. + type structInfoAccessor interface { + GetStructInfo() cbnt.StructInfo + SetStructInfo(cbnt.StructInfo) + Print() + } + + accessor, ok := m.(structInfoAccessor) + require.True(t, ok, "Manifest must implement GetStructInfo() and SetStructInfo()") + + originalInfo := accessor.GetStructInfo() + type nestedStructInfoAccessor interface { + GetStructInfo() cbnt.StructInfo + } + + var expectedInfo cbnt.StructInfo + if nestedAccessor, ok := val().(nestedStructInfoAccessor); ok { + expectedInfo = nestedAccessor.GetStructInfo() + } else { + var structInfoOK bool + expectedInfo, structInfoOK = val().(cbnt.StructInfo) + require.True(t, structInfoOK, "Layout[0] must be StructInfo or expose GetStructInfo()") + } + require.Equal(t, expectedInfo, originalInfo, "Getter should return the value from Layout") + + accessor.SetStructInfo(expectedInfo) + require.Equal(t, originalInfo, accessor.GetStructInfo(), "Getter should match the value just set") + + // Validate + err = m.Validate() + require.NoError(t, err) + + require.Equal(t, nR, int64(m.TotalSize())) + + // Print and PrettyString on WriteTo + prettyString := m.PrettyString(0, true) + oldStdout := os.Stdout + r, w, err := os.Pipe() + require.NoError(t, err, "Failed to create pipe for stdout") + os.Stdout = w + + accessor.Print() + + w.Close() + os.Stdout = oldStdout + + var buf bytes.Buffer + _, err = io.Copy(&buf, r) + require.NoError(t, err, "Failed to read from pipe") + actualOutput := buf.String() + + expectedKMUnsigned := fmt.Sprintf("%v\n --KeyAndSignature--\n\tKey Manifest not signed!\n\n", + m.PrettyString(1, true, pretty.OptionOmitKeySignature(true))) + + expectedKMSigned := fmt.Sprintf("%v\n", + m.PrettyString(1, true, pretty.OptionOmitKeySignature(false))) + + // Differs too much, thus we just grep for these two strings + expectedBPMUnsigned := " --PMSE--\n\tBoot Policy Manifest not signed!\n\n" + expectedBPMSigned := "Sig Scheme:" + + require.True(t, actualOutput == expectedKMSigned || actualOutput == expectedKMUnsigned || + strings.Contains(actualOutput, expectedBPMUnsigned) || strings.Contains(actualOutput, expectedBPMSigned), + "Print() output did not match either the signed or unsigned PrettyString format") + + var out bytes.Buffer + nW, err := m.WriteTo(&out) + require.NoError(t, err) + + newPrettyString := m.PrettyString(0, true) + require.Equal(t, prettyString, newPrettyString, newPrettyString) + require.Equal(t, string(testData), out.String()) + require.Equal(t, nW, nR) + require.Equal(t, nW, int64(out.Len())) + + // Sub Structures, for all of the fields of the manifest + // that we are testing, we can check whether these are implementing + // cbnt.Structure, and basically run exactly the same tests as we did + // for the manifest itself (well almost exactlu the same :D). + for _, f := range m.Layout() { + subStruct := f.Value() + if subStruct == nil { + continue + } + if f.Size() == 0 { + continue + } + + accessor, ok := subStruct.(cbnt.Structure) + if ok { + list := sizeList(accessor) + total := sizeAndOffset(t, list, accessor) + require.Equal(t, total, accessor.TotalSize()) + } + + // special case for []Hash + hashAccessor, ok := subStruct.(cbnt.StructureList) + if ok { + for _, i := range hashAccessor.Structures() { + list := sizeList(i) + total := sizeAndOffset(t, list, i) + require.Equal(t, total, i.TotalSize()) + } + } + } +} From 8d30fd06c4cd9ca75bb5f651a80e1bcd7ab72149 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Wed, 29 Apr 2026 01:11:28 +0200 Subject: [PATCH 38/40] fix(cbnt/bootpolicy): use unnamed returns in Manifest.ReadFrom Signed-off-by: Michal Gorlas --- .../metadata/cbnt/bootpolicy/manifest.go | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/pkg/intel/metadata/cbnt/bootpolicy/manifest.go b/pkg/intel/metadata/cbnt/bootpolicy/manifest.go index cc37dec6..9506fca7 100644 --- a/pkg/intel/metadata/cbnt/bootpolicy/manifest.go +++ b/pkg/intel/metadata/cbnt/bootpolicy/manifest.go @@ -398,18 +398,17 @@ func (s *ManifestBG) OffsetOf(id int) (uint64, error) { // ReadFrom reads the Manifest from 'r' in format defined in the document #575623. // Note that the BPM is a special case: we do not use common way of handling the reading here. -func (s *ManifestBG) ReadFrom(r io.Reader) (returnN int64, returnErr error) { +func (s *ManifestBG) ReadFrom(r io.Reader) (int64, error) { var missingFieldsByIndices = [4]bool{ 0: true, 3: true, } + + var err error defer func() { - if returnErr != nil { - return - } for fieldIndex, v := range missingFieldsByIndices { if v { - returnErr = fmt.Errorf("field '%s' is missing", s.fieldNameByIndex(fieldIndex)) + err = fmt.Errorf("field '%s' is missing", s.fieldNameByIndex(fieldIndex)) break } } @@ -418,7 +417,7 @@ func (s *ManifestBG) ReadFrom(r io.Reader) (returnN int64, returnErr error) { previousFieldIndex := int(-1) for { var structInfo cbnt.StructInfoBG - err := binary.Read(r, binary.LittleEndian, &structInfo) + err = binary.Read(r, binary.LittleEndian, &structInfo) if err == io.EOF || err == io.ErrUnexpectedEOF { return totalN, nil } @@ -801,19 +800,17 @@ func (s *ManifestCBnT) OffsetOf(id int) (uint64, error) { } // ReadFrom reads the Manifest from 'r' in format defined in the document #575623. -// Same note as above: this is an exception from the rule of usijg common approach. -func (s *ManifestCBnT) ReadFrom(r io.Reader) (returnN int64, returnErr error) { +// Same note as above: this is an exception from the rule of using common approach. +func (s *ManifestCBnT) ReadFrom(r io.Reader) (int64, error) { var missingFieldsByIndices = [7]bool{ 0: true, 6: true, } + var err error defer func() { - if returnErr != nil { - return - } for fieldIndex, v := range missingFieldsByIndices { if v { - returnErr = fmt.Errorf("field '%s' is missing", s.fieldNameByIndex(fieldIndex)) + err = fmt.Errorf("field '%s' is missing", s.fieldNameByIndex(fieldIndex)) break } } @@ -822,7 +819,7 @@ func (s *ManifestCBnT) ReadFrom(r io.Reader) (returnN int64, returnErr error) { previousFieldIndex := int(-1) for { var structInfo cbnt.StructInfoCBNT - err := binary.Read(r, binary.LittleEndian, &structInfo) + err = binary.Read(r, binary.LittleEndian, &structInfo) if err == io.EOF || err == io.ErrUnexpectedEOF { return totalN, nil } From c28ea16263f6d60ef75c95092efbe272aafacc28 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Wed, 29 Apr 2026 15:34:14 +0200 Subject: [PATCH 39/40] refactor(cbnt/bootpolicy): PM Data size formatting Signed-off-by: Michal Gorlas --- pkg/intel/metadata/cbnt/bootpolicy/pm.go | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/pkg/intel/metadata/cbnt/bootpolicy/pm.go b/pkg/intel/metadata/cbnt/bootpolicy/pm.go index beea619a..d7a27940 100644 --- a/pkg/intel/metadata/cbnt/bootpolicy/pm.go +++ b/pkg/intel/metadata/cbnt/bootpolicy/pm.go @@ -82,13 +82,9 @@ func (s *PMCBnT) Layout() []cbnt.LayoutField { Type: cbnt.ManifestFieldArrayStatic, }, { - ID: 3, - Name: "Data", - Size: func() uint64 { - size := uint64(binary.Size(uint16(0))) - size += uint64(binary.Size(s.DataSize)) - return size - }, + ID: 3, + Name: "Data", + Size: func() uint64 { return uint64(binary.Size(uint16(0))) + uint64(binary.Size(s.DataSize)) }, Value: func() any { return &s.Data }, Type: cbnt.ManifestFieldArrayDynamicWithPrefix, }, @@ -202,13 +198,9 @@ func (s *PMBG) Layout() []cbnt.LayoutField { Type: cbnt.ManifestFieldArrayStatic, }, { - ID: 2, - Name: "Data", - Size: func() uint64 { - size := uint64(binary.Size(uint16(0))) - size += uint64(s.DataSize) - return size - }, + ID: 2, + Name: "Data", + Size: func() uint64 { return uint64(binary.Size(uint16(0))) + uint64(s.DataSize) }, Value: func() any { return &s.Data }, Type: cbnt.ManifestFieldArrayDynamicWithPrefix, }, From 574d1f06e31802c0308b3c21721eb355f30c49ad Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Wed, 29 Apr 2026 20:07:18 +0200 Subject: [PATCH 40/40] docs(intel/metadata): add comments on all exported methods and functions Signed-off-by: Michal Gorlas --- .../metadata/cbnt/bootpolicy/Reserved.go | 3 ++ pkg/intel/metadata/cbnt/bootpolicy/bpmh.go | 6 +++ .../metadata/cbnt/bootpolicy/manifest.go | 51 +++++++++++++++++++ pkg/intel/metadata/cbnt/bootpolicy/pcd.go | 9 ++++ pkg/intel/metadata/cbnt/bootpolicy/pm.go | 7 +++ pkg/intel/metadata/cbnt/bootpolicy/se.go | 9 ++++ .../metadata/cbnt/bootpolicy/signature.go | 3 ++ pkg/intel/metadata/cbnt/bootpolicy/txt.go | 3 ++ .../cbnt/chipset_ac_module_information.go | 4 ++ pkg/intel/metadata/cbnt/common.go | 12 +++++ pkg/intel/metadata/cbnt/hash.go | 11 ++++ pkg/intel/metadata/cbnt/key.go | 3 ++ pkg/intel/metadata/cbnt/key_signature.go | 3 ++ pkg/intel/metadata/cbnt/keymanifest/hash.go | 10 +--- .../metadata/cbnt/keymanifest/manifest_bg.go | 6 +++ .../cbnt/keymanifest/manifest_cbnt.go | 7 +++ pkg/intel/metadata/cbnt/signature.go | 3 ++ pkg/intel/metadata/cbnt/structure.go | 4 ++ pkg/intel/metadata/cbnt/structure_bg.go | 5 ++ pkg/intel/metadata/cbnt/tpm_info_list.go | 4 ++ pkg/intel/metadata/cbnt/types.go | 2 +- 21 files changed, 156 insertions(+), 9 deletions(-) diff --git a/pkg/intel/metadata/cbnt/bootpolicy/Reserved.go b/pkg/intel/metadata/cbnt/bootpolicy/Reserved.go index b4a0f03d..c9939096 100644 --- a/pkg/intel/metadata/cbnt/bootpolicy/Reserved.go +++ b/pkg/intel/metadata/cbnt/bootpolicy/Reserved.go @@ -36,6 +36,7 @@ func (s *Reserved) Validate() error { return nil } +// Layout returns the structure's layout descriptor func (s *Reserved) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -55,6 +56,7 @@ func (s *Reserved) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *Reserved) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -64,6 +66,7 @@ func (s *Reserved) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *Reserved) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { diff --git a/pkg/intel/metadata/cbnt/bootpolicy/bpmh.go b/pkg/intel/metadata/cbnt/bootpolicy/bpmh.go index 454fd971..b66f3db8 100644 --- a/pkg/intel/metadata/cbnt/bootpolicy/bpmh.go +++ b/pkg/intel/metadata/cbnt/bootpolicy/bpmh.go @@ -68,6 +68,7 @@ type BPMHCBnT struct { NEMDataStack Size4K `json:"bpmhNEMStackSize"` } +// Layout returns the structure's layout descriptor func (s *BPMHCBnT) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -122,6 +123,7 @@ func (s *BPMHCBnT) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *BPMHCBnT) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -131,6 +133,7 @@ func (s *BPMHCBnT) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *BPMHCBnT) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { @@ -236,6 +239,7 @@ type BPMHBG struct { NEMDataStack Size4K `json:"bpmhNEMStackSize"` } +// Layout returns the structure's layout descriptor func (s *BPMHBG) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -290,6 +294,7 @@ func (s *BPMHBG) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *BPMHBG) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -299,6 +304,7 @@ func (s *BPMHBG) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *BPMHBG) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { diff --git a/pkg/intel/metadata/cbnt/bootpolicy/manifest.go b/pkg/intel/metadata/cbnt/bootpolicy/manifest.go index 9506fca7..3a1f88e7 100644 --- a/pkg/intel/metadata/cbnt/bootpolicy/manifest.go +++ b/pkg/intel/metadata/cbnt/bootpolicy/manifest.go @@ -71,6 +71,7 @@ type ManifestBG struct { PMSE Signature `json:"bpmSignature"` } +// MarshalJSON implements json.Marshaler to serialize the interface-typed fields. func (s ManifestBG) MarshalJSON() ([]byte, error) { type signatureJSON struct { StructInfoID cbnt.StructureID `json:"StructInfoID"` @@ -104,6 +105,8 @@ func (s ManifestBG) MarshalJSON() ([]byte, error) { return json.Marshal(out) } +// UnmarshalJSON implements json.Unmarshaler to deserialize the +// interface-typed fields. func (s *ManifestBG) UnmarshalJSON(data []byte) error { type signatureJSON struct { StructInfoID cbnt.StructureID `json:"StructInfoID"` @@ -174,6 +177,7 @@ type ManifestCBnT struct { PMSE Signature `json:"bpmSignature"` } +// MarshalJSON implements json.Marshaler to serialize the interface-typed fields. func (s ManifestCBnT) MarshalJSON() ([]byte, error) { type signatureJSON struct { StructInfoID cbnt.StructureID `json:"StructInfoID"` @@ -217,6 +221,8 @@ func (s ManifestCBnT) MarshalJSON() ([]byte, error) { return json.Marshal(out) } +// UnmarshalJSON implements json.Unmarshaler to deserialize the +// interface-typed fields. func (s *ManifestCBnT) UnmarshalJSON(data []byte) error { type signatureJSON struct { StructInfoID cbnt.StructureID `json:"StructInfoID"` @@ -320,6 +326,7 @@ func (s *ManifestBG) Validate() error { return nil } +// Layout returns the structure's layout descriptor func (s *ManifestBG) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -380,6 +387,7 @@ func (s *ManifestBG) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *ManifestBG) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -388,6 +396,7 @@ func (s *ManifestBG) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *ManifestBG) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { @@ -484,19 +493,25 @@ func (s *ManifestBG) ReadFrom(r io.Reader) (int64, error) { } +// RehashRecursive calls Rehash (see below) recursively. func (s *ManifestBG) RehashRecursive() { s.Rehash() } +// Rehash sets values which are calculated automatically depending on the rest +// data. It is usually about the total size field of an element. func (s *ManifestBG) Rehash() { s.BPMHBG = s.rehashedBPMH() } +// WriteTo writes the Manifest into 'w' in format defined in +// the document #575623. func (s *ManifestBG) WriteTo(w io.Writer) (int64, error) { s.Rehash() return s.Common.WriteTo(w, s) } +// Size returns the total size of the manifest func (s *ManifestBG) TotalSize() uint64 { if s == nil { return 0 @@ -533,18 +548,28 @@ func (s *ManifestBG) PrettyString(depth uint, withHeader bool, opts ...pretty.Op return strings.Join(lines, "\n") } +// StructInfo just returns StructInfo. func (s *ManifestBG) StructInfo() cbnt.StructInfo { return s.StructInfoBG } +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). func (s *ManifestBG) GetStructInfo() cbnt.StructInfo { return s.StructInfoBG } +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). func (s *ManifestBG) SetStructInfo(newStructInfo cbnt.StructInfo) { s.StructInfoBG = newStructInfo.(cbnt.StructInfoBG) } +// ValidateIBB returns an error if IBB segments does not match the signature func (s *ManifestBG) ValidateIBB(firmware uefi.Firmware) error { if s.SE[0].Digest.TotalSize() == 0 { return fmt.Errorf("no IBB hashes") @@ -584,6 +609,7 @@ func (s *ManifestBG) rehashedBPMH() BPMHBG { return s.BPMHBG } +// Print prints the Manifest func (s ManifestBG) Print() { fmt.Printf("%v", s.BPMHBG.PrettyString(1, true)) for _, item := range s.SE { @@ -604,6 +630,9 @@ func (s ManifestBG) Print() { } } +// fieldIndexByStructID returns the position index within +// structure Manifest of the field by its StructureID +// (see document #575623, an example of StructureID value is "__KEYM__"). func (ManifestCBnT) fieldIndexByStructID(structID string) int { switch structID { case StructureIDBPMH: @@ -625,6 +654,8 @@ func (ManifestCBnT) fieldIndexByStructID(structID string) int { return -1 } +// fieldNameByIndex returns the name of the field by its position number +// within structure Manifest. func (ManifestCBnT) fieldNameByIndex(fieldIndex int) string { switch fieldIndex { case 0: @@ -667,6 +698,7 @@ func (s *ManifestCBnT) Validate() error { return nil } +// Layout returns the structure's layout descriptor func (s *ManifestCBnT) Layout() []cbnt.LayoutField { // All fields marked with omitempty have to be checked for being // empty in the clousure for Value. Otherwise we risk some nasty errors @@ -781,6 +813,7 @@ func (s *ManifestCBnT) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *ManifestCBnT) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -790,6 +823,7 @@ func (s *ManifestCBnT) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *ManifestCBnT) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { @@ -914,6 +948,7 @@ func (s *ManifestCBnT) ReadFrom(r io.Reader) (int64, error) { } } +// RehashRecursive calls Rehash (see below) recursively. func (s *ManifestCBnT) RehashRecursive() { s.BPMHCBnT.Rehash() for idx := range s.SE { @@ -934,15 +969,20 @@ func (s *ManifestCBnT) RehashRecursive() { s.Rehash() } +// Rehash sets values which are calculated automatically depending on the rest +// data. It is usually about the total size field of an element. func (s *ManifestCBnT) Rehash() { s.BPMHCBnT = s.rehashedBPMH() } +// WriteTo writes the Manifest into 'w' in format defined in +// the document #575623. func (s *ManifestCBnT) WriteTo(w io.Writer) (int64, error) { s.Rehash() return s.Common.WriteTo(w, s) } +// Size returns the total size of the manifest func (s *ManifestCBnT) TotalSize() uint64 { if s == nil { return 0 @@ -985,14 +1025,23 @@ func (s *ManifestCBnT) PrettyString(depth uint, withHeader bool, opts ...pretty. return strings.Join(lines, "\n") } +// StructInfo just returns StructInfo. func (s *ManifestCBnT) StructInfo() cbnt.StructInfo { return s.StructInfoCBNT } +// GetStructInfo returns current value of StructInfo of the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). func (s *ManifestCBnT) GetStructInfo() cbnt.StructInfo { return s.StructInfoCBNT } +// SetStructInfo sets new value of StructInfo to the structure. +// +// StructInfo is a set of standard fields with presented in any element +// ("element" in terms of document #575623). func (s *ManifestCBnT) SetStructInfo(newStructInfo cbnt.StructInfo) { s.StructInfoCBNT = newStructInfo.(cbnt.StructInfoCBNT) } @@ -1056,6 +1105,7 @@ func CalculateOffsetFromPhysAddr(physAddr uint64, imageSize uint64) uint64 { return physAddr - startAddr } +// FlashSizeIFD returns the size of the BIOS flash area calculated from IFD entries. func FlashSizeIFD(buf []byte) (uint64, error) { if uint64(len(buf)) < uefi.FlashDescriptorLength { return 0, fmt.Errorf("buffer too small for flash descriptior: %d", len(buf)) @@ -1093,6 +1143,7 @@ func (s *ManifestCBnT) rehashedBPMH() BPMHCBnT { return bpmh } +// Print prints the Manifest func (s ManifestCBnT) Print() { fmt.Printf("%v", s.BPMHCBnT.PrettyString(1, true)) for _, item := range s.SE { diff --git a/pkg/intel/metadata/cbnt/bootpolicy/pcd.go b/pkg/intel/metadata/cbnt/bootpolicy/pcd.go index 3ab32de3..008ed8b5 100644 --- a/pkg/intel/metadata/cbnt/bootpolicy/pcd.go +++ b/pkg/intel/metadata/cbnt/bootpolicy/pcd.go @@ -56,6 +56,7 @@ func (s *PCD) Validate() error { return nil } +// Layout returns the structure's layout descriptor func (s *PCD) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -111,6 +112,7 @@ func (s *PCD) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *PCD) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -120,6 +122,7 @@ func (s *PCD) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *PCD) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { @@ -281,6 +284,7 @@ func (s *PDRS) Validate() error { return nil } +// Layout returns the structure's layout descriptor func (s *PDRS) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -305,6 +309,7 @@ func (s *PDRS) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *PDRS) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -314,6 +319,7 @@ func (s *PDRS) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *PDRS) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { @@ -418,6 +424,7 @@ func (s *CNBS) Validate() error { return nil } +// Layout returns the structure's layout descriptor func (s *CNBS) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -437,6 +444,7 @@ func (s *CNBS) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *CNBS) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -446,6 +454,7 @@ func (s *CNBS) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *CNBS) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { diff --git a/pkg/intel/metadata/cbnt/bootpolicy/pm.go b/pkg/intel/metadata/cbnt/bootpolicy/pm.go index d7a27940..b6d7d307 100644 --- a/pkg/intel/metadata/cbnt/bootpolicy/pm.go +++ b/pkg/intel/metadata/cbnt/bootpolicy/pm.go @@ -58,6 +58,7 @@ func (s *PMCBnT) Validate() error { return nil } +// Layout returns the structure's layout descriptor func (s *PMCBnT) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -91,6 +92,7 @@ func (s *PMCBnT) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *PMCBnT) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -100,6 +102,7 @@ func (s *PMCBnT) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *PMCBnT) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { @@ -181,6 +184,7 @@ type PMBG struct { Data []byte `json:"pcData"` } +// Layout returns the structure's layout descriptor func (s *PMBG) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -207,6 +211,7 @@ func (s *PMBG) Layout() []cbnt.LayoutField { } } +// Validate implements Structure.Validate() func (s *PMBG) Validate() error { // dummy return nil @@ -251,6 +256,7 @@ func (s *PMBG) WriteTo(w io.Writer) (int64, error) { return s.Common.WriteTo(w, s) } +// SizeOf returns the size of the structure's field of a given id. func (s *PMBG) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -260,6 +266,7 @@ func (s *PMBG) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *PMBG) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { diff --git a/pkg/intel/metadata/cbnt/bootpolicy/se.go b/pkg/intel/metadata/cbnt/bootpolicy/se.go index 2863f57b..351ef37f 100644 --- a/pkg/intel/metadata/cbnt/bootpolicy/se.go +++ b/pkg/intel/metadata/cbnt/bootpolicy/se.go @@ -44,6 +44,7 @@ func (s *IBBSegment) Validate() error { return nil } +// Layout returns the structure's layout descriptor func (s *IBBSegment) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -77,6 +78,7 @@ func (s *IBBSegment) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *IBBSegment) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -86,6 +88,7 @@ func (s *IBBSegment) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *IBBSegment) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { @@ -250,6 +253,7 @@ func (s *SECBnT) Validate() error { return nil } +// Layout returns the structure's layout descriptor func (s *SECBnT) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -418,6 +422,7 @@ func (s *SECBnT) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *SECBnT) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -427,6 +432,7 @@ func (s *SECBnT) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *SECBnT) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { @@ -549,6 +555,7 @@ type SEBG struct { IBBSegments []IBBSegment `countType:"uint8" json:"seIBBSegments,omitempty"` } +// Layout returns the structure's layout descriptor func (s *SEBG) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -734,6 +741,7 @@ func (s *SEBG) WriteTo(w io.Writer) (int64, error) { return s.Common.WriteTo(w, s) } +// SizeOf returns the size of the structure's field of a given id. func (s *SEBG) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -743,6 +751,7 @@ func (s *SEBG) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *SEBG) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { diff --git a/pkg/intel/metadata/cbnt/bootpolicy/signature.go b/pkg/intel/metadata/cbnt/bootpolicy/signature.go index 65997a47..6085a0a1 100644 --- a/pkg/intel/metadata/cbnt/bootpolicy/signature.go +++ b/pkg/intel/metadata/cbnt/bootpolicy/signature.go @@ -54,6 +54,7 @@ func (s *Signature) Validate() error { return nil } +// Layout returns the structure's layout descriptor func (s *Signature) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -73,6 +74,7 @@ func (s *Signature) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *Signature) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -82,6 +84,7 @@ func (s *Signature) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *Signature) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { diff --git a/pkg/intel/metadata/cbnt/bootpolicy/txt.go b/pkg/intel/metadata/cbnt/bootpolicy/txt.go index a8786158..5cf5ebdf 100644 --- a/pkg/intel/metadata/cbnt/bootpolicy/txt.go +++ b/pkg/intel/metadata/cbnt/bootpolicy/txt.go @@ -101,6 +101,7 @@ func (s *TXT) Validate() error { return nil } +// Layout returns the structure's layout descriptor func (s *TXT) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -211,6 +212,7 @@ func (s *TXT) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *TXT) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -220,6 +222,7 @@ func (s *TXT) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *TXT) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { diff --git a/pkg/intel/metadata/cbnt/chipset_ac_module_information.go b/pkg/intel/metadata/cbnt/chipset_ac_module_information.go index 8eade88b..ad942111 100644 --- a/pkg/intel/metadata/cbnt/chipset_ac_module_information.go +++ b/pkg/intel/metadata/cbnt/chipset_ac_module_information.go @@ -82,6 +82,7 @@ func (s *ChipsetACModuleInformation) WriteTo(w io.Writer) (int64, error) { return s.Common.WriteTo(w, s) } +// Layout returns the structure's layout descriptor func (s *ChipsetACModuleInformation) Layout() []LayoutField { return []LayoutField{ { @@ -171,6 +172,7 @@ func (s *ChipsetACModuleInformation) Layout() []LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *ChipsetACModuleInformation) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -180,6 +182,7 @@ func (s *ChipsetACModuleInformation) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *ChipsetACModuleInformation) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { @@ -189,6 +192,7 @@ func (s *ChipsetACModuleInformation) OffsetOf(id int) (uint64, error) { return ret, nil } +// Size returns the total size of the manifest func (s *ChipsetACModuleInformation) TotalSize() uint64 { if s == nil { return 0 diff --git a/pkg/intel/metadata/cbnt/common.go b/pkg/intel/metadata/cbnt/common.go index 17315771..d7ed6585 100644 --- a/pkg/intel/metadata/cbnt/common.go +++ b/pkg/intel/metadata/cbnt/common.go @@ -26,6 +26,8 @@ type LayoutProvider interface { // All types implementing Structure should embed it. type Common struct{} +// TotalSize returns the sum of size of all fields from a provided Layout +// descriptor. func (Common) TotalSize(p LayoutProvider) uint64 { var total uint64 for _, f := range p.Layout() { @@ -34,6 +36,8 @@ func (Common) TotalSize(p LayoutProvider) uint64 { return total } +// SizeOf returns the size of the field from a provided Layout descriptor, +// of a given id. func (Common) SizeOf(p LayoutProvider, id int) (uint64, error) { for _, f := range p.Layout() { if f.ID == id { @@ -44,6 +48,8 @@ func (Common) SizeOf(p LayoutProvider, id int) (uint64, error) { return 0, fmt.Errorf("has no field of ID %d", id) } +// OffsetOf returns the size of the field from a provided Layout descriptor, +// of a given id. func (Common) OffsetOf(p LayoutProvider, id int) (uint64, error) { var offset uint64 @@ -57,6 +63,8 @@ func (Common) OffsetOf(p LayoutProvider, id int) (uint64, error) { return 0, fmt.Errorf("has no field of ID %d", id) } +// PrettyString returns the content of the provided Layout descriptor in an +// easy-to-read format. func (Common) PrettyString(depth uint, withHeader bool, p LayoutProvider, structName string, opts ...pretty.Option) string { var lines []string @@ -80,6 +88,8 @@ func (Common) PrettyString(depth uint, withHeader bool, p LayoutProvider, struct return strings.Join(lines, "\n") } +// ReadFrom reads the 'r' and fills the fields of the provided Layout +// descriptor in format defined in the document #575623. func (Common) ReadFrom(r io.Reader, p LayoutProvider) (int64, error) { totalN := int64(0) @@ -136,6 +146,8 @@ func (Common) ReadFrom(r io.Reader, p LayoutProvider) (int64, error) { return totalN, nil } +// WriteTo writes the fields from the provided Layout descriptor into 'w' +// in format defined in the document #575623. func (Common) WriteTo(w io.Writer, p LayoutProvider) (int64, error) { totalN := int64(0) diff --git a/pkg/intel/metadata/cbnt/hash.go b/pkg/intel/metadata/cbnt/hash.go index eae9844a..b6ebd94e 100644 --- a/pkg/intel/metadata/cbnt/hash.go +++ b/pkg/intel/metadata/cbnt/hash.go @@ -67,6 +67,7 @@ func (s *HashList) WriteTo(w io.Writer) (int64, error) { return s.Common.WriteTo(w, s) } +// Layout returns the structure's layout descriptor func (s *HashList) Layout() []LayoutField { return []LayoutField{ { @@ -129,6 +130,7 @@ func (s *HashList) Layout() []LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *HashList) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -139,6 +141,7 @@ func (s *HashList) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *HashList) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { @@ -206,6 +209,7 @@ func (s *HashStructure) WriteTo(w io.Writer) (int64, error) { return s.Common.WriteTo(w, s) } +// Layout returns the structure's layout descriptor func (s *HashStructure) Layout() []LayoutField { return []LayoutField{ { @@ -231,6 +235,7 @@ func (s *HashStructure) Layout() []LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *HashStructure) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -241,6 +246,7 @@ func (s *HashStructure) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *HashStructure) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { @@ -250,6 +256,7 @@ func (s *HashStructure) OffsetOf(id int) (uint64, error) { return ret, nil } +// Size returns the total size of the manifest func (s *HashStructure) TotalSize() uint64 { if s == nil { return 0 @@ -310,6 +317,7 @@ func (s *HashStructureFill) WriteTo(w io.Writer) (int64, error) { return s.Common.WriteTo(w, s) } +// Layout returns the structure's layout descriptor func (s *HashStructureFill) Layout() []LayoutField { return []LayoutField{ { @@ -329,6 +337,7 @@ func (s *HashStructureFill) Layout() []LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *HashStructureFill) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -338,6 +347,7 @@ func (s *HashStructureFill) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *HashStructureFill) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { @@ -347,6 +357,7 @@ func (s *HashStructureFill) OffsetOf(id int) (uint64, error) { return ret, nil } +// Size returns the total size of the manifest func (s *HashStructureFill) TotalSize() uint64 { if s == nil { return 0 diff --git a/pkg/intel/metadata/cbnt/key.go b/pkg/intel/metadata/cbnt/key.go index 464ff88c..f3fcacf1 100644 --- a/pkg/intel/metadata/cbnt/key.go +++ b/pkg/intel/metadata/cbnt/key.go @@ -219,6 +219,7 @@ func NewKey() *Key { return s } +// Layout returns the structure's layout descriptor func (k *Key) Layout() []LayoutField { return []LayoutField{ { @@ -279,6 +280,7 @@ func (k *Key) WriteTo(w io.Writer) (int64, error) { return k.Common.WriteTo(w, k) } +// SizeOf returns the size of the structure's field of a given id. func (k *Key) SizeOf(id int) (uint64, error) { ret, err := k.Common.SizeOf(k, id) if err != nil { @@ -289,6 +291,7 @@ func (k *Key) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (k *Key) OffsetOf(id int) (uint64, error) { ret, err := k.Common.OffsetOf(k, id) if err != nil { diff --git a/pkg/intel/metadata/cbnt/key_signature.go b/pkg/intel/metadata/cbnt/key_signature.go index 01b9b6aa..8a643647 100644 --- a/pkg/intel/metadata/cbnt/key_signature.go +++ b/pkg/intel/metadata/cbnt/key_signature.go @@ -124,6 +124,7 @@ func (s *KeySignature) WriteTo(w io.Writer) (int64, error) { return s.Common.WriteTo(w, s) } +// Layout returns the structure's layout descriptor func (s *KeySignature) Layout() []LayoutField { return []LayoutField{ { @@ -150,6 +151,7 @@ func (s *KeySignature) Layout() []LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *KeySignature) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -159,6 +161,7 @@ func (s *KeySignature) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *KeySignature) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { diff --git a/pkg/intel/metadata/cbnt/keymanifest/hash.go b/pkg/intel/metadata/cbnt/keymanifest/hash.go index 92628020..dd5e620a 100644 --- a/pkg/intel/metadata/cbnt/keymanifest/hash.go +++ b/pkg/intel/metadata/cbnt/keymanifest/hash.go @@ -103,20 +103,12 @@ func (u *Usage) Set(f Usage, v bool) { // all default values set. func NewHash() *Hash { s := &Hash{} - // Recursively initializing a child structure: - // s.Digest = *cbnt.NewHashStructure() - // s.Rehash() return s } // Validate (recursively) checks the structure if there are any unexpected // values. It returns an error if so. func (s *Hash) Validate() error { - // Recursively validating a child structure: - // if err := s.Digest.Validate(); err != nil { - // return fmt.Errorf("error on field 'Digest': %w", err) - // } - return nil } @@ -155,6 +147,7 @@ func (s *Hash) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *Hash) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -165,6 +158,7 @@ func (s *Hash) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *Hash) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { diff --git a/pkg/intel/metadata/cbnt/keymanifest/manifest_bg.go b/pkg/intel/metadata/cbnt/keymanifest/manifest_bg.go index adb57065..bc3a7b86 100644 --- a/pkg/intel/metadata/cbnt/keymanifest/manifest_bg.go +++ b/pkg/intel/metadata/cbnt/keymanifest/manifest_bg.go @@ -24,6 +24,7 @@ type BGManifest struct { KeyAndSignature cbnt.KeySignature `json:"kmKeySignature"` } +// Setter for the Key signature. func (m *BGManifest) SetSignature( algo cbnt.Algorithm, hashAlgo cbnt.Algorithm, @@ -38,6 +39,7 @@ func (m *BGManifest) SetSignature( return nil } +// ValidateBPMKey returns an error if BPKey does not match Key Signature from BPM. func (m *BGManifest) ValidateBPMKey(bpmKS cbnt.KeySignature) error { h, err := m.BPKey.HashAlg.Hash() if err != nil { @@ -107,6 +109,7 @@ func (m *BGManifest) WriteTo(w io.Writer) (int64, error) { return m.Common.WriteTo(w, m) } +// Layout returns the structure's layout descriptor func (m *BGManifest) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -154,6 +157,7 @@ func (m *BGManifest) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (m *BGManifest) SizeOf(id int) (uint64, error) { ret, err := m.Common.SizeOf(m, id) if err != nil { @@ -163,6 +167,7 @@ func (m *BGManifest) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (m *BGManifest) OffsetOf(id int) (uint64, error) { ret, err := m.Common.OffsetOf(m, id) if err != nil { @@ -186,6 +191,7 @@ func (m *BGManifest) PrettyString(depth uint, withHeader bool, opts ...pretty.Op return m.Common.PrettyString(depth, withHeader, m, "BG Key Manifest", opts...) } +// Print prints the Key Manifest func (m *BGManifest) Print() { if len(m.KeyAndSignature.Signature.Data) < 1 { fmt.Printf("%v\n", m.PrettyString(1, true, pretty.OptionOmitKeySignature(true))) diff --git a/pkg/intel/metadata/cbnt/keymanifest/manifest_cbnt.go b/pkg/intel/metadata/cbnt/keymanifest/manifest_cbnt.go index 05ebc345..ad3155fd 100644 --- a/pkg/intel/metadata/cbnt/keymanifest/manifest_cbnt.go +++ b/pkg/intel/metadata/cbnt/keymanifest/manifest_cbnt.go @@ -61,6 +61,7 @@ func (l *HashList) Structures() []cbnt.Structure { return out } +// Setter for the Key Signature. func (m *CBnTManifest) SetSignature( algo cbnt.Algorithm, hashAlgo cbnt.Algorithm, @@ -76,6 +77,8 @@ func (m *CBnTManifest) SetSignature( return nil } +// ValidateBPMKey returns an error if any of the keys in BPM does not match +// the ones in KM. func (m *CBnTManifest) ValidateBPMKey(bpmKS cbnt.KeySignature) error { hashCount := 0 for _, hashEntry := range m.Hash { @@ -115,6 +118,7 @@ func (m *CBnTManifest) ValidateBPMKey(bpmKS cbnt.KeySignature) error { return nil } +// Validate (recursively) checks the structure if there are any unexpected values. func (m *CBnTManifest) Validate() error { v, err := m.OffsetOf(8) if err != nil { @@ -178,6 +182,7 @@ func (m *CBnTManifest) WriteTo(w io.Writer) (int64, error) { return m.Common.WriteTo(w, m) } +// Layout returns the structure's layout descriptor func (m *CBnTManifest) Layout() []cbnt.LayoutField { return []cbnt.LayoutField{ { @@ -286,6 +291,7 @@ func (m *CBnTManifest) Layout() []cbnt.LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (m *CBnTManifest) SizeOf(id int) (uint64, error) { ret, err := m.Common.SizeOf(m, id) if err != nil { @@ -295,6 +301,7 @@ func (m *CBnTManifest) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (m *CBnTManifest) OffsetOf(id int) (uint64, error) { ret, err := m.Common.OffsetOf(m, id) if err != nil { diff --git a/pkg/intel/metadata/cbnt/signature.go b/pkg/intel/metadata/cbnt/signature.go index 055df4de..b5fbb6e9 100644 --- a/pkg/intel/metadata/cbnt/signature.go +++ b/pkg/intel/metadata/cbnt/signature.go @@ -61,6 +61,7 @@ func (s *Signature) WriteTo(w io.Writer) (int64, error) { return s.Common.WriteTo(w, s) } +// Layout returns the structure's layout descriptor func (s *Signature) Layout() []LayoutField { return []LayoutField{ { @@ -101,6 +102,7 @@ func (s *Signature) Layout() []LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *Signature) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -110,6 +112,7 @@ func (s *Signature) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *Signature) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { diff --git a/pkg/intel/metadata/cbnt/structure.go b/pkg/intel/metadata/cbnt/structure.go index 93fbf623..94d206c2 100644 --- a/pkg/intel/metadata/cbnt/structure.go +++ b/pkg/intel/metadata/cbnt/structure.go @@ -33,6 +33,7 @@ func (s StructInfoCBNT) ReadFrom(r io.Reader) (int64, error) { return totalN, nil } +// Validate (recursively) checks the structure if there are any unexpected values. func (s StructInfoCBNT) Validate() error { // ID, version and element size might differ, only thing that we can always validate is // Variable0. @@ -48,6 +49,7 @@ func (s StructInfoCBNT) WriteTo(w io.Writer) (int64, error) { return s.Common.WriteTo(w, s) } +// Layout returns the structure's layout descriptor func (s StructInfoCBNT) Layout() []LayoutField { return []LayoutField{ { @@ -81,6 +83,7 @@ func (s StructInfoCBNT) Layout() []LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s StructInfoCBNT) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -90,6 +93,7 @@ func (s StructInfoCBNT) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s StructInfoCBNT) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { diff --git a/pkg/intel/metadata/cbnt/structure_bg.go b/pkg/intel/metadata/cbnt/structure_bg.go index 74389276..6d15956b 100644 --- a/pkg/intel/metadata/cbnt/structure_bg.go +++ b/pkg/intel/metadata/cbnt/structure_bg.go @@ -27,7 +27,9 @@ func (s StructInfoBG) ReadFrom(r io.Reader) (int64, error) { return totalN, nil } +// Validate (recursively) checks the structure if there are any unexpected values. func (s StructInfoBG) Validate() error { + // dummy return nil } @@ -37,6 +39,7 @@ func (s StructInfoBG) WriteTo(w io.Writer) (int64, error) { return s.Common.WriteTo(w, s) } +// Layout returns the structure's layout descriptor func (s StructInfoBG) Layout() []LayoutField { return []LayoutField{ { @@ -56,6 +59,7 @@ func (s StructInfoBG) Layout() []LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s StructInfoBG) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -65,6 +69,7 @@ func (s StructInfoBG) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s StructInfoBG) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { diff --git a/pkg/intel/metadata/cbnt/tpm_info_list.go b/pkg/intel/metadata/cbnt/tpm_info_list.go index 83a5f311..be64d35e 100644 --- a/pkg/intel/metadata/cbnt/tpm_info_list.go +++ b/pkg/intel/metadata/cbnt/tpm_info_list.go @@ -43,6 +43,7 @@ func (s *TPMInfoList) WriteTo(w io.Writer) (int64, error) { return s.Common.WriteTo(w, s) } +// Layout returns the structure's layout descriptor. func (s *TPMInfoList) Layout() []LayoutField { return []LayoutField{ { @@ -103,6 +104,7 @@ func (s *TPMInfoList) Layout() []LayoutField { } } +// SizeOf returns the size of the structure's field of a given id. func (s *TPMInfoList) SizeOf(id int) (uint64, error) { ret, err := s.Common.SizeOf(s, id) if err != nil { @@ -112,6 +114,7 @@ func (s *TPMInfoList) SizeOf(id int) (uint64, error) { return ret, nil } +// OffsetOf returns the offset of the structure's field of a given id. func (s *TPMInfoList) OffsetOf(id int) (uint64, error) { ret, err := s.Common.OffsetOf(s, id) if err != nil { @@ -121,6 +124,7 @@ func (s *TPMInfoList) OffsetOf(id int) (uint64, error) { return ret, nil } +// Size returns the total size of the manifest func (s *TPMInfoList) TotalSize() uint64 { if s == nil { return 0 diff --git a/pkg/intel/metadata/cbnt/types.go b/pkg/intel/metadata/cbnt/types.go index 003f236f..0882e537 100644 --- a/pkg/intel/metadata/cbnt/types.go +++ b/pkg/intel/metadata/cbnt/types.go @@ -22,7 +22,7 @@ type ( Size func() uint64 Value func() any Type ManifestFieldType - // optional list reader onluy to be used for types that contain + // optional list reader, only to be used for types that contain // ManifestFieldList ReadList func(r io.Reader) (int64, error) // optional list writer to be used for types that contain