def sign_tx(self, tx): self.device.check_mitm() # Get psbt in hex and then make binary fd = io.BytesIO(base64.b64decode(tx.serialize())) # learn size (portable way) offset = 0 sz = fd.seek(0, 2) fd.seek(0) left = sz chk = sha256() for pos in range(0, sz, MAX_BLK_LEN): here = fd.read(min(MAX_BLK_LEN, left)) if not here: break left -= len(here) result = self.device.send_recv( CCProtocolPacker.upload(pos, sz, here)) assert result == pos chk.update(here) # do a verify expect = chk.digest() result = self.device.send_recv(CCProtocolPacker.sha256()) assert len(result) == 32 if result != expect: raise ValueError("Wrong checksum:\nexpect: %s\n got: %s" % (b2a_hex(expect).decode('ascii'), b2a_hex(result).decode('ascii'))) # start the signing process ok = self.device.send_recv(CCProtocolPacker.sign_transaction( sz, expect), timeout=None) assert ok == None if self.device.is_simulator: self.device.send_recv(CCProtocolPacker.sim_keypress(b'y')) print("Waiting for OK on the Coldcard...") while 1: time.sleep(0.250) done = self.device.send_recv(CCProtocolPacker.get_signed_txn(), timeout=None) if done == None: continue break if len(done) != 2: raise ValueError('Failed: %r' % done) result_len, result_sha = done result = self.device.download_file(result_len, result_sha, file_number=1) return {'psbt': base64.b64encode(result).decode()}
def doit(): dlen, _ = dev.upload_file(firmware, verify=True) assert dlen == len(firmware) # append the firmware header a second time result = dev.send_recv(CCProtocolPacker.upload(size, size+FW_HEADER_SIZE, hdr)) # make it reboot into bootlaoder which might install it dev.send_recv(CCProtocolPacker.reboot())
def real_file_upload(fd, dev, blksize=MAX_BLK_LEN, do_upgrade=False, do_reboot=True): # learn size (portable way) offset = 0 sz = fd.seek(0, 2) fd.seek(0) if do_upgrade: # Unwrap DFU contents, if needed. Also handles raw binary file. try: if fd.read(5) == b'DfuSe': # expecting a DFU-wrapped file. fd.seek(0) offset, sz, *_ = dfu_parse(fd) else: # assume raw binary pass assert sz % 256 == 0, "un-aligned size: %s" % sz fd.seek(offset + FW_HEADER_OFFSET) hdr = fd.read(FW_HEADER_SIZE) magic = struct.unpack_from("<I", hdr)[0] #print("hdr @ 0x%x: %s" % (FW_HEADER_OFFSET, b2a_hex(hdr))) except Exception: magic = None if magic != FW_HEADER_MAGIC: click.echo( "This does not look like a firmware file! Bad magic value.") sys.exit(1) fd.seek(offset) click.echo( "%d bytes (start @ %d) to send from %r" % (sz, fd.tell(), os.path.basename(fd.name) if hasattr(fd, 'name') else 'memory'), err=1) left = sz chk = sha256() with click.progressbar(range(0, sz, blksize), label="Uploading") as bar: for pos in bar: here = fd.read(min(blksize, left)) if not here: break left -= len(here) result = dev.send_recv(CCProtocolPacker.upload(pos, sz, here)) assert result == pos, "Got back: %r" % result chk.update(here) # do a verify expect = chk.digest() result = dev.send_recv(CCProtocolPacker.sha256()) assert len(result) == 32 if result != expect: click.echo( "Wrong checksum:\nexpect: %s\n got: %s" % (b2a_hex(expect).decode('ascii'), b2a_hex(result).decode('ascii')), err=1) sys.exit(1) if not do_upgrade: return sz, expect # AFTER fully uploaded and verified, write a copy of the signature header # onto the end of flash. Bootrom uses this to check entire file uploaded. result = dev.send_recv( CCProtocolPacker.upload(sz, sz + FW_HEADER_SIZE, hdr)) assert result == sz, "failed to write trailer" # check also SHA after that! chk.update(hdr) expect = chk.digest() final_chk = dev.send_recv(CCProtocolPacker.sha256()) assert expect == final_chk, "Checksum mismatch after all that?" if do_reboot: click.echo("Upgrade started. Observe Coldcard screen for progress.", err=1) dev.send_recv(CCProtocolPacker.reboot())