Skip to content

Commit

Permalink
api/bootloader: add ParseSignedFirwmare() util function
Browse files Browse the repository at this point in the history
  • Loading branch information
benma committed May 13, 2024
1 parent b118c1b commit 3191e45
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 11 deletions.
16 changes: 5 additions & 11 deletions api/bootloader/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,18 +233,12 @@ func (device *Device) flashUnsignedFirmware(firmware []byte, progressCallback fu
// format is invalid, or the firmware magic does not match the expected magic according to the
// device product.
func (device *Device) parseSignedFirmware(firmware []byte) ([]byte, []byte, error) {
if len(firmware) <= magicLen+sigDataLen {
return nil, nil, errp.New("firmware too small")
}
magic, firmware := firmware[:magicLen], firmware[magicLen:]
sigData, firmware := firmware[:sigDataLen], firmware[sigDataLen:]

expectedMagic, ok := sigDataMagic[device.product]
if !ok {
return nil, nil, errp.New("unrecognized product")
product, sigData, firmware, err := ParseSignedFirmware(firmware)
if err != nil {
return nil, nil, err
}
if binary.BigEndian.Uint32(magic) != expectedMagic {
return nil, nil, errp.New("invalid signing pubkeys data magic")
if product != device.product {
return nil, nil, errp.New("signed firmware binary does not match device product")
}
return sigData, firmware, nil
}
Expand Down
28 changes: 28 additions & 0 deletions api/bootloader/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import (
"bytes"
"crypto/sha256"
"encoding/binary"

"github.com/digitalbitbox/bitbox02-api-go/api/common"
"github.com/digitalbitbox/bitbox02-api-go/util/errp"
)

// HashFirmware returns the hash of `<firmware version><firmware>`, as computed by the bootloader to
Expand All @@ -35,3 +38,28 @@ func HashFirmware(firmwareVersion uint32, unsignedFirmware []byte) []byte {
copy(padded, unsignedFirmware)
return doubleHash(append(firmwareVersionLE, padded...))
}

// ParseSignedFirmware parses a signed firmware file and returns (sigdata, firmware). Errors if the
// format is invalid, or the firmware magic does not match the expected magic according to the
// device product.
func ParseSignedFirmware(firmware []byte) (common.Product, []byte, []byte, error) {
if len(firmware) <= magicLen+sigDataLen {
return "", nil, nil, errp.New("firmware too small")
}
magic, firmware := firmware[:magicLen], firmware[magicLen:]
sigData, firmware := firmware[:sigDataLen], firmware[sigDataLen:]

var product common.Product
magicInt := binary.BigEndian.Uint32(magic)
for p, productMagic := range sigDataMagic {
if magicInt == productMagic {
product = p
break
}
}
if product == "" {
return "", nil, nil, errp.Newf("unrecognized magic")
}

return product, sigData, firmware, nil
}
18 changes: 18 additions & 0 deletions api/bootloader/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
package bootloader

import (
"encoding/hex"
"io/ioutil"
"testing"

"github.com/digitalbitbox/bitbox02-api-go/api/common"
"github.com/stretchr/testify/require"
)

Expand All @@ -32,3 +34,19 @@ func TestHashFirmware(t *testing.T) {
HashFirmware(7, unsignedFirmware),
)
}

func TestParseSignedFirmmare(t *testing.T) {
unsignedFirmware, err := ioutil.ReadFile("testdata/firmware-btc.v4.2.2.bin")
require.NoError(t, err)

signedFirmware, err := ioutil.ReadFile("testdata/firmware-btc.v4.2.2.signed.bin")
require.NoError(t, err)

product, sigData, firmware, err := ParseSignedFirmware(signedFirmware)
require.NoError(t, err)

expectedSigData := "0000000027a8678099f9f52b142a0692b320d6053d3f7c637273a236654ce4e5346efaffb35034df24eca2e500bbd24b84ba79799d4d7ad5492516b5122587d41a63d9d7c2565124b98a5d9da8bfab7e566371c936b1435d7980d4c09bc31b84431c2e3c6b62829093f478be5356657aa525d6a5fc793acd2641f9bd2d3587dea6a33ad7c6789655ce072bf02908b5d795a87b6789cac63e98bf7849d740d47fb62f3fef88c6db3cb260c53302eb133a89b3529e2f8ae20e99ed0fe3d32cd30db880ffbc47be63edb71c681a3a0d45716746db7704c915d617fcf1c895ca949bb3adcc9a666c73dd373cdf9d4ccf9ff102bde32307f29ecdbf981b3553af7ba3509ff565000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d8054281b0f6733469f58e0406cba24fefcea8704cd6e8d990bd98fa33d2b0a0942dcafc81f912216ca86cab2000b6de96f1567d5209ab6167278dc585b011d070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017a44e602e19792e468a110b997f74b4149a4aca55e98a8b94f219739886c0227f6267ff582f2c1293f71f5afcb5ba6065ebeb454aa142f389f2bb91da62e4281f557a14e9974a3df39c9451b88766c4de7d1fcb8173fcdef82e316e8a8fd4822947a103aeee373e7c687228fadbd5b7ae3032886da057d53338abd889bff301"
require.Equal(t, expectedSigData, hex.EncodeToString(sigData))
require.Equal(t, common.ProductBitBox02BTCOnly, product)
require.Equal(t, unsignedFirmware, firmware)
}

0 comments on commit 3191e45

Please sign in to comment.