github.com/linuxboot/fiano@v1.2.0/pkg/intel/metadata/bg/bgbootpolicy/manifest.go (about) 1 // Copyright 2017-2023 the LinuxBoot Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:generate manifestcodegen 6 7 package bgbootpolicy 8 9 import ( 10 "bytes" 11 "fmt" 12 13 pkgbytes "github.com/linuxboot/fiano/pkg/bytes" 14 15 "github.com/linuxboot/fiano/pkg/intel/metadata/bg" 16 "github.com/linuxboot/fiano/pkg/uefi" 17 ) 18 19 // StructInfo is the common header of any element. 20 type StructInfo = bg.StructInfo 21 22 // PrettyString: Boot Policy Manifest 23 type Manifest struct { 24 // PrettyString: BPMH: Header 25 BPMH `rehashValue:"rehashedBPMH()" json:"bpmHeader"` 26 // PrettyString: SE: Header 27 SE []SE `json:"bpmSE"` 28 // PrettyString: PME: Platform Manufacturer 29 PME *PM `json:"bpmPME,omitempty"` 30 // PrettyString: PMSE: Signature 31 PMSE Signature `json:"bpmSignature"` 32 } 33 34 // StructInfo is the information about how to parse the structure. 35 func (bpm Manifest) StructInfo() StructInfo { 36 return bpm.BPMH.StructInfo 37 } 38 39 // ValidateIBB returns an error if IBB segments does not match the signature 40 func (bpm *Manifest) ValidateIBB(firmware uefi.Firmware) error { 41 if bpm.SE[0].Digest.TotalSize() == 0 { 42 return fmt.Errorf("no IBB hashes") 43 } 44 45 digest := bpm.SE[0].Digest 46 47 h, err := digest.HashAlg.Hash() 48 if err != nil { 49 return fmt.Errorf("invalid hash function: %v", digest.HashAlg) 50 } 51 52 for _, _range := range bpm.IBBDataRanges(uint64(len(firmware.Buf()))) { 53 if _, err := h.Write(firmware.Buf()[_range.Offset:_range.End()]); err != nil { 54 return fmt.Errorf("unable to hash: %w", err) 55 } 56 } 57 hashValue := h.Sum(nil) 58 59 if !bytes.Equal(hashValue, digest.HashBuffer) { 60 return fmt.Errorf("IBB %s hash mismatch: %X != %X", digest.HashAlg, hashValue, digest.HashBuffer) 61 } 62 63 return nil 64 } 65 66 // IBBDataRanges returns data ranges of IBB. 67 func (bpm *Manifest) IBBDataRanges(firmwareSize uint64) pkgbytes.Ranges { 68 var result pkgbytes.Ranges 69 70 for _, seg := range bpm.SE[0].IBBSegments { 71 if seg.Flags&1 == 1 { 72 continue 73 } 74 startIdx := calculateOffsetFromPhysAddr(uint64(seg.Base), firmwareSize) 75 result = append(result, pkgbytes.Range{Offset: startIdx, Length: uint64(seg.Size)}) 76 } 77 78 return result 79 } 80 81 // calculateOffsetFromPhysAddr calculates the offset within an image 82 // of the physical address (address to a region mapped from 83 // the SPI chip). 84 // 85 // Examples: 86 // 87 // calculateOffsetFromPhysAddr(0xffffffff, 0x1000) == 0xfff 88 // calculateOffsetFromPhysAddr(0xffffffc0, 0x1000) == 0xfc0 89 func calculateOffsetFromPhysAddr(physAddr uint64, imageSize uint64) uint64 { 90 const basePhysAddr = 1 << 32 // "4GiB" 91 startAddr := basePhysAddr - imageSize 92 return physAddr - startAddr 93 }