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 }