github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/exp/vboot/vboot.go (about)

     1  // Copyright 2018 the u-root 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  package main
     6  
     7  import (
     8  	"crypto/sha1"
     9  	"crypto/sha256"
    10  	"flag"
    11  	"log"
    12  	"os"
    13  	"os/exec"
    14  	"syscall"
    15  
    16  	"github.com/google/go-tpm/tpm"
    17  	"golang.org/x/crypto/ed25519"
    18  )
    19  
    20  const (
    21  	tpmDevice  string = "/dev/tpm0"
    22  	mountPath  string = "/mnt/vboot"
    23  	filesystem string = "ext3"
    24  )
    25  
    26  var (
    27  	publicKey            = flag.String("pubkey", "/etc/sig.pub", "A public key which should verify the signature.")
    28  	pcr                  = flag.Uint("pcr", 12, "The pcr index used for measuring the kernel before kexec.")
    29  	bootDev              = flag.String("boot-device", "/dev/sda1", "The boot device which is used to kexec into a signed kernel.")
    30  	linuxKernel          = flag.String("kernel", "/mnt/vboot/kernel", "Kernel image file path.")
    31  	linuxKernelSignature = flag.String("kernel-sig", "/mnt/vboot/kernel.sig", "Kernel image signature file path.")
    32  	initrd               = flag.String("initrd", "/mnt/vboot/initrd", "Initrd file path.")
    33  	initrdSignature      = flag.String("initrd-sig", "/mnt/vboot/initrd.sig", "Initrd signature file path.")
    34  	debug                = flag.Bool("debug", false, "Enables debug mode.")
    35  	noTPM                = flag.Bool("no-tpm", false, "Disables tpm measuring process.")
    36  )
    37  
    38  func die(err error) {
    39  	if *debug {
    40  		panic(err)
    41  	}
    42  	if err := syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF); err != nil {
    43  		log.Fatalf("reboot err: %v", err)
    44  	}
    45  }
    46  
    47  func main() {
    48  	flag.Parse()
    49  
    50  	if err := os.MkdirAll(mountPath, os.ModePerm); err != nil {
    51  		die(err)
    52  	}
    53  
    54  	if err := syscall.Mount(*bootDev, mountPath, filesystem, syscall.MS_RDONLY, ""); err != nil {
    55  		die(err)
    56  	}
    57  
    58  	paths := []string{*publicKey, *linuxKernel, *linuxKernelSignature, *initrd, *initrdSignature}
    59  	files := make(map[string][]byte)
    60  
    61  	for _, element := range paths {
    62  		data, err := os.ReadFile(element)
    63  		if err != nil {
    64  			die(err)
    65  		} else {
    66  			files[element] = data
    67  		}
    68  	}
    69  
    70  	kernelDigest := sha256.Sum256(files[*linuxKernel])
    71  	initrdDigest := sha256.Sum256(files[*initrd])
    72  
    73  	pcrDigestKernel := sha1.Sum(files[*linuxKernel])
    74  	pcrDigestInitrd := sha1.Sum(files[*initrd])
    75  
    76  	kernelSuccess := ed25519.Verify(files[*publicKey], kernelDigest[:], files[*linuxKernelSignature])
    77  	initrdSuccess := ed25519.Verify(files[*publicKey], initrdDigest[:], files[*initrdSignature])
    78  
    79  	if !kernelSuccess || !initrdSuccess {
    80  		die(nil)
    81  	}
    82  
    83  	if !*noTPM {
    84  		rwc, err := tpm.OpenTPM(tpmDevice)
    85  		if err != nil {
    86  			die(err)
    87  		}
    88  
    89  		tpm.PcrExtend(rwc, uint32(*pcr), pcrDigestKernel)
    90  		tpm.PcrExtend(rwc, uint32(*pcr), pcrDigestInitrd)
    91  	}
    92  
    93  	binary, lookErr := exec.LookPath("kexec")
    94  	if lookErr != nil {
    95  		die(lookErr)
    96  	}
    97  
    98  	args := []string{"kexec", "-initrd", *initrd, *linuxKernel}
    99  	env := os.Environ()
   100  
   101  	if execErr := syscall.Exec(binary, args, env); execErr != nil {
   102  		die(execErr)
   103  	}
   104  }