Skip to content

Commit da155b0

Browse files
committed
backend/bitbox02bootloader: allow fixing broken install
Problem: a new device ships with the latest firmware monotonic version. User sees 'Install' because the device is erased (no firmware on it), but during first install of firmware, unplugs. Upon replug, the device will show 'Invalid firmware' and boot into bootloader again. Since the monotonic version of the firmware to be installed is the same as the version stored on the device, and the device is not erased (half of the firmware is on it), the user sees no button to upgrade/instll anymore. This commit fixes this by still showing the upgrade button if the versions are the same, but the device firmware hash does not match the expected firmware hash.
1 parent b4d6e7a commit da155b0

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

backend/devices/bitbox02bootloader/device.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package bitbox02bootloader
1818

1919
import (
20+
"bytes"
21+
"encoding/hex"
2022
"fmt"
2123
"sync"
2224

@@ -240,6 +242,11 @@ func (device *Device) VersionInfo() (*VersionInfo, error) {
240242
if err != nil {
241243
return nil, err
242244
}
245+
currentFirmwareHash, _, err := device.Device.GetHashes(false, false)
246+
if err != nil {
247+
return nil, err
248+
}
249+
243250
latestFw, err := bundledFirmware(device.Device.Product())
244251
if err != nil {
245252
return nil, err
@@ -249,12 +256,27 @@ func (device *Device) VersionInfo() (*VersionInfo, error) {
249256
if err != nil {
250257
return nil, err
251258
}
252-
canUpgrade := erased || latestFirmwareVersion > currentFirmwareVersion
259+
260+
latestFirmwareHash, err := latestFw.firmwareHash()
261+
if err != nil {
262+
return nil, err
263+
}
264+
265+
// If the device firmware version is at the latest version but the installed firmware is
266+
// different, we assume it's a broken/interrupted install. This can happen for example when a
267+
// new device is shipped with the latest monotonic version pre-set, and the user interrupts
268+
// their first install.
269+
brokenInstall := latestFirmwareVersion == currentFirmwareVersion &&
270+
!bytes.Equal(currentFirmwareHash, latestFirmwareHash)
271+
272+
canUpgrade := erased || latestFirmwareVersion > currentFirmwareVersion || brokenInstall
253273
additionalUpgradeFollows := nextFw.monotonicVersion < latestFirmwareVersion
254274
device.log.
255275
WithField("latestFirmwareVersion", latestFirmwareVersion).
256276
WithField("currentFirmwareVersion", currentFirmwareVersion).
277+
WithField("currentFirmwareHash", hex.EncodeToString(currentFirmwareHash)).
257278
WithField("erased", erased).
279+
WithField("brokenInstall", brokenInstall).
258280
WithField("canUpgrade", canUpgrade).
259281
WithField("additionalUpgradeFollows", additionalUpgradeFollows).
260282
Info("VersionInfo")

backend/devices/bitbox02bootloader/firmware.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"io"
2222

2323
"github.com/BitBoxSwiss/bitbox-wallet-app/util/errp"
24+
"github.com/BitBoxSwiss/bitbox02-api-go/api/bootloader"
2425
bitbox02common "github.com/BitBoxSwiss/bitbox02-api-go/api/common"
2526
"github.com/BitBoxSwiss/bitbox02-api-go/util/semver"
2627
)
@@ -53,6 +54,19 @@ func (fi firmwareInfo) signedBinary() ([]byte, error) {
5354
return io.ReadAll(gz)
5455
}
5556

57+
func (fi firmwareInfo) firmwareHash() ([]byte, error) {
58+
signedBinary, err := fi.signedBinary()
59+
if err != nil {
60+
return nil, err
61+
}
62+
63+
_, _, binary, err := bootloader.ParseSignedFirmware(signedBinary)
64+
if err != nil {
65+
return nil, err
66+
}
67+
return bootloader.HashFirmware(fi.monotonicVersion, binary), nil
68+
}
69+
5670
// The last entry in the slice is the latest firmware update to which one can upgrade.
5771
// The other entries are intermediate upgrades that are required before upgrading to the latest one.
5872
// Each one has to be flashed and booted before being able to continue upgrading.

0 commit comments

Comments
 (0)