python script for progamming via solo bootloader

This commit is contained in:
Conor Patrick 2018-12-03 23:01:51 -05:00
parent 9b4b18e1a4
commit 5a96e82f4d
10 changed files with 144 additions and 15 deletions

View File

@ -27,6 +27,8 @@
#include "log.h" #include "log.h"
#define htonl(x) (((x & 0xff) << 24) | ((x & 0xff00) << 8) \
| ((x & 0xff0000) >> 8) | ((x & 0xff000000) >> 24) )
int is_extension_request(uint8_t * kh, int len) int is_extension_request(uint8_t * kh, int len)
{ {
@ -53,11 +55,11 @@ int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen
uint8_t sig[72]; uint8_t sig[72];
if (extension_needs_atomic_count(klen, keyh)) if (extension_needs_atomic_count(klen, keyh))
{ {
count = ctap_atomic_count(0); count = htonl(ctap_atomic_count(0));
} }
else else
{ {
count = 10; count = htonl(10);
} }
u2f_response_writeback(&up,1); u2f_response_writeback(&up,1);
@ -102,7 +104,8 @@ int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
{ {
rcode = U2F_SW_WRONG_DATA; rcode = U2F_SW_WRONG_DATA;
} }
printf1(TAG_WALLET,"Ignoring U2F request\n"); printf1(TAG_EXT,"Ignoring U2F request\n");
dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl);
goto end; goto end;
} }
else else
@ -110,7 +113,8 @@ int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
if ( ! is_extension_request((uint8_t *) &auth->kh, auth->khl)) // Pin requests if ( ! is_extension_request((uint8_t *) &auth->kh, auth->khl)) // Pin requests
{ {
rcode = U2F_SW_WRONG_PAYLOAD; rcode = U2F_SW_WRONG_PAYLOAD;
printf1(TAG_WALLET,"Ignoring U2F request\n"); printf1(TAG_EXT, "Ignoring U2F request\n");
dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl);
goto end; goto end;
} }
rcode = bridge_u2f_to_extensions(auth->chal, auth->app, auth->khl, (uint8_t*)&auth->kh); rcode = bridge_u2f_to_extensions(auth->chal, auth->app, auth->khl, (uint8_t*)&auth->kh);
@ -118,7 +122,7 @@ int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
} }
else if (req->ins == U2F_VERSION) else if (req->ins == U2F_VERSION)
{ {
printf1(TAG_U2F, "U2F_VERSION\n"); printf1(TAG_EXT, "U2F_VERSION\n");
if (len) if (len)
{ {
rcode = U2F_SW_WRONG_LENGTH; rcode = U2F_SW_WRONG_LENGTH;

View File

@ -61,6 +61,7 @@ struct logtag tagtable[] = {
{TAG_WALLET,"WALLET"}, {TAG_WALLET,"WALLET"},
{TAG_STOR,"STOR"}, {TAG_STOR,"STOR"},
{TAG_BOOT,"BOOT"}, {TAG_BOOT,"BOOT"},
{TAG_BOOT,"EXT"},
}; };

View File

@ -56,6 +56,7 @@ typedef enum
TAG_STOR = (1 << 15), TAG_STOR = (1 << 15),
TAG_DUMP2 = (1 << 16), TAG_DUMP2 = (1 << 16),
TAG_BOOT = (1 << 17), TAG_BOOT = (1 << 17),
TAG_EXT = (1 << 17),
TAG_FILENO = (1<<31) TAG_FILENO = (1<<31)
} LOG_TAG; } LOG_TAG;

View File

@ -22,7 +22,6 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#if DEBUG_LEVEL
void dump_hex(uint8_t * buf, int size) void dump_hex(uint8_t * buf, int size)
{ {
while(size--) while(size--)
@ -31,9 +30,3 @@ void dump_hex(uint8_t * buf, int size)
} }
printf("\n"); printf("\n");
} }
#else
void dump_hex(uint8_t * buf, int size)
{
}
#endif

View File

@ -130,6 +130,7 @@ int bootloader_bridge(uint8_t klen, uint8_t * keyh)
return 0; return 0;
break; break;
case BootVersion: case BootVersion:
has_erased = 0;
printf1(TAG_BOOT, "BootVersion.\r\n"); printf1(TAG_BOOT, "BootVersion.\r\n");
u2f_response_writeback(&version,1); u2f_response_writeback(&version,1);
return 0; return 0;

View File

@ -72,6 +72,7 @@ int main(int argc, char * argv[])
// TAG_TIME| // TAG_TIME|
// TAG_DUMP| // TAG_DUMP|
TAG_BOOT| TAG_BOOT|
TAG_EXT|
TAG_GREEN| TAG_GREEN|
TAG_RED| TAG_RED|
TAG_ERR TAG_ERR
@ -107,7 +108,7 @@ int main(int argc, char * argv[])
memset(hidmsg,0,sizeof(hidmsg)); memset(hidmsg,0,sizeof(hidmsg));
printf1(TAG_GEN,"recv'ing hid msg \n"); printf1(TAG_GEN,"recv'ing hid msg \n");
while(1) while(1)

