github.com/transparency-dev/armored-witness-applet@v0.1.1/trusted_applet/internal/update/rpc/update_client.go (about)

     1  // Copyright 2023 The Armored Witness Applet 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 rpc provides an RPC-based update client.
    16  package rpc
    17  
    18  import (
    19  	"github.com/coreos/go-semver/semver"
    20  	"github.com/transparency-dev/armored-witness-boot/config"
    21  	"github.com/transparency-dev/armored-witness-common/release/firmware"
    22  	"github.com/transparency-dev/armored-witness-os/api/rpc"
    23  	"github.com/usbarmory/GoTEE/syscall"
    24  	"k8s.io/klog/v2"
    25  )
    26  
    27  const fwUpdateChunkSize = 1 << 20
    28  
    29  // Client is an implementation of the Local interface which uses RPCs to the TrustedOS
    30  // to perform the updates.
    31  type Client struct {
    32  }
    33  
    34  // GetInstalledVersions returns the semantic versions of the OS and Applet
    35  // installed on this device. These will be the same versions that are
    36  // currently running.
    37  func (r Client) GetInstalledVersions() (os, applet semver.Version, err error) {
    38  	iv := &rpc.InstalledVersions{}
    39  	err = syscall.Call("RPC.GetInstalledVersions", nil, iv)
    40  	return iv.OS, iv.Applet, err
    41  
    42  }
    43  
    44  // InstallOS updates the OS to the version contained in the firmware bundle.
    45  // If the update is successful, the RPC will not return.
    46  func (r Client) InstallOS(fb firmware.Bundle) error {
    47  	return sendChunkedUpdate("OS", "RPC.InstallOS", fb)
    48  }
    49  
    50  // InstallApplet updates the Applet to the version contained in the firmware bundle.
    51  // If the update is successful, the RPC will not return.
    52  func (r Client) InstallApplet(fb firmware.Bundle) error {
    53  	return sendChunkedUpdate("applet", "RPC.InstallApplet", fb)
    54  }
    55  
    56  // sendChunkedUpdate sends a chunked OS or Applet firmware update request via one or
    57  // more RPCs to the OS.
    58  func sendChunkedUpdate(t string, rpcName string, fb firmware.Bundle) error {
    59  	klog.Infof("Requesting %s install from OS...", t)
    60  	fu := &rpc.FirmwareUpdate{}
    61  	for i := uint(0); ; i++ {
    62  		fu.Sequence = i
    63  		size := fwUpdateChunkSize
    64  		if rem := len(fb.Firmware); size >= rem {
    65  			fu.Proof = config.ProofBundle{
    66  				Checkpoint:     fb.Checkpoint,
    67  				LogIndex:       fb.Index,
    68  				InclusionProof: fb.InclusionProof,
    69  				Manifest:       fb.Manifest,
    70  			}
    71  			size = rem
    72  		}
    73  		fu.Image = fb.Firmware[:size]
    74  		fb.Firmware = fb.Firmware[size:]
    75  		klog.Infof("Sending %s chunk %d", t, i)
    76  		if err := syscall.Call(rpcName, fu, nil); err != nil {
    77  			return err
    78  		}
    79  	}
    80  }
    81  
    82  // Reboot instructs the device to reboot after new firmware is installed.
    83  // This call will not return and deferred functions will not be run.
    84  func (r Client) Reboot() {
    85  	_ = syscall.Call("RPC.Reboot", nil, nil)
    86  }