Skip to content

Commit

Permalink
Improve update RPC flow (#89)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlCutter authored Oct 30, 2023
1 parent 855603a commit 6ba598d
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 48 deletions.
3 changes: 0 additions & 3 deletions api/rpc/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ type FirmwareUpdate struct {
// Image is the firmware image to be applied.
Image []byte

// Signatures contains authentication signatures for the firmware.
Signatures [][]byte

// Proof contains firmware transparency artefacts for the new firmware image.
Proof config.ProofBundle
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/proofbundle/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func main() {
LogVerifer: logVerifier,
ManifestVerifiers: []note.Verifier{mv},
}
if err := v.Verify(bundle); err != nil {
if _, err := v.Verify(bundle); err != nil {
klog.Exitf("Failed to verify proof bundle: %v", err)
}

Expand Down
72 changes: 42 additions & 30 deletions trusted_os/flash.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const (
otaLimit = 31457280
taConfBlock = 0x200000
taBlock = taConfBlock + config.MaxLength/expectedBlockSize
osConfBlock = config.Offset / expectedBlockSize // Offset is in bytes
osConfBlock = 0x5000
osBlock = osConfBlock + config.MaxLength/expectedBlockSize
batchSize = 2048
)
Expand Down Expand Up @@ -116,15 +116,18 @@ func read(card Card) (fw *firmware.Bundle, err error) {
return
}

// flash writes a buffer to internal storage
// flash writes a buffer to internal storage.
//
// Since this function is writing blocks to MMC, it will pad the passed in
// buf with zeros to ensure full MMC blocks are written.
func flash(card Card, buf []byte, lba int) (err error) {
blockSize := card.Info().BlockSize
if blockSize != expectedBlockSize {
return fmt.Errorf("h/w invariant error - expected MMC blocksize %d, found %d", expectedBlockSize, blockSize)
}

if blockSize == 0 {
return errors.New("invalid block size")
if rem := len(buf) % blockSize; rem > 0 {
buf = append(buf, make([]byte, blockSize-rem)...)
}

blocks := len(buf) / blockSize
Expand All @@ -139,13 +142,11 @@ func flash(card Card, buf []byte, lba int) (err error) {
start := i * blockSize
end := start + blockSize*batch

if i%batch == 0 {
log.Printf("flashed %d/%d applet blocks", i, blocks)
}

if err = card.WriteBlocks(lba+i, buf[start:end]); err != nil {
return
}

log.Printf("flashed %d/%d blocks", i+batch, blocks)
}

return
Expand Down Expand Up @@ -178,21 +179,37 @@ func blinkenLights() (func(), func()) {
}

// updateApplet verifies an applet update and flashes it to internal storage
func updateApplet(taELF []byte, taSig []byte, pb config.ProofBundle) (err error) {
// TODO: OS applet verification
func updateApplet(storage Card, taELF []byte, pb config.ProofBundle) (err error) {
// First, verify everything is correct and that, as far as we can tell,
// we would succeed in loadering and launching this applet upon next boot.
bundle := firmware.Bundle{
Checkpoint: pb.Checkpoint,
Index: pb.LogIndex,
InclusionProof: pb.InclusionProof,
Manifest: pb.Manifest,
Firmware: taELF,
}
if _, err := AppletBundleVerifier.Verify(bundle); err != nil {
return err
}
log.Printf("SM verified applet bundle for update")

return flashFirmware(Firmware_Applet, taELF, [][]byte{taSig}, pb)
return flashFirmware(storage, Firmware_Applet, taELF, pb)
}

// updateOS verifies an OS update and flashes it to internal storage
func updateOS(osELF []byte, osSigs [][]byte, pb config.ProofBundle) (err error) {
// TODO: OS signature verification
func updateOS(storage Card, osELF []byte, pb config.ProofBundle) (err error) {
// TODO: OS proof bundle verification

return flashFirmware(Firmware_OS, osELF, osSigs, pb)
return flashFirmware(storage, Firmware_OS, osELF, pb)
}

// flashFirmware writes config & elf bytes to the MMC in the correct region for the specificed type of firmware.
func flashFirmware(t FirmwareType, elf []byte, sigs [][]byte, pb config.ProofBundle) error {
func flashFirmware(storage Card, t FirmwareType, elf []byte, pb config.ProofBundle) error {
if storage == nil {
return fmt.Errorf("Flashing %s error: missing Storage", t)
}

blink, cancel := blinkenLights()
defer cancel()
go blink()
Expand All @@ -213,30 +230,25 @@ func flashFirmware(t FirmwareType, elf []byte, sigs [][]byte, pb config.ProofBun
// Convert the signature to an armory-witness-boot format to serialize
// all required information for applet loading.
conf := &config.Config{
Size: int64(len(elf)),
Signatures: sigs,
Bundle: pb,
Offset: int64(elfBlock) * expectedBlockSize,
Size: int64(len(elf)),
Bundle: pb,
Offset: int64(elfBlock) * expectedBlockSize,
}

confEnc, err := conf.Encode()
if err != nil {
return err
}

if Storage == nil {
return fmt.Errorf("Flashing %s error: missing Storage", t)
}

log.Printf("SM flashing %s config", t)
log.Printf("SM flashing %s config (%d bytes) @ 0x%x", t, len(confEnc), confBlock)

if err = flash(Storage, confEnc, confBlock); err != nil {
if err = flash(storage, confEnc, confBlock); err != nil {
return fmt.Errorf("%s signature flashing error: %v", t, err)
}

log.Printf("SM flashing %s", t)
log.Printf("SM flashing %s (%d bytes) @ 0x%x", t, len(elf), elfBlock)

if err = flash(Storage, elf, elfBlock); err != nil {
if err = flash(storage, elf, elfBlock); err != nil {
return fmt.Errorf("%s flashing error: %v", t, err)
}

Expand Down Expand Up @@ -316,11 +328,11 @@ func (ctl *controlInterface) Update(req []byte) (res []byte) {
if ctl.ota.seq == ctl.ota.total {
log.Printf("received all %d firmware update chunks", ctl.ota.total)

go func(buf []byte, sig []byte, pb config.ProofBundle) {
go func(buf []byte, pb config.ProofBundle) {
// avoid USB control interface timeout
time.Sleep(500 * time.Millisecond)

if err = updateApplet(buf, sig, pb); err != nil {
if err = updateApplet(ctl.RPC.Storage, buf, pb); err != nil {
log.Printf("firmware update error, %v", err)
}

Expand All @@ -335,7 +347,7 @@ func (ctl *controlInterface) Update(req []byte) (res []byte) {
if _, err = loadApplet(taELF, ctl); err != nil {
log.Printf("SM applet execution error, %v", err)
}
}(ctl.ota.buf, ctl.ota.sig, *ctl.ota.bundle)
}(ctl.ota.buf, *ctl.ota.bundle)

ctl.ota = nil
}
Expand Down
16 changes: 8 additions & 8 deletions trusted_os/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ var (

var (
Control *usb.USB
Storage Card

// USB armory Mk II (rev. β) - UA-MKII-β
// USB armory Mk II (rev. γ) - UA-MKII-γ
Expand All @@ -63,6 +62,8 @@ var (
// loadedAppletVersion is taken from the manifest used to verify the
// applet.
loadedAppletVersion semver.Version

AppletBundleVerifier firmware.BundleVerifier
)

// A Trusted Applet can be embedded for testing purposes with QEMU.
Expand Down Expand Up @@ -166,6 +167,11 @@ func main() {
if err != nil {
log.Fatalf("SM invalid AppletlManifestogVerifier: %v", err)
}
AppletBundleVerifier = firmware.BundleVerifier{
LogOrigin: AppletLogOrigin,
LogVerifer: logVerifier,
ManifestVerifiers: []note.Verifier{appletVerifier},
}

if v, err := semver.NewVersion(Version); err != nil {
log.Printf("Failed to parse OS version %q: %v", Version, err)
Expand All @@ -189,13 +195,7 @@ func main() {
}

if ta != nil {
bv := firmware.BundleVerifier{
LogOrigin: AppletLogOrigin,
LogVerifer: logVerifier,
ManifestVerifiers: []note.Verifier{appletVerifier},
}

manifest, err := bv.Verify(*ta)
manifest, err := AppletBundleVerifier.Verify(*ta)
if err != nil {
log.Printf("SM applet verification error, %v", err)
}
Expand Down
10 changes: 4 additions & 6 deletions trusted_os/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ func (r *RPC) GetInstalledVersions(_ *any, v *rpc.InstalledVersions) error {
// If the update is successful, this func will not return and the device will
// immediately reboot.
func (r *RPC) InstallOS(b *rpc.FirmwareUpdate, _ *bool) error {
if err := updateOS(b.Image, b.Signatures, b.Proof); err != nil {
if err := updateOS(r.Storage, b.Image, b.Proof); err != nil {
return err
}
r.Ctx.Stop()
Expand All @@ -243,11 +243,7 @@ func (r *RPC) InstallOS(b *rpc.FirmwareUpdate, _ *bool) error {
// If the update is successful, this func will not return and the device will
// immediately reboot.
func (r *RPC) InstallApplet(b *rpc.FirmwareUpdate, _ *bool) error {
if len(b.Signatures) == 0 {
return errors.New("missing signature")
}

if err := updateApplet(b.Image, b.Signatures[0], b.Proof); err != nil {
if err := updateApplet(r.Storage, b.Image, b.Proof); err != nil {
return err
}
r.Ctx.Stop()
Expand All @@ -259,6 +255,8 @@ func (r *RPC) InstallApplet(b *rpc.FirmwareUpdate, _ *bool) error {
// Reboot resets the system.
func (r *RPC) Reboot(_ *any, _ *bool) error {
log.Printf("SM rebooting")
// Reduce Watchdog timeout for a faster reboot:
imx6ul.WDOG2.Service(500)
usbarmory.Reset()

return nil
Expand Down

0 comments on commit 6ba598d

Please sign in to comment.