constellation/image/measured-boot/extract/extract.go

117 lines
2.6 KiB
Go

/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package extract
import (
"crypto/sha256"
"debug/pe"
"fmt"
"io"
"os/exec"
"sort"
"github.com/edgelesssys/constellation/v2/image/measured-boot/pesection"
)
// CopyFrom is a wrapper for systemd-dissect --copy-from.
func CopyFrom(dissectToolchain, image, path, output string) error {
if dissectToolchain == "" {
dissectToolchain = "systemd-dissect"
}
out, err := exec.Command(dissectToolchain, "--copy-from", image, path, output).CombinedOutput()
if err != nil {
return fmt.Errorf("failed to extract %s from %s: %v\n%s", path, image, err, out)
}
return nil
}
// PeSectionReader returns a reader for the named section of a PE file.
func PeSectionReader(peFile io.ReaderAt, section string) (io.Reader, error) {
f, err := pe.NewFile(peFile)
if err != nil {
return nil, err
}
defer f.Close()
for _, s := range f.Sections {
if s.Name == section {
return io.LimitReader(s.Open(), int64(s.VirtualSize)), nil
}
}
return nil, fmt.Errorf("section %q not found", section)
}
// PeFileSectionDigests returns the section digests of a PE file.
func PeFileSectionDigests(peFile io.ReaderAt) ([]pesection.PESection, error) {
f, err := pe.NewFile(peFile)
if err != nil {
return nil, err
}
defer f.Close()
sections := make([]pesection.PESection, len(f.Sections))
for i, section := range f.Sections {
sectionDigest := sha256.New()
sectionReader := section.Open()
_, err := io.CopyN(sectionDigest, sectionReader, int64(section.VirtualSize))
if err != nil {
return nil, err
}
sections[i].Name = section.Name
sections[i].Size = section.VirtualSize
sections[i].Digest = ([32]byte)(sectionDigest.Sum(nil))
sections[i].Measure = shouldMeasureSection(section.Name)
sections[i].MeasureOrder = sectionMeasureOrder(section.Name)
}
sort.Slice(sections, func(i, j int) bool {
if sections[i].Measure != sections[j].Measure {
return sections[i].Measure
}
if sections[i].MeasureOrder == sections[j].MeasureOrder {
return sections[i].Name < sections[j].Name
}
return sections[i].MeasureOrder < sections[j].MeasureOrder
})
return sections, nil
}
var ukiSections = []string{
".linux",
".osrel",
".cmdline",
".initrd",
".splash",
".dtb",
// uanme and sbat will be added in systemd-stub >= 254
// ".uname",
// ".sbat",
".pcrsig",
".pcrkey",
}
func shouldMeasureSection(name string) bool {
for _, section := range ukiSections {
if name == section && name != ".pcrsig" {
return true
}
}
return false
}
func sectionMeasureOrder(name string) int {
for i, section := range ukiSections {
if name == section {
return i
}
}
return -1
}