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  }