Beispiel #1
0
    async def handle_upload(self, offset, total_size, data):
        from main import dis, sf, hsm_active
        from utils import check_firmware_hdr
        from sigheader import FW_HEADER_OFFSET, FW_HEADER_SIZE

        # maintain a running SHA256 over what's received
        if offset == 0:
            self.file_checksum = tcc.sha256()

        assert offset % 256 == 0, 'alignment'
        assert offset + len(data) <= total_size <= MAX_UPLOAD_LEN, 'long'

        if hsm_active:
            # additional restrictions in HSM mode
            assert offset + len(data) <= total_size <= MAX_TXN_LEN, 'psbt'
            if offset == 0:
                assert data[0:5] == b'psbt\xff', 'psbt'

        for pos in range(offset, offset + len(data), 256):
            if pos % 4096 == 0:
                # erase here
                dis.fullscreen("Receiving...", offset / total_size)

                sf.sector_erase(pos)

                while sf.is_busy():
                    await sleep_ms(10)

            # write up to 256 bytes
            here = data[pos - offset:pos - offset + 256]

            self.file_checksum.update(here)

            # Very special case for firmware upgrades: intercept and modify
            # header contents on the fly, and also fail faster if wouldn't work
            # on this specific hardware.
            # - workaround: ckcc-protocol upgrade process understates the file
            #   length and appends hdr, but that's kinda a bug, so support both
            if (pos == (FW_HEADER_OFFSET & ~255)
                    or pos == (total_size - FW_HEADER_SIZE)
                    or pos == total_size):

                prob = check_firmware_hdr(memoryview(here)[-128:],
                                          None,
                                          bad_magic_ok=True)
                if prob:
                    raise ValueError(prob)

            sf.write(pos, here)

            # full page write: 0.6 to 3ms
            while sf.is_busy():
                await sleep_ms(1)

        if offset + len(data) >= total_size and not hsm_active:
            # probably done
            dis.progress_bar_show(1.0)
            ux.restore_menu()

        return offset
Beispiel #2
0
async def microsd_upgrade(*a):
    # Upgrade vis MicroSD card
    # - search for a particular file
    # - verify it lightly
    # - erase serial flash
    # - copy it over (slow)
    # - reboot into bootloader, which finishes install

    fn = await file_picker('Pick firmware image to use (.DFU)', suffix='.dfu', min_size=0x7800)

    if not fn: return

    failed = None

    with CardSlot() as card:
        with open(fn, 'rb') as fp:
            from main import sf, dis
            from files import dfu_parse
            from utils import check_firmware_hdr

            offset, size = dfu_parse(fp)

            # we also put a copy of special signed heaer at the end of the flash
            from sigheader import FW_HEADER_OFFSET, FW_HEADER_SIZE

            # read just the signature header
            hdr = bytearray(FW_HEADER_SIZE)
            fp.seek(offset + FW_HEADER_OFFSET)
            rv = fp.readinto(hdr)
            assert rv == FW_HEADER_SIZE

            # check header values
            failed = check_firmware_hdr(hdr, size)

            if not failed:
                patched = 0
            
                # copy binary into serial flash
                fp.seek(offset)

                buf = bytearray(256)        # must be flash page size
                pos = 0
                dis.fullscreen("Loading...")
                while pos <= size + FW_HEADER_SIZE:
                    dis.progress_bar_show(pos/size)

                    if pos == size:
                        # save an extra copy of the header (also means we got done)
                        buf = hdr
                        patched += 1
                    else:
                        here = fp.readinto(buf)
                        if not here: break

                    if pos == (FW_HEADER_OFFSET & ~255):
                        # update w/ our patched version of hdr
                        buf[128:FW_HEADER_SIZE+128] = hdr
                        patched += 1

                    if pos % 4096 == 0:
                        # erase here
                        sf.sector_erase(pos)
                        while sf.is_busy():
                            await sleep_ms(10)

                    sf.write(pos, buf)

                    # full page write: 0.6 to 3ms
                    while sf.is_busy():
                        await sleep_ms(1)

                    pos += here

                assert patched == 2

    if failed:
        await ux_show_story(failed, title='Sorry!')
        return

    # continue process...
    import machine
    machine.reset()
Beispiel #3
0
    async def handle_upload(self, offset, total_size, data):
        from sflash import SF
        from glob import dis, hsm_active
        from utils import check_firmware_hdr
        from sigheader import FW_HEADER_OFFSET, FW_HEADER_SIZE, FW_HEADER_MAGIC

        # maintain a running SHA256 over what's received
        if offset == 0:
            self.file_checksum = sha256()
            self.is_fw_upgrade = False

        assert offset % 256 == 0, 'alignment'
        assert offset + len(data) <= total_size <= MAX_UPLOAD_LEN, 'long'

        if hsm_active:
            # additional restrictions in HSM mode
            assert offset + len(data) <= total_size <= MAX_TXN_LEN, 'psbt'
            if offset == 0:
                assert data[0:5] == b'psbt\xff', 'psbt'

        for pos in range(offset, offset + len(data), 256):
            if pos % 4096 == 0:
                # erase here
                dis.fullscreen("Receiving...", offset / total_size)

                SF.sector_erase(pos)

                # expect 10-22 ms delay here
                await sleep_ms(12)
                while SF.is_busy():
                    await sleep_ms(2)

            # write up to 256 bytes
            here = data[pos - offset:pos - offset + 256]
            self.file_checksum.update(here)

            # Very special case for firmware upgrades: intercept and modify
            # header contents on the fly, and also fail faster if wouldn't work
            # on this specific hardware.
            # - workaround: ckcc-protocol upgrade process understates the file
            #   length and appends hdr, but that's kinda a bug, so support both
            is_trailer = (pos == (total_size - FW_HEADER_SIZE)
                          or pos == total_size)

            if pos == (FW_HEADER_OFFSET & ~255):
                hdr = memoryview(here)[-128:]
                magic, = unpack_from('<I', hdr[0:4])
                if magic == FW_HEADER_MAGIC:
                    self.is_fw_upgrade = bytes(hdr)

                    prob = check_firmware_hdr(hdr, total_size)
                    if prob:
                        raise ValueError(prob)

            if is_trailer and self.is_fw_upgrade:
                # expect the trailer to exactly match the original one
                assert len(here) == 128  # == FW_HEADER_SIZE
                hdr = memoryview(here)[-128:]
                assert hdr == self.is_fw_upgrade  # indicates hacking

                # but don't write it, instead offer user a chance to abort
                from auth import authorize_upgrade
                authorize_upgrade(self.is_fw_upgrade, pos)

                # pretend we wrote it, so ckcc-protocol or whatever gives normal feedback
                return offset

            SF.write(pos, here)

            # full page write: 0.6 to 3ms
            while SF.is_busy():
                await sleep_ms(1)

        if offset + len(data) >= total_size and not hsm_active:
            # probably done
            dis.progress_bar_show(1.0)
            ux.restore_menu()

        return offset