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  }