github.com/linuxboot/fiano@v1.2.0/pkg/intel/metadata/cbnt/cbntbootpolicy/manifest.go (about) 1 // Copyright 2017-2021 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 cbntbootpolicy 8 9 import ( 10 "bytes" 11 "fmt" 12 13 pkgbytes "github.com/linuxboot/fiano/pkg/bytes" 14 "github.com/linuxboot/fiano/pkg/intel/metadata/cbnt" 15 "github.com/linuxboot/fiano/pkg/uefi" 16 ) 17 18 // StructInfo is the common header of any element. 19 type StructInfo = cbnt.StructInfo 20 21 // Manifest is a boot policy manifest 22 // 23 // PrettyString: Boot Policy Manifest 24 type Manifest struct { 25 // BPMH is the header of the boot policy manifest 26 // 27 // PrettyString: BPMH: Header 28 BPMH `rehashValue:"rehashedBPMH()" json:"bpmHeader"` 29 30 SE []SE `json:"bpmSE"` 31 TXTE *TXT `json:"bpmTXTE,omitempty"` 32 Res *Reserved `json:"bpmReserved,omitempty"` 33 34 // PCDE is the platform configuration data element 35 // 36 // PrettyString: PCDE: Platform Config Data 37 PCDE *PCD `json:"bpmPCDE,omitempty"` 38 39 // PME is the platform manufacturer element 40 // 41 // PrettyString: PME: Platform Manufacturer 42 PME *PM `json:"bpmPME,omitempty"` 43 44 // PMSE is the signature element 45 // 46 // PrettyString: PMSE: Signature 47 PMSE Signature `json:"bpmSignature"` 48 } 49 50 // StructInfo is the information about how to parse the structure. 51 func (bpm Manifest) StructInfo() StructInfo { 52 return bpm.BPMH.StructInfo 53 } 54 55 // ValidateIBB returns an error if IBB segments does not match the signature 56 func (bpm *Manifest) ValidateIBB(firmware uefi.Firmware) error { 57 if len(bpm.SE[0].DigestList.List) == 0 { 58 return fmt.Errorf("no IBB hashes") 59 } 60 61 digest := bpm.SE[0].DigestList.List[0] // [0] instead of range -- is intentionally 62 63 h, err := digest.HashAlg.Hash() 64 if err != nil { 65 return fmt.Errorf("invalid hash function: %v", digest.HashAlg) 66 } 67 68 for _, _range := range bpm.IBBDataRanges(uint64(len(firmware.Buf()))) { 69 if _, err := h.Write(firmware.Buf()[_range.Offset:_range.End()]); err != nil { 70 return fmt.Errorf("unable to hash: %w", err) 71 } 72 } 73 hashValue := h.Sum(nil) 74 75 if !bytes.Equal(hashValue, digest.HashBuffer) { 76 return fmt.Errorf("IBB %s hash mismatch: %X != %X", digest.HashAlg, hashValue, digest.HashBuffer) 77 } 78 79 return nil 80 } 81 82 // IBBDataRanges returns data ranges of IBB. 83 func (bpm *Manifest) IBBDataRanges(firmwareSize uint64) pkgbytes.Ranges { 84 var result pkgbytes.Ranges 85 86 for _, seg := range bpm.SE[0].IBBSegments { 87 if seg.Flags&1 == 1 { 88 continue 89 } 90 startIdx := calculateOffsetFromPhysAddr(uint64(seg.Base), firmwareSize) 91 result = append(result, pkgbytes.Range{Offset: startIdx, Length: uint64(seg.Size)}) 92 } 93 94 return result 95 } 96 97 // calculateOffsetFromPhysAddr calculates the offset within an image 98 // of the physical address (address to a region mapped from 99 // the SPI chip). 100 // 101 // Examples: 102 // 103 // calculateOffsetFromPhysAddr(0xffffffff, 0x1000) == 0xfff 104 // calculateOffsetFromPhysAddr(0xffffffc0, 0x1000) == 0xfc0 105 func calculateOffsetFromPhysAddr(physAddr uint64, imageSize uint64) uint64 { 106 const basePhysAddr = 1 << 32 // "4GiB" 107 startAddr := basePhysAddr - imageSize 108 return physAddr - startAddr 109 }