github.com/transparency-dev/armored-witness-os@v0.1.3-0.20240514084412-27eef7325168/cmd/witnessctl/witnessctl.go (about) 1 // Copyright 2022 The Armored Witness OS 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 //go:build !tamago 16 // +build !tamago 17 18 package main 19 20 import ( 21 "errors" 22 "flag" 23 "log" 24 "os" 25 ) 26 27 const warning = ` 28 ████████████████████████████████████████████████████████████████████████████████ 29 30 ** WARNING ** 31 32 Enabling NXP HABv4 secure boot is an irreversible action that permanently fuses 33 verification key hashes on the device. 34 35 Any errors in the process or loss of the signing PKI will result in a bricked 36 device incapable of executing unsigned code. This is a security feature, not a 37 bug. 38 39 The use of this tool is therefore **at your own risk**. 40 41 ████████████████████████████████████████████████████████████████████████████████ 42 ` 43 44 var ( 45 // knownSRKHashes maps known SRK hash values to the release environment they came from. 46 // These values MUST NOT be changed unless you really know what you're doing! 47 knownSRKHashes = map[string]string{ 48 // CI: From https://github.com/transparency-dev/armored-witness-os/blob/main/release/cloudbuild_ci.yaml#L188-L191C18 49 "b8ba457320663bf006accd3c57e06720e63b21ce5351cb91b4650690bb08d85a": "CI", 50 } 51 ) 52 53 type Config struct { 54 devs []Device 55 56 hidPath string 57 58 status bool 59 consoleLogs bool 60 crashLogs bool 61 hab bool 62 63 dhcp bool 64 ip string 65 gw string 66 mask string 67 dns string 68 ntp string 69 } 70 71 var conf *Config 72 73 func init() { 74 log.SetFlags(0) 75 log.SetOutput(os.Stdout) 76 77 conf = &Config{} 78 79 flag.StringVar(&conf.hidPath, "d", "", "HID path of witness device to act upon (use -s to list devices)") 80 flag.BoolVar(&conf.status, "s", false, "get witness status") 81 flag.BoolVar(&conf.consoleLogs, "l", false, "get witness console/debug logs") 82 flag.BoolVar(&conf.crashLogs, "L", false, "get crash logs from most recent witness failure") 83 flag.BoolVar(&conf.hab, "H", false, "set HAB fuses") 84 flag.BoolVar(&conf.dhcp, "A", true, "enable DHCP") 85 flag.StringVar(&conf.ip, "a", "10.0.0.1", "set IP address") 86 flag.StringVar(&conf.mask, "m", "255.255.255.0", "set Netmask") 87 flag.StringVar(&conf.gw, "g", "10.0.0.2", "set Gateway") 88 flag.StringVar(&conf.dns, "r", "8.8.8.8:53", "set DNS resolver") 89 flag.StringVar(&conf.ntp, "n", "time.google.com", "set NTP server") 90 } 91 92 func (c *Config) detect() error { 93 devs, err := detect() 94 if err != nil { 95 return err 96 } 97 if len(devs) == 0 { 98 return errors.New("no devices found") 99 } 100 // If the user specified a device in particular, limit to just that one: 101 if len(c.hidPath) > 0 { 102 for _, d := range devs { 103 if d.usb.Path == conf.hidPath { 104 c.devs = []Device{d} 105 return nil 106 } 107 } 108 109 } 110 c.devs = devs 111 return nil 112 } 113 114 func main() { 115 defer func() { 116 if flag.NFlag() == 0 { 117 flag.PrintDefaults() 118 } 119 }() 120 121 flag.Parse() 122 123 if err := conf.detect(); err != nil { 124 log.Fatalf("detect(): %v", err) 125 } 126 127 switch { 128 case conf.hab: 129 s, err := conf.devs[0].status() 130 if err != nil { 131 log.Printf("Failed to get status on %q: %c", conf.devs[0].usb.Path, err) 132 } 133 log.Print(warning) 134 log.Print() 135 136 env, ok := knownSRKHashes[s.SRKHash] 137 if !ok { 138 log.Printf("WARNING: SRK hash '%s' is UNKNOWN!", s.SRKHash) 139 } else { 140 log.Printf("Will fuse to %s release environment (SRK Hash: %s)", env, s.SRKHash) 141 } 142 143 if confirm("Proceed?") { 144 log.Print("Asking device to fuse itself...") 145 if err := conf.devs[0].hab(); err != nil { 146 log.Fatalf("%v", err) 147 } 148 } else { 149 if err := errors.New("User cancelled"); err != nil { 150 log.Fatalf("%v", err) 151 } 152 } 153 case conf.status: 154 for _, d := range conf.devs { 155 log.Printf("👁️🗨️ @ %s", d.usb.Path) 156 s, err := d.status() 157 if err != nil { 158 log.Printf("Failed to get status on %q: %v", d.usb.Path, err) 159 } 160 log.Printf("%s\n\n", s.Print()) 161 } 162 case conf.consoleLogs: 163 for _, d := range conf.devs { 164 log.Printf("👁️🗨️ @ %s", d.usb.Path) 165 s, err := d.consoleLogs() 166 if err != nil { 167 log.Printf("Failed to get console logs on %q: %v", d.usb.Path, err) 168 } 169 log.Printf("%s\n\n", s) 170 } 171 case conf.crashLogs: 172 for _, d := range conf.devs { 173 log.Printf("👁️🗨️ @ %s", d.usb.Path) 174 s, err := d.crashLogs() 175 if err != nil { 176 log.Printf("Failed to get crash logs on %q: %v", d.usb.Path, err) 177 } 178 log.Printf("%s\n\n", s) 179 } 180 case conf.dhcp || len(conf.ip) > 0 || len(conf.gw) > 0 || len(conf.dns) > 0 || len(conf.ntp) > 0: 181 if len(conf.devs) != 1 { 182 log.Fatal("Please specify which device to configure using -d") 183 } 184 if err := conf.devs[0].cfg(conf.dhcp, conf.ip, conf.mask, conf.gw, conf.dns, conf.ntp); err != nil { 185 log.Fatalf("%v", err) 186 } 187 } 188 }