github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/cmds/boot/stboot/main.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/sha256" 9 "encoding/hex" 10 "encoding/json" 11 "encoding/pem" 12 "flag" 13 "fmt" 14 "io/ioutil" 15 "log" 16 "net/url" 17 "path" 18 "strings" 19 "time" 20 21 "github.com/u-root/u-root/pkg/boot/stboot" 22 "github.com/u-root/u-root/pkg/recovery" 23 ) 24 25 var debug = func(string, ...interface{}) {} 26 27 var ( 28 dryRun = flag.Bool("dryrun", false, "Do everything except booting the loaded kernel") 29 doDebug = flag.Bool("d", false, "Print debug output") 30 ) 31 32 const ( 33 rootCACertPath = "/root/LetsEncrypt_Authority_X3.pem" 34 rootCertFingerprintPath = "root/signing_rootcert.fingerprint" 35 entropyAvail = "/proc/sys/kernel/random/entropy_avail" 36 interfaceUpTimeout = 6 * time.Second 37 ) 38 39 var banner = ` 40 _____ _______ _____ ____ ____________ 41 / ____|__ __| | _ \ / __ \ / __ \__ __| 42 | (___ | | | |_) | | | | | | | | | 43 \___ \ | | | _ <| | | | | | | | | 44 ____) | | | | |_) | |__| | |__| | | | 45 |_____/ |_| |____/ \____/ \____/ |_| 46 47 ` 48 49 var check = ` 50 //\\ 51 OS is // \\ 52 valid // // 53 // // 54 //\\ // // 55 // \\// // 56 \\ // 57 \\ // 58 \\ // 59 \\__// 60 ` 61 62 func main() { 63 log.SetPrefix("stboot: ") 64 65 flag.Parse() 66 if *doDebug { 67 debug = log.Printf 68 } 69 log.Print(banner) 70 71 vars, err := stboot.FindHostVarsInInitramfs() 72 if err != nil { 73 reboot("Cant find Netvars at all: %v", err) 74 } 75 76 if *doDebug { 77 str, _ := json.MarshalIndent(vars, "", " ") 78 log.Printf("Host variables: %s", str) 79 } 80 81 if vars.HostIP != "" { 82 err = configureStaticNetwork(vars) 83 } else { 84 err = configureDHCPNetwork() 85 } 86 87 if err != nil { 88 reboot("Can not set up IO: %v", err) 89 } 90 91 err = validateSystemTime() 92 if err != nil { 93 reboot("%v", err) 94 } 95 96 ballPath := path.Join("root/", stboot.BallName) 97 url, err := url.Parse(vars.BootstrapURL) 98 if err != nil { 99 reboot("Invalid bootstrap URL: %v", err) 100 } 101 url.Path = path.Join(url.Path, stboot.BallName) 102 err = downloadFromHTTPS(url.String(), ballPath) 103 if err != nil { 104 reboot("Downloading bootball failed: %v", err) 105 } 106 107 ball, err := stboot.BootBallFromArchive(ballPath) 108 if err != nil { 109 reboot("Cannot open bootball: %v", err) 110 } 111 112 fp, err := ioutil.ReadFile(rootCertFingerprintPath) 113 if err != nil { 114 reboot("Cannot read fingerprint: %v", err) 115 } 116 117 if *doDebug { 118 log.Print("Fingerprint of boot ball's root certificate:") 119 log.Print(string(fp)) 120 } 121 if !matchFingerprint(ball.RootCertPEM, string(fp)) { 122 reboot("Root certificate of boot ball does not match expacted fingerprint %v", err) 123 } 124 125 // Just choose the first Bootconfig for now 126 log.Printf("Pick the first boot configuration") 127 var index = 0 128 bc, err := ball.GetBootConfigByIndex(index) 129 if err != nil { 130 reboot("Cannot get boot configuration %d: %v", index, err) 131 } 132 133 if *doDebug { 134 str, _ := json.MarshalIndent(*bc, "", " ") 135 log.Printf("Bootconfig (ID: %s): %s", bc.ID(), str) 136 } 137 138 n, valid, err := ball.VerifyBootconfigByID(bc.ID()) 139 if err != nil { 140 reboot("Error verifying bootconfig %d: %v", index, err) 141 } 142 if valid < vars.MinimalSignaturesMatch { 143 reboot("Did not found enough valid signatures: %d found, %d valid, %d required", n, valid, vars.MinimalSignaturesMatch) 144 } 145 146 if *doDebug { 147 reboot("Signatures: %d found, %d valid, %d required", n, valid, vars.MinimalSignaturesMatch) 148 } 149 150 log.Printf("Bootconfig '%s' passed verification", bc.Name) 151 log.Print(check) 152 153 if *dryRun { 154 debug("Dryrun mode: will not boot") 155 return 156 } 157 158 log.Println("Starting up new kernel.") 159 160 if err := bc.Boot(); err != nil { 161 log.Printf("Failed to boot kernel %s: %v", bc.Kernel, err) 162 } 163 // if we reach this point, no boot configuration succeeded 164 reboot("No boot configuration succeeded") 165 } 166 167 // matchFingerprint returns true if fingerprintHex matches the SHA256 168 // hash calculated from pem decoded certPEM. 169 func matchFingerprint(certPEM []byte, fingerprintHex string) bool { 170 block, _ := pem.Decode(certPEM) 171 fp := sha256.Sum256(block.Bytes) 172 str := hex.EncodeToString(fp[:]) 173 str = strings.TrimSpace(str) 174 175 fingerprintHex = strings.TrimSpace(fingerprintHex) 176 177 return str == fingerprintHex 178 } 179 180 //reboot trys to reboot the system in an infinity loop 181 func reboot(format string, v ...interface{}) { 182 for { 183 recover := recovery.SecureRecoverer{ 184 Reboot: true, 185 Debug: true, 186 RandWait: true, 187 } 188 err := recover.Recover(fmt.Sprintf(format, v...)) 189 if err != nil { 190 continue 191 } 192 } 193 }