github.com/transparency-dev/armored-witness-boot@v0.1.0/main.go (about)

     1  // Copyright 2022 The Armored Witness Boot authors. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"bytes"
    19  	"crypto/sha256"
    20  	"encoding/json"
    21  	"fmt"
    22  	"log"
    23  
    24  	usbarmory "github.com/usbarmory/tamago/board/usbarmory/mk2"
    25  	"github.com/usbarmory/tamago/dma"
    26  	"github.com/usbarmory/tamago/soc/nxp/imx6ul"
    27  	"github.com/usbarmory/tamago/soc/nxp/usdhc"
    28  	"golang.org/x/mod/sumdb/note"
    29  
    30  	"github.com/usbarmory/armory-boot/exec"
    31  
    32  	"github.com/transparency-dev/armored-witness-boot/config"
    33  	"github.com/transparency-dev/armored-witness-common/release/firmware"
    34  	"github.com/transparency-dev/armored-witness-common/release/firmware/ftlog"
    35  )
    36  
    37  const (
    38  	// Quorum defines the number of required authentication signatures for
    39  	// unikernel loading.
    40  	Quorum = 2
    41  
    42  	expectedBlockSize = 512
    43  	osConfBlock       = 0x5000
    44  )
    45  
    46  var (
    47  	Revision string
    48  	Version  string
    49  
    50  	OSLogOrigin         string
    51  	OSLogVerifier       string
    52  	OSManifestVerifiers string
    53  )
    54  
    55  // DMA region for target kernel boot
    56  var mem *dma.Region
    57  
    58  func init() {
    59  	var err error
    60  
    61  	log.SetFlags(0)
    62  
    63  	if imx6ul.Native {
    64  		imx6ul.SetARMFreq(imx6ul.Freq528)
    65  	}
    66  
    67  	dma.Init(dmaStart, dmaSize)
    68  
    69  	if mem, err = dma.NewRegion(memoryStart, memorySize, false); err != nil {
    70  		panic("could not allocate dma region")
    71  	}
    72  
    73  	mem.Reserve(memorySize, 0)
    74  }
    75  
    76  func preLaunch() {
    77  	usbarmory.LED("blue", false)
    78  	usbarmory.LED("white", false)
    79  }
    80  
    81  // read reads the firmware bundle for the trusted OS from internal storage, the
    82  // OS proof bundle is *not* verified by this function.
    83  func read(card *usdhc.USDHC) (fw *firmware.Bundle, err error) {
    84  	blockSize := card.Info().BlockSize
    85  	if blockSize != expectedBlockSize {
    86  		return nil, fmt.Errorf("h/w invariant error - got MMC blocksize %d, want %d", blockSize, expectedBlockSize)
    87  	}
    88  
    89  	buf, err := card.Read(osConfBlock*expectedBlockSize, config.MaxLength)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	conf := &config.Config{}
    95  	if err = conf.Decode(buf); err != nil {
    96  		return nil, err
    97  	}
    98  
    99  	fw = &firmware.Bundle{
   100  		Checkpoint:     conf.Bundle.Checkpoint,
   101  		Index:          conf.Bundle.LogIndex,
   102  		InclusionProof: conf.Bundle.InclusionProof,
   103  		Manifest:       conf.Bundle.Manifest,
   104  	}
   105  
   106  	fw.Firmware, err = card.Read(conf.Offset, conf.Size)
   107  	if err != nil {
   108  		return nil, fmt.Errorf("failed to read firmware: %v", err)
   109  	}
   110  
   111  	return fw, nil
   112  }
   113  
   114  func main() {
   115  	card := usbarmory.MMC
   116  
   117  	usbarmory.LED("blue", false)
   118  	usbarmory.LED("white", false)
   119  	log.Printf("armored-witness-boot: version %v", Version)
   120  
   121  	if len(OSManifestVerifiers) == 0 {
   122  		panic("armored-witness-boot: missing public keys, aborting")
   123  	}
   124  
   125  	if err := card.Detect(); err != nil {
   126  		panic(fmt.Sprintf("armored-witness-boot: boot media error, %v\n", err))
   127  	}
   128  
   129  	usbarmory.LED("blue", true)
   130  
   131  	log.Printf("armored-witness-boot: loading configuration & kernel at USDHC%d@%d\n", card.Index, config.Offset)
   132  	os, err := read(card)
   133  	if err != nil {
   134  		panic(fmt.Sprintf("armored-witness-boot: Failed to read OS firmware bundle: %v", err))
   135  	}
   136  
   137  	logVerifier, err := note.NewVerifier(OSLogVerifier)
   138  	if err != nil {
   139  		panic(fmt.Sprintf("armored-witness-boot: Invalid OSLogVerifier: %v", err))
   140  	}
   141  	log.Printf("armored-witness-boot: log verifier: %s", OSLogVerifier)
   142  
   143  	manifestVerifiers, err := manifestVerifiers()
   144  	if err != nil {
   145  		panic(fmt.Sprintf("armored-witness-boot: Invalid OSManifestVerifiers: %v", err))
   146  	}
   147  
   148  	bv := &firmware.BundleVerifier{
   149  		LogOrigin:         OSLogOrigin,
   150  		LogVerifer:        logVerifier,
   151  		ManifestVerifiers: manifestVerifiers,
   152  	}
   153  	manifest, err := bv.Verify(*os)
   154  	if err != nil {
   155  		panic(fmt.Sprintf("armored-witness-boot: kernel verification error, %v", err))
   156  	}
   157  	log.Printf("armored-witness-boot: loaded kernel version %v", manifest.Git.TagName)
   158  
   159  	// For reference, this is how we'd fall back to verifying signatures only.
   160  	if false {
   161  		n, err := note.Open(os.Manifest, note.VerifierList(manifestVerifiers...))
   162  		if err != nil {
   163  			panic(fmt.Sprintf("armored-witness-boot: kernel verification error, Open: %v", err))
   164  		}
   165  		relManifest := ftlog.FirmwareRelease{}
   166  		if err := json.Unmarshal([]byte(n.Text), &relManifest); err != nil {
   167  			panic(fmt.Sprintf("armored-witness-boot: kernel verification error, invalid manifest: %v", err))
   168  		}
   169  		if got, want := len(n.Sigs), len(manifestVerifiers); got < want {
   170  			panic(fmt.Sprintf("armored-witness-boot: kernel verification error, quorum not met (%d < %d)", got, want))
   171  		}
   172  		if fwHash, mHash := sha256.Sum256(os.Firmware), relManifest.Output.FirmwareDigestSha256; !bytes.Equal(fwHash[:], mHash) {
   173  			panic("armored-witness-boot: kernel verification error, firmware hash != manifest hash")
   174  		}
   175  	}
   176  
   177  	usbarmory.LED("white", true)
   178  
   179  	log.Print("armored-witness-boot: verified kernel")
   180  
   181  	image := &exec.ELFImage{
   182  		Region: mem,
   183  		ELF:    os.Firmware,
   184  	}
   185  
   186  	if err = image.Load(); err != nil {
   187  		panic(fmt.Sprintf("load error, %v\n", err))
   188  	}
   189  
   190  	log.Printf("armored-witness-boot: starting kernel@%.8x\n", image.Entry())
   191  
   192  	if err = image.Boot(preLaunch); err != nil {
   193  		panic(fmt.Sprintf("armored-witness-boot: load error, %v\n", err))
   194  	}
   195  }
   196  
   197  func manifestVerifiers() ([]note.Verifier, error) {
   198  	var manifestKeys []string
   199  	if err := json.Unmarshal([]byte(OSManifestVerifiers), &manifestKeys); err != nil {
   200  		return nil, fmt.Errorf("invalid OSManifestVerifiers format: %v", err)
   201  	}
   202  	manifestVerifiers := make([]note.Verifier, 0, len(manifestKeys))
   203  	for _, v := range manifestKeys {
   204  		mv, err := note.NewVerifier(v)
   205  		if err != nil {
   206  			return nil, fmt.Errorf("invalid OSManifestVerifier %q: %v", v, err)
   207  		}
   208  		manifestVerifiers = append(manifestVerifiers, mv)
   209  		log.Printf("armored-witness-boot: kernel verifier: %v", v)
   210  	}
   211  	if l := len(manifestVerifiers); l != Quorum {
   212  		return nil, fmt.Errorf("insufficient number of kernel manifest verifiers %d, need quorum of %d", l, Quorum)
   213  	}
   214  
   215  	return manifestVerifiers, nil
   216  }