View File

@ -11,6 +11,11 @@
#define BOOT_TO_DFU 0 #define BOOT_TO_DFU 0
// Uncomment SOLO_HACKKER to Only use level 1 read-out-protection,
// allows booting to ST bootloader or Solo bootloader without any button press,
// Disables signature check in Solo bootloader.
#define SOLO_HACKER
//#define USING_DEV_BOARD //#define USING_DEV_BOARD
//#define ENABLE_U2F_EXTENSIONS //#define ENABLE_U2F_EXTENSIONS

122
tools/programmer.py Normal file
View File

@ -0,0 +1,122 @@
# Programs solo using the Solo bootloader
# Requires python-fido2, intelhex
import sys,os,time,struct
import array,struct,socket,json,base64
import tempfile
from binascii import hexlify
from fido2.hid import CtapHidDevice, CTAPHID
from fido2.client import Fido2Client, ClientError
from fido2.ctap import CtapError
from fido2.ctap1 import CTAP1
from intelhex import IntelHex
from sign_firmware import *
class SoloBootloader:
write = 0x40
done = 0x41
check = 0x42
erase = 0x43
version = 0x44
TAG = b'\x8C\x27\x90\xf6'
class Programmer():
def __init__(self,):
self.origin = 'https://example.org'
def find_device(self,):
dev = next(CtapHidDevice.list_devices(), None)
if not dev:
raise RuntimeError('No FIDO device found')
self.dev = dev
self.ctap1 = CTAP1(dev)
@staticmethod
def format_request(cmd,addr = 0,data = b'A'*16):
arr = b'\x00'*9
addr = struct.pack('<L', addr)
cmd = struct.pack('B', cmd)
length = struct.pack('B', len(data))
return cmd + addr[:3] + SoloBootloader.TAG + length + data
def exchange(self,cmd,addr=0,data=b'A'*16):
appid = b'A'*32
chal = b'B'*32
req = Programmer.format_request(cmd,addr,data)
res = self.ctap1.authenticate(chal,appid, req)
ret = res.signature[0]
if ret != CtapError.ERR.SUCCESS:
raise RuntimeError('Device returned non-success code %02x' % ret)
return res.signature[1:]
def version(self,):
data = self.exchange(SoloBootloader.version)
return data[0]
def write_flash(self,addr,data):
self.exchange(SoloBootloader.write,addr,data)
def verify_flash(self,sig):
"""
Tells device to check signature against application. If it passes,
the application will boot.
Exception raises if signature fails.
"""
self.exchange(SoloBootloader.done,0,sig)
def program_file(self,name):
data = json.loads(open(name,'r').read())
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')
chunk = 240
seg = ih.segments()[0]
size = seg[1] - seg[0]
total = 0
t1 = time.time()*1000
for i in range(seg[0], seg[1], chunk):
s = i
e = min(i+chunk,seg[1])
data = ih.tobinarray(start=i,size = e-s)
self.write_flash(i,data)
total += chunk
progress = total/float(size)*100
sys.stdout.write('downloading %.2f%%...\r' % progress)
sys.stdout.write('downloading 100% \r\n')
t2 = time.time()*1000
print('time: %.2f s' % ((t2-t1)/1000.0))
print('Verifying...')
self.verify_flash(sig)
if __name__ == '__main__':
if len(sys.argv) != 2:
print('usage: %s <firmware.json>' % sys.argv[0])
sys.exit(1)
p = Programmer()
p.find_device()
print('version is ', p.version())
p.program_file(sys.argv[1])

View File

@ -22,6 +22,8 @@ def get_firmware_object(sk_name, hex_file):
fw = base64.b64encode(fw.encode()) fw = base64.b64encode(fw.encode())
fw = to_websafe(fw.decode()) fw = to_websafe(fw.decode())
# start of firmware and the size of the flash region allocated for it.
# TODO put this somewhere else.
START = 0x08008000 START = 0x08008000
END = START + 1024 * 186 - 8 END = START + 1024 * 186 - 8
@ -58,5 +60,3 @@ if __name__ == '__main__':
wfile = open(sys.argv[3],'wb+') wfile = open(sys.argv[3],'wb+')
wfile.write(json.dumps(msg).encode()) wfile.write(json.dumps(msg).encode())
wfile.close() wfile.close()

View File

@ -262,6 +262,7 @@ var CMD = {
boot_done: 0x41, boot_done: 0x41,
boot_check: 0x42, boot_check: 0x42,
boot_erase: 0x43, boot_erase: 0x43,
boot_version: 0x44,
}; };
var PIN = { var PIN = {