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  }