program using just hid protocol, quicker
This commit is contained in:
parent
5a96e82f4d
commit
b0cc9cf582
@ -30,6 +30,7 @@
|
|||||||
#include "time.h"
|
#include "time.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "extensions.h"
|
||||||
#include APP_CONFIG
|
#include APP_CONFIG
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
@ -682,6 +683,23 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
printf1(TAG_HID,"CTAPHID_CANCEL\n");
|
printf1(TAG_HID,"CTAPHID_CANCEL\n");
|
||||||
is_busy = 0;
|
is_busy = 0;
|
||||||
break;
|
break;
|
||||||
|
#if defined(IS_BOOTLOADER)
|
||||||
|
case CTAPHID_BOOT:
|
||||||
|
printf1(TAG_HID,"CTAPHID_BOOT\n");
|
||||||
|
ctap_response_init(&ctap_resp);
|
||||||
|
u2f_set_writeback_buffer(&ctap_resp);
|
||||||
|
is_busy = bootloader_bridge(len, ctap_buffer);
|
||||||
|
|
||||||
|
ctaphid_write_buffer_init(&wb);
|
||||||
|
wb.cid = cid;
|
||||||
|
wb.cmd = CTAPHID_BOOT;
|
||||||
|
wb.bcnt = (ctap_resp.length + 1);
|
||||||
|
ctaphid_write(&wb, &is_busy, 1);
|
||||||
|
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
|
||||||
|
ctaphid_write(&wb, NULL, 0);
|
||||||
|
is_busy = 0;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
printf2(TAG_ERR,"error, unimplemented HID cmd: %02x\r\n", buffer_cmd());
|
printf2(TAG_ERR,"error, unimplemented HID cmd: %02x\r\n", buffer_cmd());
|
||||||
ctaphid_send_error(cid, CTAP1_ERR_INVALID_COMMAND);
|
ctaphid_send_error(cid, CTAP1_ERR_INVALID_COMMAND);
|
||||||
|
@ -38,6 +38,9 @@
|
|||||||
#define CTAPHID_ERROR (TYPE_INIT | 0x3f)
|
#define CTAPHID_ERROR (TYPE_INIT | 0x3f)
|
||||||
#define CTAPHID_KEEPALIVE (TYPE_INIT | 0x3b)
|
#define CTAPHID_KEEPALIVE (TYPE_INIT | 0x3b)
|
||||||
|
|
||||||
|
// Custom commands between 0x40-0x7f
|
||||||
|
#define CTAPHID_BOOT (TYPE_INIT | 0x50)
|
||||||
|
|
||||||
#define ERR_INVALID_CMD 0x01
|
#define ERR_INVALID_CMD 0x01
|
||||||
#define ERR_INVALID_PAR 0x02
|
#define ERR_INVALID_PAR 0x02
|
||||||
#define ERR_INVALID_SEQ 0x04
|
#define ERR_INVALID_SEQ 0x04
|
||||||
|
@ -25,6 +25,6 @@
|
|||||||
|
|
||||||
int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len);
|
int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len);
|
||||||
|
|
||||||
int bootloader_bridge(uint8_t klen, uint8_t * keyh);
|
int bootloader_bridge(int klen, uint8_t * keyh);
|
||||||
|
|
||||||
#endif /* EXTENSIONS_H_ */
|
#endif /* EXTENSIONS_H_ */
|
||||||
|
@ -34,6 +34,7 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
|
|||||||
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
|
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
|
||||||
void u2f_reset_response();
|
void u2f_reset_response();
|
||||||
|
|
||||||
|
|
||||||
static CTAP_RESPONSE * _u2f_resp = NULL;
|
static CTAP_RESPONSE * _u2f_resp = NULL;
|
||||||
|
|
||||||
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
||||||
@ -43,7 +44,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
|||||||
uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16));
|
uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16));
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
|
|
||||||
_u2f_resp = resp;
|
u2f_set_writeback_buffer(resp);
|
||||||
|
|
||||||
if (req->cla != 0)
|
if (req->cla != 0)
|
||||||
{
|
{
|
||||||
@ -137,6 +138,10 @@ void u2f_reset_response()
|
|||||||
ctap_response_init(_u2f_resp);
|
ctap_response_init(_u2f_resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void u2f_set_writeback_buffer(CTAP_RESPONSE * resp)
|
||||||
|
{
|
||||||
|
_u2f_resp = resp;
|
||||||
|
}
|
||||||
|
|
||||||
static void dump_signature_der(uint8_t * sig)
|
static void dump_signature_der(uint8_t * sig)
|
||||||
{
|
{
|
||||||
|
@ -116,6 +116,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp);
|
|||||||
|
|
||||||
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
|
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
|
||||||
void u2f_reset_response();
|
void u2f_reset_response();
|
||||||
|
void u2f_set_writeback_buffer(CTAP_RESPONSE * resp);
|
||||||
|
|
||||||
int16_t u2f_version();
|
int16_t u2f_version();
|
||||||
|
|
||||||
|
@ -28,8 +28,9 @@ typedef struct {
|
|||||||
uint8_t op;
|
uint8_t op;
|
||||||
uint8_t addr[3];
|
uint8_t addr[3];
|
||||||
uint8_t tag[4];
|
uint8_t tag[4];
|
||||||
uint8_t len;
|
uint8_t lenh;
|
||||||
uint8_t payload[255 - 9];
|
uint8_t lenl;
|
||||||
|
uint8_t payload[255 - 10];
|
||||||
} __attribute__((packed)) BootloaderReq;
|
} __attribute__((packed)) BootloaderReq;
|
||||||
|
|
||||||
|
|
||||||
@ -49,30 +50,29 @@ static void authorize_application()
|
|||||||
ptr = (uint32_t *)AUTH_WORD_ADDR;
|
ptr = (uint32_t *)AUTH_WORD_ADDR;
|
||||||
flash_write((uint32_t)ptr, (uint8_t *)&zero, 4);
|
flash_write((uint32_t)ptr, (uint8_t *)&zero, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
int is_authorized_to_boot()
|
int is_authorized_to_boot()
|
||||||
{
|
{
|
||||||
uint32_t * auth = (uint32_t *)AUTH_WORD_ADDR;
|
uint32_t * auth = (uint32_t *)AUTH_WORD_ADDR;
|
||||||
return *auth == 0;
|
return *auth == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bootloader_bridge(uint8_t klen, uint8_t * keyh)
|
int bootloader_bridge(int klen, uint8_t * keyh)
|
||||||
{
|
{
|
||||||
static int has_erased = 0;
|
static int has_erased = 0;
|
||||||
BootloaderReq * req = (BootloaderReq * )keyh;
|
BootloaderReq * req = (BootloaderReq * )keyh;
|
||||||
uint8_t payload[256];
|
|
||||||
uint8_t hash[32];
|
uint8_t hash[32];
|
||||||
uint8_t version = 1;
|
uint8_t version = 1;
|
||||||
|
uint16_t len = (req->lenh << 8) | (req->lenl);
|
||||||
|
|
||||||
uint8_t * pubkey = (uint8_t*)"\x85\xaa\xce\xda\xd4\xb4\xd8\x0d\xf7\x0e\xe8\x91\x6d\x69\x8e\x00\x7a\x27\x40\x76\x93\x7a\x1d\x63\xb1\xcf\xe8\x22\xdd\x9f\xbc\x43\x3e\x34\x0a\x05\x9d\x8a\x9d\x72\xdc\xc2\x4b\x56\x9c\x64\x3d\xc1\x0d\x14\x64\x69\x52\x31\xd7\x54\xa3\xb6\x69\xa7\x6f\x6b\x81\x8d";
|
if (len > klen-10)
|
||||||
const struct uECC_Curve_t * curve = NULL;
|
|
||||||
|
|
||||||
if (req->len > 255-9)
|
|
||||||
{
|
{
|
||||||
|
printf1(TAG_BOOT,"Invalid length %d / %d\r\n", len, klen-9);
|
||||||
return CTAP1_ERR_INVALID_LENGTH;
|
return CTAP1_ERR_INVALID_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(payload, 0xff, sizeof(payload));
|
uint8_t * pubkey = (uint8_t*)"\x85\xaa\xce\xda\xd4\xb4\xd8\x0d\xf7\x0e\xe8\x91\x6d\x69\x8e\x00\x7a\x27\x40\x76\x93\x7a\x1d\x63\xb1\xcf\xe8\x22\xdd\x9f\xbc\x43\x3e\x34\x0a\x05\x9d\x8a\x9d\x72\xdc\xc2\x4b\x56\x9c\x64\x3d\xc1\x0d\x14\x64\x69\x52\x31\xd7\x54\xa3\xb6\x69\xa7\x6f\x6b\x81\x8d";
|
||||||
memmove(payload, req->payload, req->len);
|
const struct uECC_Curve_t * curve = NULL;
|
||||||
|
|
||||||
uint32_t addr = ((*((uint32_t*)req->addr)) & 0xffffff) | 0x8000000;
|
uint32_t addr = ((*((uint32_t*)req->addr)) & 0xffffff) | 0x8000000;
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ int bootloader_bridge(uint8_t klen, uint8_t * keyh)
|
|||||||
case BootWrite:
|
case BootWrite:
|
||||||
printf1(TAG_BOOT, "BootWrite: %08lx\r\n",(uint32_t)ptr);
|
printf1(TAG_BOOT, "BootWrite: %08lx\r\n",(uint32_t)ptr);
|
||||||
if ((uint32_t)ptr < APPLICATION_START_ADDR || (uint32_t)ptr >= APPLICATION_END_ADDR
|
if ((uint32_t)ptr < APPLICATION_START_ADDR || (uint32_t)ptr >= APPLICATION_END_ADDR
|
||||||
|| ((uint32_t)ptr+req->len) > APPLICATION_END_ADDR)
|
|| ((uint32_t)ptr+len) > APPLICATION_END_ADDR)
|
||||||
{
|
{
|
||||||
printf1(TAG_BOOT,"Bound exceeded [%08lx, %08lx]\r\n",APPLICATION_START_ADDR,APPLICATION_END_ADDR);
|
printf1(TAG_BOOT,"Bound exceeded [%08lx, %08lx]\r\n",APPLICATION_START_ADDR,APPLICATION_END_ADDR);
|
||||||
return CTAP2_ERR_NOT_ALLOWED;
|
return CTAP2_ERR_NOT_ALLOWED;
|
||||||
@ -99,11 +99,17 @@ int bootloader_bridge(uint8_t klen, uint8_t * keyh)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
flash_write((uint32_t)ptr,payload, req->len);
|
flash_write((uint32_t)ptr,req->payload, len);
|
||||||
break;
|
break;
|
||||||
case BootDone:
|
case BootDone:
|
||||||
printf1(TAG_BOOT, "BootDone: ");
|
printf1(TAG_BOOT, "BootDone: ");
|
||||||
dump_hex1(TAG_BOOT, payload, 32);
|
#ifndef SOLO_HACKER
|
||||||
|
if (len != 64)
|
||||||
|
{
|
||||||
|
printf1(TAG_BOOT,"Invalid length for signature\r\n");
|
||||||
|
return CTAP1_ERR_INVALID_LENGTH;
|
||||||
|
}
|
||||||
|
dump_hex1(TAG_BOOT, req->payload, 32);
|
||||||
ptr = (uint32_t *)APPLICATION_START_ADDR;
|
ptr = (uint32_t *)APPLICATION_START_ADDR;
|
||||||
crypto_sha256_init();
|
crypto_sha256_init();
|
||||||
crypto_sha256_update((uint8_t*)ptr, APPLICATION_END_ADDR-APPLICATION_START_ADDR);
|
crypto_sha256_update((uint8_t*)ptr, APPLICATION_END_ADDR-APPLICATION_START_ADDR);
|
||||||
@ -113,11 +119,12 @@ int bootloader_bridge(uint8_t klen, uint8_t * keyh)
|
|||||||
if (! uECC_verify(pubkey,
|
if (! uECC_verify(pubkey,
|
||||||
hash,
|
hash,
|
||||||
32,
|
32,
|
||||||
payload,
|
req->payload,
|
||||||
curve))
|
curve))
|
||||||
{
|
{
|
||||||
return CTAP2_ERR_OPERATION_DENIED;
|
return CTAP2_ERR_OPERATION_DENIED;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
authorize_application();
|
authorize_application();
|
||||||
REBOOT_FLAG = 1;
|
REBOOT_FLAG = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -70,7 +70,8 @@ int main(int argc, char * argv[])
|
|||||||
/*TAG_U2F|*/
|
/*TAG_U2F|*/
|
||||||
// TAG_PARSE |
|
// TAG_PARSE |
|
||||||
// TAG_TIME|
|
// TAG_TIME|
|
||||||
// TAG_DUMP|
|
// TAG_DUMP|
|
||||||
|
// TAG_DUMP2|
|
||||||
TAG_BOOT|
|
TAG_BOOT|
|
||||||
TAG_EXT|
|
TAG_EXT|
|
||||||
TAG_GREEN|
|
TAG_GREEN|
|
||||||
|
@ -74,7 +74,6 @@ class Tester():
|
|||||||
#cmd,resp = self.recv_raw()
|
#cmd,resp = self.recv_raw()
|
||||||
|
|
||||||
def send_data(self, cmd, data):
|
def send_data(self, cmd, data):
|
||||||
#print('<<', hexlify(data))
|
|
||||||
if type(data) != type(b''):
|
if type(data) != type(b''):
|
||||||
data = struct.pack('%dB' % len(data), *[ord(x) for x in data])
|
data = struct.pack('%dB' % len(data), *[ord(x) for x in data])
|
||||||
with Timeout(1.0) as event:
|
with Timeout(1.0) as event:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Programs solo using the Solo bootloader
|
# Programs solo using the Solo bootloader
|
||||||
# Requires python-fido2, intelhex
|
# Requires python-fido2, intelhex
|
||||||
|
|
||||||
import sys,os,time,struct
|
import sys,os,time,struct,argparse
|
||||||
import array,struct,socket,json,base64
|
import array,struct,socket,json,base64
|
||||||
import tempfile
|
import tempfile
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
@ -10,6 +10,7 @@ from fido2.hid import CtapHidDevice, CTAPHID
|
|||||||
from fido2.client import Fido2Client, ClientError
|
from fido2.client import Fido2Client, ClientError
|
||||||
from fido2.ctap import CtapError
|
from fido2.ctap import CtapError
|
||||||
from fido2.ctap1 import CTAP1
|
from fido2.ctap1 import CTAP1
|
||||||
|
from fido2.utils import Timeout
|
||||||
|
|
||||||
from intelhex import IntelHex
|
from intelhex import IntelHex
|
||||||
|
|
||||||
@ -22,12 +23,26 @@ class SoloBootloader:
|
|||||||
erase = 0x43
|
erase = 0x43
|
||||||
version = 0x44
|
version = 0x44
|
||||||
|
|
||||||
|
HIDCommand = 0x50
|
||||||
|
|
||||||
TAG = b'\x8C\x27\x90\xf6'
|
TAG = b'\x8C\x27\x90\xf6'
|
||||||
|
|
||||||
class Programmer():
|
class Programmer():
|
||||||
|
|
||||||
def __init__(self,):
|
def __init__(self,):
|
||||||
self.origin = 'https://example.org'
|
self.origin = 'https://example.org'
|
||||||
|
self.exchange = self.exchange_hid
|
||||||
|
self.reboot = True
|
||||||
|
|
||||||
|
def use_u2f(self,):
|
||||||
|
self.exchange = self.exchange_u2f
|
||||||
|
|
||||||
|
def use_hid(self,):
|
||||||
|
self.exchange = self.exchange_hid
|
||||||
|
|
||||||
|
def set_reboot(self,val):
|
||||||
|
""" option to reboot after programming """
|
||||||
|
self.reboot = val
|
||||||
|
|
||||||
def find_device(self,):
|
def find_device(self,):
|
||||||
dev = next(CtapHidDevice.list_devices(), None)
|
dev = next(CtapHidDevice.list_devices(), None)
|
||||||
@ -36,16 +51,36 @@ class Programmer():
|
|||||||
self.dev = dev
|
self.dev = dev
|
||||||
self.ctap1 = CTAP1(dev)
|
self.ctap1 = CTAP1(dev)
|
||||||
|
|
||||||
|
if self.exchange == self.exchange_hid:
|
||||||
|
self.send_data_hid(CTAPHID.INIT, '\x11\x11\x11\x11\x11\x11\x11\x11')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def format_request(cmd,addr = 0,data = b'A'*16):
|
def format_request(cmd,addr = 0,data = b'A'*16):
|
||||||
arr = b'\x00'*9
|
arr = b'\x00'*9
|
||||||
addr = struct.pack('<L', addr)
|
addr = struct.pack('<L', addr)
|
||||||
cmd = struct.pack('B', cmd)
|
cmd = struct.pack('B', cmd)
|
||||||
length = struct.pack('B', len(data))
|
length = struct.pack('>H', len(data))
|
||||||
|
|
||||||
return cmd + addr[:3] + SoloBootloader.TAG + length + data
|
return cmd + addr[:3] + SoloBootloader.TAG + length + data
|
||||||
|
|
||||||
def exchange(self,cmd,addr=0,data=b'A'*16):
|
def send_data_hid(self, cmd, data):
|
||||||
|
if type(data) != type(b''):
|
||||||
|
data = struct.pack('%dB' % len(data), *[ord(x) for x in data])
|
||||||
|
with Timeout(1.0) as event:
|
||||||
|
return self.dev.call(cmd, data,event)
|
||||||
|
|
||||||
|
def exchange_hid(self,cmd,addr=0,data=b'A'*16):
|
||||||
|
req = Programmer.format_request(cmd,addr,data)
|
||||||
|
|
||||||
|
data = self.send_data_hid(SoloBootloader.HIDCommand, req)
|
||||||
|
|
||||||
|
ret = data[0]
|
||||||
|
if ret != CtapError.ERR.SUCCESS:
|
||||||
|
raise RuntimeError('Device returned non-success code %02x' % ret)
|
||||||
|
|
||||||
|
return data[1:]
|
||||||
|
|
||||||
|
def exchange_u2f(self,cmd,addr=0,data=b'A'*16):
|
||||||
appid = b'A'*32
|
appid = b'A'*32
|
||||||
chal = b'B'*32
|
chal = b'B'*32
|
||||||
|
|
||||||
@ -77,21 +112,32 @@ class Programmer():
|
|||||||
|
|
||||||
def program_file(self,name):
|
def program_file(self,name):
|
||||||
data = json.loads(open(name,'r').read())
|
data = json.loads(open(name,'r').read())
|
||||||
fw = base64.b64decode(from_websafe(data['firmware']).encode())
|
if name.lower().endswith('.json'):
|
||||||
sig = base64.b64decode(from_websafe(data['signature']).encode())
|
fw = base64.b64decode(from_websafe(data['firmware']).encode())
|
||||||
|
sig = base64.b64decode(from_websafe(data['signature']).encode())
|
||||||
|
ih = IntelHex()
|
||||||
|
tmp = tempfile.NamedTemporaryFile(delete=False)
|
||||||
|
tmp.write(fw)
|
||||||
|
tmp.seek(0)
|
||||||
|
tmp.close()
|
||||||
|
ih.fromfile(tmp.name, format='hex')
|
||||||
|
else:
|
||||||
|
if not name.lower().endswith('.hex'):
|
||||||
|
print('Warning, assuming "%s" is an Intel Hex file.' % name)
|
||||||
|
sig = None
|
||||||
|
ih = IntelHex()
|
||||||
|
ih.fromfile(tmp.name, format='hex')
|
||||||
|
|
||||||
ih = IntelHex()
|
if self.exchange == self.exchange_hid:
|
||||||
tmp = tempfile.NamedTemporaryFile(delete=False)
|
chunk = 2048
|
||||||
tmp.write(fw)
|
else:
|
||||||
tmp.seek(0)
|
chunk = 240
|
||||||
tmp.close()
|
|
||||||
ih.fromfile(tmp.name, format='hex')
|
|
||||||
|
|
||||||
chunk = 240
|
|
||||||
seg = ih.segments()[0]
|
seg = ih.segments()[0]
|
||||||
size = seg[1] - seg[0]
|
size = seg[1] - seg[0]
|
||||||
total = 0
|
total = 0
|
||||||
t1 = time.time()*1000
|
t1 = time.time()*1000
|
||||||
|
print('erasing...')
|
||||||
for i in range(seg[0], seg[1], chunk):
|
for i in range(seg[0], seg[1], chunk):
|
||||||
s = i
|
s = i
|
||||||
e = min(i+chunk,seg[1])
|
e = min(i+chunk,seg[1])
|
||||||
@ -100,23 +146,41 @@ class Programmer():
|
|||||||
total += chunk
|
total += chunk
|
||||||
progress = total/float(size)*100
|
progress = total/float(size)*100
|
||||||
sys.stdout.write('downloading %.2f%%...\r' % progress)
|
sys.stdout.write('downloading %.2f%%...\r' % progress)
|
||||||
sys.stdout.write('downloading 100% \r\n')
|
sys.stdout.write('downloaded 100% \r\n')
|
||||||
t2 = time.time()*1000
|
t2 = time.time()*1000
|
||||||
print('time: %.2f s' % ((t2-t1)/1000.0))
|
print('time: %.2f s' % ((t2-t1)/1000.0))
|
||||||
|
|
||||||
print('Verifying...')
|
print('Verifying...')
|
||||||
self.verify_flash(sig)
|
if sig is not None:
|
||||||
|
self.verify_flash(sig)
|
||||||
|
else:
|
||||||
|
self.verify_flash(b'A'*64)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if len(sys.argv) != 2:
|
|
||||||
print('usage: %s <firmware.json>' % sys.argv[0])
|
parser = argparse.ArgumentParser()
|
||||||
sys.exit(1)
|
parser.add_argument("<firmware>", help = 'firmware file. Either a JSON or hex file. JSON file contains signature while hex does not.')
|
||||||
|
parser.add_argument("--use-hid", action="store_true", help = 'Programs using custom HID command (default). Quicker than using U2F authenticate which is what a browser has to use.')
|
||||||
|
parser.add_argument("--use-u2f", action="store_true", help = 'Programs using U2F authenticate. This is what a web application will use.')
|
||||||
|
parser.add_argument("--no-reset", action="store_true", help = 'Don\'t reset after writing firmware. Stay in bootloader mode.')
|
||||||
|
parser.add_argument("--reset-only", action="store_true", help = 'Don\'t write anything, try to boot without a signature.')
|
||||||
|
args = parser.parse_args()
|
||||||
|
print()
|
||||||
|
|
||||||
p = Programmer()
|
p = Programmer()
|
||||||
p.find_device()
|
p.find_device()
|
||||||
|
|
||||||
|
if args.use_u2f:
|
||||||
|
p.use_u2f()
|
||||||
|
|
||||||
|
if args.no_reset:
|
||||||
|
p.set_reboot(False)
|
||||||
|
|
||||||
print('version is ', p.version())
|
print('version is ', p.version())
|
||||||
|
|
||||||
p.program_file(sys.argv[1])
|
if not args.reset_only:
|
||||||
|
p.program_file(args.__dict__['<firmware>'])
|
||||||
|
else:
|
||||||
|
p.exchange(SoloBootloader.done,0,b'A'*64)
|
||||||
|
@ -425,9 +425,10 @@ function formatBootRequest(cmd, addr, data) {
|
|||||||
array[6] = 0x90;
|
array[6] = 0x90;
|
||||||
array[7] = 0xf6;
|
array[7] = 0xf6;
|
||||||
|
|
||||||
array[8] = data.length & 0xff;
|
array[8] = 0;
|
||||||
|
array[9] = data.length & 0xff;
|
||||||
|
|
||||||
var offset = 9;
|
var offset = 10;
|
||||||
|
|
||||||
var i;
|
var i;
|
||||||
for (i = 0; i < data.length; i++){
|
for (i = 0; i < data.length; i++){
|
||||||
|
Loading…
x
Reference in New Issue
Block a user