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  }