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  }