github.com/transparency-dev/armored-witness-os@v0.1.3-0.20240514084412-27eef7325168/trusted_os/rpc.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 package main 16 17 import ( 18 "crypto/aes" 19 "crypto/sha256" 20 "errors" 21 "log" 22 "net" 23 "strings" 24 25 usbarmory "github.com/usbarmory/tamago/board/usbarmory/mk2" 26 "github.com/usbarmory/tamago/soc/nxp/imx6ul" 27 "github.com/usbarmory/tamago/soc/nxp/usdhc" 28 29 "github.com/usbarmory/GoTEE/monitor" 30 31 "github.com/transparency-dev/armored-witness-os/api" 32 "github.com/transparency-dev/armored-witness-os/api/rpc" 33 "github.com/transparency-dev/armored-witness-os/internal/hab" 34 ) 35 36 // RPC represents an example receiver for user/system mode RPC over system 37 // calls. 38 type RPC struct { 39 RPMB *RPMB 40 Storage Card 41 Ctx *monitor.ExecCtx 42 Cfg []byte 43 Diversifier [32]byte 44 } 45 46 // Version receives the Trusted Applet version for verification. 47 func (r *RPC) Version(version string, _ *bool) error { 48 if !imx6ul.Native || !imx6ul.SNVS.Available() { 49 log.Print("SM skipping applet version verification") 50 return nil 51 } 52 53 log.Printf("SM applet version verification (%s)", version) 54 55 if err := r.RPMB.checkVersion(taVersionSector, version); err != nil { 56 log.Printf("SM stopping applet, %v", err) 57 r.Ctx.Stop() 58 } 59 60 return nil 61 } 62 63 // Config receives network configuration from the Trusted Applet. It also 64 // returns the previous configuration to allow the Trusted Applet to evaluate 65 // whether any updates from the control interface must be applied. 66 func (r *RPC) Config(current []byte, previous *[]byte) error { 67 if len(r.Cfg) == 0 { 68 defer func() { 69 log.Println("SM starting network") 70 netStart() 71 }() 72 } else if previous != nil { 73 *previous = r.Cfg 74 } 75 76 r.Cfg = current 77 78 return nil 79 } 80 81 // Address sets the Ethernet MAC address on LAN models. 82 func (r *RPC) Address(mac net.HardwareAddr, _ *bool) error { 83 if LAN != nil { 84 LAN.SetMAC(mac) 85 } 86 87 return nil 88 } 89 90 // Register registers the Trusted Applet event handler. 91 func (r *RPC) Register(handler rpc.Handler, _ *bool) error { 92 if handler.G == 0 || handler.P == 0 { 93 return errors.New("invalid argument") 94 } 95 96 log.Printf("SM registering applet event handler g:%#x p:%#x", handler.G, handler.P) 97 appletHandlerG = handler.G 98 appletHandlerP = handler.P 99 100 return nil 101 } 102 103 // Status returns Trusted OS status information. 104 func (r *RPC) Status(_ any, status *api.Status) error { 105 if status == nil { 106 return errors.New("invalid argument") 107 } 108 109 s := getStatus() 110 *status = *s 111 112 return nil 113 } 114 115 // SetWitnessStatus informs the OS of the witness Trusted Applet's status. 116 func (r *RPC) SetWitnessStatus(status rpc.WitnessStatus, _ *bool) error { 117 witnessStatus = &status 118 return nil 119 } 120 121 // LED receives a LED state request. 122 func (r *RPC) LED(led rpc.LEDStatus, _ *bool) error { 123 if strings.EqualFold(led.Name, "white") { 124 return errors.New("LED is secure only") 125 } 126 127 return usbarmory.LED(led.Name, led.On) 128 } 129 130 // CardInfo returns the storage media information. 131 func (r *RPC) CardInfo(_ any, info *usdhc.CardInfo) error { 132 if r.Storage == nil { 133 return errors.New("missing Storage") 134 } 135 136 *info = r.Storage.Info() 137 138 return nil 139 } 140 141 // WriteBlocks transfers full blocks of data to the storage media. 142 func (r *RPC) WriteBlocks(xfer rpc.WriteBlocks, _ *bool) error { 143 if r.Storage == nil { 144 return errors.New("missing Storage") 145 } 146 147 return r.Storage.WriteBlocks(xfer.LBA, xfer.Data) 148 } 149 150 // Read transfers data from the storage media. 151 func (r *RPC) Read(xfer rpc.Read, out *[]byte) (err error) { 152 if r.Storage == nil { 153 return errors.New("missing Storage") 154 } 155 156 *out, err = r.Storage.Read(xfer.Offset, xfer.Size) 157 158 return 159 } 160 161 // WriteRPMB performs an authenticated data transfer to the card RPMB partition 162 // sector allocated to the Trusted Applet. The input buffer can contain up to 163 // 256 bytes of data, n can be passed to retrieve the partition write counter. 164 func (r *RPC) WriteRPMB(buf []byte, n *uint32) (err error) { 165 return r.RPMB.transfer(taUserSector, buf, n, true) 166 } 167 168 // ReadRPMB performs an authenticated data transfer from the card RPMB 169 // partition sector allocated to the Trusted Applet. The input buffer can 170 // contain up to 256 bytes of data, n can be set to retrieve the partition 171 // write counter. 172 func (r *RPC) ReadRPMB(buf []byte, n *uint32) error { 173 return r.RPMB.transfer(taUserSector, buf, n, false) 174 } 175 176 // DeriveKey derives a hardware unique key in a manner equivalent to PKCS#11 177 // C_DeriveKey with CKM_AES_CBC_ENCRYPT_DATA. 178 // 179 // The diversifier is AES-CBC encrypted using the internal OTPMK key. 180 func (r *RPC) DeriveKey(diversifier [aes.BlockSize]byte, key *[sha256.Size]byte) (err error) { 181 switch { 182 case imx6ul.Native && !debug && !imx6ul.SNVS.Available(): 183 return errors.New("Weird - SNVS not available but we're not in debug?!") 184 case !imx6ul.Native && debug: 185 // we support emulation only on debug builds, use input buffer as dummy key 186 return 187 case !imx6ul.Native && !debug: 188 return errors.New("Weird - under emulation but we're not in debug?!") 189 } 190 191 switch { 192 case imx6ul.CAAM != nil: 193 div := sha256.Sum256(append(r.Diversifier[:], diversifier[:]...)) 194 err = imx6ul.CAAM.DeriveKey(div[:], key[:]) 195 case imx6ul.DCP != nil: 196 var k []byte 197 k, err = imx6ul.DCP.DeriveKey(r.Diversifier[:], diversifier[:], -1) 198 copy(key[:], k) 199 default: 200 err = errors.New("unsupported hardware") 201 } 202 203 return 204 } 205 206 // HAB activates secure boot. 207 func (r *RPC) HAB(srk []byte, _ *bool) error { 208 log.Printf("SM activating HAB") 209 return hab.Activate(srk) 210 } 211 212 // GetInstalledVersions returns the semantic versions of the OS and Applet 213 // installed on this device. These will be the same versions that are 214 // currently running. 215 func (r *RPC) GetInstalledVersions(_ *any, v *rpc.InstalledVersions) error { 216 if v != nil { 217 v.Applet = loadedAppletVersion 218 v.OS = osVersion 219 } 220 return nil 221 } 222 223 // InstallOS updates the OS to the version contained in the firmware bundle. 224 // 225 // This RPC supports sending the (potentially large) firmware image either: 226 // - In one RPC call, or 227 // - Spread over multiple RPC calls, breaking the firmware image it into multiple "chunks" of arbitrary size 228 // 229 // For a given install attempt: 230 // - An RPC call with the Sequence field set to zero indicates a fresh attempt to install firmware. 231 // - If firmware is being sent in chunks via multiple RPC calls, each subsequent RPC call should: 232 // 1. increment the Sequence field by 1 each time. 233 // 2. Pass a chunk of firmware image which is contiguous with the previous chunk. 234 // - An RPC call with the Proof set to a non-zero value indicates that all firmware chunks have been sent. 235 // This will cause the firmware update to be finalised, and if successful, this RPC will not 236 // return and the device will reboot. 237 func (r *RPC) InstallOS(b *rpc.FirmwareUpdate, _ *bool) error { 238 if b.Sequence == 0 { 239 // Dump previous partial attempts 240 osFirmwareBuffer = make([]byte, 0, len(b.Image)) 241 } 242 // Extend our firmware buffer 243 osFirmwareBuffer = append(osFirmwareBuffer, b.Image...) 244 b.Image = nil 245 246 // Return early if we're don't yet have the full image. 247 if len(b.Proof.Checkpoint) == 0 { 248 return nil 249 } 250 251 if err := updateOS(r.Storage, osFirmwareBuffer, b.Proof); err != nil { 252 return err 253 } 254 r.Ctx.Stop() 255 <-r.Ctx.Done() 256 257 return r.Reboot(nil, nil) 258 } 259 260 var osFirmwareBuffer []byte 261 262 // InstallApplet updates the Applet to the version contained in the firmware bundle. 263 // This RPC supports sending the (potentially large) firmware image either: 264 // - In one RPC call, or 265 // - Spread over multiple RPC calls, breaking the firmware image it into multiple "chunks" of arbitrary size 266 // 267 // For a given install attempt: 268 // - An RPC call with the Sequence field set to zero indicates a fresh attempt to install firmware. 269 // - If firmware is being sent in chunks via multiple RPC calls, each subsequent RPC call should: 270 // 1. increment the Sequence field by 1 each time. 271 // 2. Pass a chunk of firmware image which is contiguous with the previous chunk. 272 // - An RPC call with the Proof set to a non-zero value indicates that all firmware chunks have been sent. 273 // This will cause the firmware update to be finalised, and if successful, this RPC will not 274 // return and the device will reboot. 275 func (r *RPC) InstallApplet(b *rpc.FirmwareUpdate, _ *bool) error { 276 if b.Sequence == 0 { 277 // Dump previous partial attempts 278 appletFirmwareBuffer = make([]byte, 0, len(b.Image)) 279 } 280 // Extend our firmware buffer 281 appletFirmwareBuffer = append(appletFirmwareBuffer, b.Image...) 282 b.Image = nil 283 284 // Return early if we're don't yet have the full image. 285 if len(b.Proof.Checkpoint) == 0 { 286 return nil 287 } 288 if err := updateApplet(r.Storage, appletFirmwareBuffer, b.Proof); err != nil { 289 return err 290 } 291 r.Ctx.Stop() 292 // This must be done in a go-routine because the ExecCtx.Stop() above can only be 293 // actioned once the RPC has returned. 294 go func() { 295 <-r.Ctx.Done() 296 r.Reboot(nil, nil) 297 }() 298 299 return r.Reboot(nil, nil) 300 } 301 302 var appletFirmwareBuffer []byte 303 304 // Reboot resets the system. 305 func (r *RPC) Reboot(_ *any, _ *bool) error { 306 log.Printf("SM rebooting") 307 usbarmory.Reset() 308 309 return nil 310 } 311 312 // ConsoleLog returns the console log for the current running OS & applet. 313 func (r *RPC) ConsoleLog(_ *any, ret *[]byte) error { 314 if ret == nil { 315 return errors.New("nil buffer passed") 316 } 317 318 *ret = getConsoleLogs() 319 return nil 320 } 321 322 // CrashLog returns the console log stored by the OS after the last 323 // applet exit, if any. 324 func (r *RPC) CrashLog(_ *any, ret *[]byte) error { 325 if ret == nil { 326 return errors.New("nil buffer passed") 327 } 328 329 l, err := retrieveLastCrashLog(r.Storage) 330 if err != nil { 331 return err 332 } 333 *ret = l 334 return nil 335 }