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