github.com/google/trillian-examples@v0.0.0-20240520080811-0d40d35cef0e/binary_transparency/firmware/devices/usbarmory/flash/flash.go (about) 1 // Copyright 2020 Google LLC. 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 flash holds code to deal with the USB armory SD card storage. 16 package flash 17 18 import ( 19 "encoding/json" 20 "errors" 21 "fmt" 22 "os" 23 "path/filepath" 24 "strings" 25 26 "github.com/google/trillian-examples/binary_transparency/firmware/api" 27 "github.com/google/trillian-examples/binary_transparency/firmware/cmd/flash_tool/devices" 28 ) 29 30 const ( 31 // bundlePath is the filename within the proof partition where the armory 32 // expects to fund the proof bundle. 33 bundlePath = "bundle.json" 34 ) 35 36 // Device represents the flash storage for the unsarmory. 37 type Device struct { 38 fwDevPath string 39 bundlePath string 40 41 // bundle holds all the update data except the firmware image. 42 bundle api.ProofBundle 43 } 44 45 var _ devices.Device = Device{} 46 47 // New creates a new usbarmory device instance. 48 // 49 // storage is a comma separated string with the format: 50 // <proof_mount_point_path>,<firmware_block_device> 51 func New(storage string) (*Device, error) { 52 bits := strings.Split(storage, ",") 53 if len(bits) != 2 { 54 return nil, errors.New("storage should be '<proof mount point path>,<firmware block device path>'") 55 } 56 proofDir, fwDevPath := bits[0], bits[1] 57 58 dStat, err := os.Stat(proofDir) 59 if err != nil { 60 return nil, fmt.Errorf("unable to stat %q: %w", proofDir, err) 61 } 62 if !dStat.Mode().IsDir() { 63 return nil, fmt.Errorf("%q is not a directory", proofDir) 64 } 65 66 d := &Device{ 67 fwDevPath: filepath.Clean(fwDevPath), 68 bundlePath: filepath.Clean(filepath.Join(proofDir, bundlePath)), 69 } 70 71 f, err := os.OpenFile(d.bundlePath, os.O_RDONLY, os.ModePerm) 72 if err != nil { 73 if os.IsNotExist(err) { 74 return d, devices.ErrNeedsInit(fmt.Errorf("couldn't read bundle file %q: %w", d.bundlePath, err)) 75 } 76 return d, fmt.Errorf("failed to read bundle file %q: %w", d.bundlePath, err) 77 } 78 defer func() { 79 _ = f.Close() 80 }() 81 82 err = json.NewDecoder(f).Decode(&d.bundle) 83 return d, err 84 } 85 86 // DeviceCheckpoint returns the latest log checkpoint stored on the device. 87 func (d Device) DeviceCheckpoint() ([]byte, error) { 88 return d.bundle.Checkpoint, nil 89 } 90 91 // ApplyUpdate applies the firmware update to the armory SD Card device. 92 // The firmware image is written directly to the unikernel partition of the device 93 // (the raw block device is specified by the --armory_unikernel_dev flag), 94 // and proof bundle is stored in the proof partition of the device which must be 95 // mounted at the location specified by the --armory_proof_mount_point flag). 96 // 97 // TODO(al): see what can be done to make this easier to use. 98 func (d Device) ApplyUpdate(u api.UpdatePackage) error { 99 if err := os.WriteFile(d.bundlePath, u.ProofBundle, os.ModePerm); err != nil { 100 return fmt.Errorf("failed to write proof bundle to %q: %w", d.bundlePath, err) 101 } 102 103 fw := u.FirmwareImage 104 if err := os.WriteFile(d.fwDevPath, fw, os.ModePerm); err != nil { 105 return fmt.Errorf("failed to write firmware image to %q: %w", d.fwDevPath, err) 106 } 107 108 return nil 109 }