signed update working

pull/39/head
Conor Patrick 2018-12-02 23:31:34 -05:00
rodzic 0c461bb5d8
commit bfa2d2830d
12 zmienionych plików z 116 dodań i 270 usunięć

Wyświetl plik

@ -100,7 +100,7 @@ int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
}
else
{
rcode = U2F_SW_WRONG_DATA;
rcode = U2F_SW_WRONG_DATA;
}
printf1(TAG_WALLET,"Ignoring U2F request\n");
goto end;

Wyświetl plik

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

Wyświetl plik

@ -22,7 +22,7 @@
#ifndef _LOG_H
#define _LOG_H
#include APP_CONFIG
#include APP_CONFIG
#include <stdint.h>
#ifndef DEBUG_LEVEL
@ -55,6 +55,7 @@ typedef enum
TAG_WALLET = (1 << 14),
TAG_STOR = (1 << 15),
TAG_DUMP2 = (1 << 16),
TAG_BOOT = (1 << 17),
TAG_FILENO = (1<<31)
} LOG_TAG;

Wyświetl plik

@ -1,9 +1,9 @@
all:
$(MAKE) -f application.mk -j8
$(MAKE) -f application.mk -j8 solo.hex
boot:
$(MAKE) -f bootloader.mk -j8
$(MAKE) -f bootloader.mk -j8 bootloader.hex
clean:
$(MAKE) -f application.mk clean
@ -14,6 +14,11 @@ flash: solo.hex bootloader.hex
STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
STM32_Programmer_CLI -c port=SWD -halt -d all.hex -rst
flashboot: solo.hex bootloader.hex
python merge_hex.py solo.hex bootloader.hex all.hex
STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
STM32_Programmer_CLI -c port=SWD -halt -d bootloader.hex -rst
bootloader.hex:
echo "You need to build the bootloader first."

Wyświetl plik

@ -105,6 +105,7 @@ int main(int argc, char * argv[])
// TAG_PARSE |
// TAG_TIME|
// TAG_DUMP|
TAG_BOOT|
TAG_GREEN|
TAG_RED|
TAG_ERR
@ -134,7 +135,7 @@ int main(int argc, char * argv[])
usbhid_init();
printf1(TAG_GEN,"init usb\n");
ctaphid_init();
printf1(TAG_GEN,"init ctaphid\n");

Wyświetl plik

@ -19,6 +19,7 @@
#include "ctap.h"
#include "crypto.h"
#include "uECC.h"
#include "u2f.h"
#define PAGE_SIZE 2048
@ -520,7 +521,8 @@ typedef enum
BootDone = 0x41,
BootCheck = 0x42,
BootErase = 0x43,
} WalletOperation;
BootVersion = 0x44,
} BootOperation;
typedef struct {
@ -564,7 +566,9 @@ int bootloader_bridge(uint8_t klen, uint8_t * keyh)
BootloaderReq * req = (BootloaderReq * )keyh;
uint8_t payload[256];
uint8_t hash[32];
uint8_t * pubkey = (uint8_t*)"\x57\xe6\x80\x39\x56\x46\x2f\x0c\x95\xac\x72\x71\xf0\xbc\xe8\x2d\x67\xd0\x59\x29\x2e\x15\x22\x89\x6a\xbd\x3f\x7f\x27\xf3\xc0\xc6\xe2\xd7\x7d\x8a\x9f\xcc\x53\xc5\x91\xb2\x0c\x9c\x3b\x4e\xa4\x87\x31\x67\xb4\xa9\x4b\x0e\x8d\x06\x67\xd8\xc5\xef\x2c\x50\x4a\x55";
uint8_t version = 1;
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";
const struct uECC_Curve_t * curve = NULL;
if (req->len > 255-9)
@ -575,18 +579,20 @@ int bootloader_bridge(uint8_t klen, uint8_t * keyh)
memset(payload, 0xff, sizeof(payload));
memmove(payload, req->payload, req->len);
uint32_t addr = (*((uint32_t*)req->addr)) & 0xffffff;
uint32_t addr = ((*((uint32_t*)req->addr)) & 0xffffff) | 0x8000000;
uint32_t * ptr = (uint32_t *)addr;
switch(req->op){
case BootWrite:
printf1(TAG_BOOT, "BootWrite: %08lx\r\n",(uint32_t)ptr);
if ((uint32_t)ptr < APPLICATION_START_ADDR || (uint32_t)ptr >= APPLICATION_END_ADDR)
{
printf1(TAG_BOOT,"Bound exceeded [%08lx, %08lx]\r\n",APPLICATION_START_ADDR,APPLICATION_END_ADDR);
return CTAP2_ERR_NOT_ALLOWED;
}
if (!has_erased)
if (!has_erased || is_authorized_to_boot())
{
erase_application();
has_erased = 1;
@ -596,12 +602,15 @@ int bootloader_bridge(uint8_t klen, uint8_t * keyh)
printf2(TAG_ERR, "Error, boot check bypassed\n");
exit(1);
}
flash_write((uint32_t)ptr,payload, req->len + (req->len%4));
break;
case BootDone:
printf1(TAG_BOOT, "BootDone: ");
dump_hex1(TAG_BOOT, payload, 32);
ptr = (uint32_t *)APPLICATION_START_ADDR;
crypto_sha256_init();
crypto_sha256_update(ptr, APPLICATION_END_ADDR-APPLICATION_START_ADDR);
crypto_sha256_update((uint8_t*)ptr, APPLICATION_END_ADDR-APPLICATION_START_ADDR);
crypto_sha256_final(hash);
curve = uECC_secp256r1();
@ -620,9 +629,15 @@ int bootloader_bridge(uint8_t klen, uint8_t * keyh)
return 0;
break;
case BootErase:
printf1(TAG_BOOT, "BootErase.\r\n");
erase_application();
return 0;
break;
case BootVersion:
printf1(TAG_BOOT, "BootVersion.\r\n");
u2f_response_writeback(&version,1);
return 0;
break;
default:
return CTAP1_ERR_INVALID_COMMAND;
}

Wyświetl plik

@ -42,8 +42,8 @@ _Min_Stack_Size = 0x400; /* required amount of stack */
MEMORY
{
/* First 32 KB is bootloader */
/*FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 238K-8 [> Leave out 18 Kb at end for data <]*/
FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 206K-8 /* Leave out 18 Kb at end for data */
/*FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 238K-8 [> Leave out 38 Kb at end for data <]*/
FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 186K-8 /* Leave out 38 Kb at end for data */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
SRAM2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
}

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -16,6 +16,8 @@ from ecdsa import SigningKey, NIST256p
import socket,json,base64,ssl,array,binascii
from sign_firmware import *
httpport = 8080
udpport = 8111
@ -41,16 +43,7 @@ if __name__ == '__main__':
print(e)
def to_websafe(data):
data = data.replace('+','-')
data = data.replace('/','_')
data = data.replace('=','')
return data
def from_websafe(data):
data = data.replace('-','+')
data = data.replace('_','/')
return data + '=='[:(3*len(data)) % 4]
def write(data):
msg = from_websafe(data)
@ -81,38 +74,6 @@ def read():
msg = to_websafe(pkt)
return msg
def get_firmware_object():
sk = SigningKey.from_pem(open("signing_key.pem").read())
h = open(HEX_FILE,'r').read()
h = base64.b64encode(h.encode())
h = to_websafe(h.decode())
num_pages = 64
START = 0x4000
END = 2048 * (num_pages - 3) - 4
ih = IntelHex(HEX_FILE)
segs = ih.segments()
arr = ih.tobinarray(start = START, size = END-START)
im_size = END-START
print('im_size: ', im_size)
print('firmware_size: ', len(arr))
byts = (arr).tobytes() if hasattr(arr,'tobytes') else (arr).tostring()
sig = sha256(byts)
print('hash', binascii.hexlify(sig))
sig = sk.sign_digest(sig)
print('sig', binascii.hexlify(sig))
sig = base64.b64encode(sig)
sig = to_websafe(sig.decode())
#msg = {'data': read()}
msg = {'firmware': h, 'signature':sig}
return msg
class UDPBridge(BaseHTTPRequestHandler):
def end_headers (self):
self.send_header('Access-Control-Allow-Origin', '*')
@ -147,7 +108,7 @@ class UDPBridge(BaseHTTPRequestHandler):
self.send_response(200)
self.send_header('Content-type','text/json')
msg = get_firmware_object()
msg = get_firmware_object("signing_key.pem",HEX_FILE)
self.end_headers()
@ -162,7 +123,7 @@ try:
certfile='../web/localhost.crt', server_side=True)
print('Saving signed firmware to firmware.json')
msg = get_firmware_object()
msg = get_firmware_object("signing_key.pem",HEX_FILE)
wfile = open('firmware.json','wb+')
wfile.write(json.dumps(msg).encode())
wfile.close()

Wyświetl plik

@ -0,0 +1,62 @@
import sys
import json,base64,array,binascii
from hashlib import sha256
from ecdsa import SigningKey, NIST256p
from intelhex import IntelHex
def to_websafe(data):
data = data.replace('+','-')
data = data.replace('/','_')
data = data.replace('=','')
return data
def from_websafe(data):
data = data.replace('-','+')
data = data.replace('_','/')
return data + '=='[:(3*len(data)) % 4]
def get_firmware_object(sk_name, hex_file):
sk = SigningKey.from_pem(open(sk_name).read())
fw = open(hex_file,'r').read()
fw = base64.b64encode(fw.encode())
fw = to_websafe(fw.decode())
START = 0x08008000
END = START + 1024 * 186 - 8
ih = IntelHex(hex_file)
segs = ih.segments()
arr = ih.tobinarray(start = START, size = END-START)
im_size = END-START
print('im_size: ', im_size)
print('firmware_size: ', len(arr))
byts = (arr).tobytes() if hasattr(arr,'tobytes') else (arr).tostring()
h = sha256()
h.update(byts)
sig = binascii.unhexlify(h.hexdigest())
print('hash', binascii.hexlify(sig))
sig = sk.sign_digest(sig)
print('sig', binascii.hexlify(sig))
sig = base64.b64encode(sig)
sig = to_websafe(sig.decode())
#msg = {'data': read()}
msg = {'firmware': fw, 'signature':sig}
return msg
if __name__ == '__main__':
if len(sys.argv) != 4:
print('usage: %s <signing-key.pem> <app.hex> <output.json>' % sys.argv[0])
msg = get_firmware_object(sys.argv[1],sys.argv[2])
print('Saving signed firmware to firmware.json')
wfile = open(sys.argv[3],'wb+')
wfile.write(json.dumps(msg).encode())
wfile.close()

Wyświetl plik

@ -174,12 +174,12 @@ function toUTF8Array(str) {
var charcode = str.charCodeAt(i);
if (charcode < 0x80) utf8.push(charcode);
else if (charcode < 0x800) {
utf8.push(0xc0 | (charcode >> 6),
utf8.push(0xc0 | (charcode >> 6),
0x80 | (charcode & 0x3f));
}
else if (charcode < 0xd800 || charcode >= 0xe000) {
utf8.push(0xe0 | (charcode >> 12),
0x80 | ((charcode>>6) & 0x3f),
utf8.push(0xe0 | (charcode >> 12),
0x80 | ((charcode>>6) & 0x3f),
0x80 | (charcode & 0x3f));
}
// surrogate pair
@ -190,9 +190,9 @@ function toUTF8Array(str) {
// 20 bits of 0x0-0xFFFFF into two halves
charcode = 0x10000 + (((charcode & 0x3ff)<<10)
| (str.charCodeAt(i) & 0x3ff));
utf8.push(0xf0 | (charcode >>18),
0x80 | ((charcode>>12) & 0x3f),
0x80 | ((charcode>>6) & 0x3f),
utf8.push(0xf0 | (charcode >>18),
0x80 | ((charcode>>12) & 0x3f),
0x80 | ((charcode>>6) & 0x3f),
0x80 | (charcode & 0x3f));
}
}
@ -386,9 +386,9 @@ function send_msg_u2f(data, func, timeout) {
appId: appid
};
console.log('sign attempt');
window.u2f.sign(appid,chal,[key], function(res){
console.log('res',res);
var d2 = new Date();
t2 = d2.getTime();
if (!res.signatureData)
@ -410,9 +410,6 @@ if (DEVELOPMENT) {
function formatBootRequest(cmd, addr, data) {
var array = new Uint8Array(255);
if (addr == undefined)
addr = 0x8000;
data = data || new Uint8Array(1);
if (data.length > (255 - 9)) {
@ -1078,14 +1075,19 @@ async function handleFirmware(files)
var blocks = MemoryMap.fromHex(resp.firmware);
var addresses = blocks.keys();
console.log(blocks);
console.log(addresses);
var addr = addresses.next();
var chunk_size = 244;
var chunk_size = 240;
while(!addr.done) {
var data = blocks.get(addr.value);
var i;
for (i = 0; i < data.length; i += chunk_size) {
var chunk = data.slice(i,i+chunk_size);
console.log('addr ',addr.value + i);
p = await dev.bootloader_write(addr.value + i, chunk);
console.log('writing',p);
TEST(p.status == 'CTAP1_SUCCESS', 'Device wrote data');
var progress = (((i/data.length) * 100 * 100) | 0)/100;
document.getElementById('progress').textContent = ''+progress+' %';
@ -1501,4 +1503,3 @@ var test;
EC = elliptic.ec
//run_tests()

Wyświetl plik

@ -1,202 +0,0 @@
#!/bin/bash
# Directories
cur=`pwd`
tmp=`mktemp -d`
scriptName=`basename $0`
# Certificate Variables
OUTPATH="./"
VERBOSE=0
DURATION=3650 # 10 years
safeExit() {
if [ -d $tmp ]; then
if [ $VERBOSE -eq 1 ]; then
echo "Removing temporary directory '${tmp}'"
fi
rm -rf $tmp
fi
trap - INT TERM EXIT
exit
}
# Help Screen
help() {
echo -n "${scriptName} [OPTIONS] -c=US --state=California
Generate self-signed TLS certificate using OpenSSL
Options:
-c|--country Country Name (2 letter code)
-s|--state State or Province Name (full name)
-l|--locality Locality Name (eg, city)
-o|--organization Organization Name (eg, company)
-u|--unit Organizational Unit Name (eg, section)
-n|--common-name Common Name (e.g. server FQDN or YOUR name)
-e|--email Email Address
-p|--path Path to output generated keys
-d|--duration Validity duration of the certificate (in days)
-h|--help Display this help and exit
-v|--verbose Verbose output
"
}
# Test output path is valid
testPath() {
if [ ! -d $OUTPATH ]; then
echo "The specified directory \"${OUTPATH}\" does not exist"
exit 1
fi
}
# Process Arguments
while [ "$1" != "" ]; do
PARAM=`echo $1 | awk -F= '{print $1}'`
VALUE=`echo $1 | awk -F= '{print $2}'`
case $PARAM in
-h|--help) help; safeExit ;;
-c|--country) C=$VALUE ;;
-s|--state) ST=$VALUE ;;
-l|--locality) L=$VALUE ;;
-o|--organization) O=$VALUE ;;
-u|--unit) OU=$VALUE ;;
-n|--common-name) CN=$VALUE ;;
-e|--email) emailAddress=$VALUE ;;
-p|--path) OUTPATH=$VALUE; testPath ;;
-d|--duration) DURATION=$VALUE ;;
-v|--verbose) VERBOSE=1 ;;
*) echo "ERROR: unknown parameter \"$PARAM\""; help; exit 1 ;;
esac
shift
done
# Prompt for variables that were not provided in arguments
checkVariables() {
# Country
if [ -z $C ]; then
echo -n "Country Name (2 letter code) [AU]:"
read C
fi
# State
if [ -z $ST ]; then
echo -n "State or Province Name (full name) [Some-State]:"
read ST
fi
# Locality
if [ -z $L ]; then
echo -n "Locality Name (eg, city) []:"
read L
fi
# Organization
if [ -z $O ]; then
echo -n "Organization Name (eg, company) [Internet Widgits Pty Ltd]:"
read O
fi
# Organizational Unit
if [ -z $OU ]; then
echo -n "Organizational Unit Name (eg, section) []:"
read OU
fi
# Common Name
if [ -z $CN ]; then
echo -n "Common Name (e.g. server FQDN or YOUR name) []:"
read CN
fi
# Common Name
if [ -z $emailAddress ]; then
echo -n "Email Address []:"
read emailAddress
fi
}
# Show variable values
showVals() {
echo "Country: ${C}";
echo "State: ${ST}";
echo "Locality: ${L}";
echo "Organization: ${O}";
echo "Organization Unit: ${OU}";
echo "Common Name: ${CN}";
echo "Email: ${emailAddress}";
echo "Output Path: ${OUTPATH}";
echo "Certificate Duration (Days): ${DURATION}";
echo "Verbose: ${VERBOSE}";
}
# Init
init() {
cd $tmp
pwd
}
# Cleanup
cleanup() {
echo "Cleaning up"
cd $cur
rm -rf $tmp
}
buildCsrCnf() {
cat << EOF > ${tmp}/tmp.csr.cnf
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
[dn]
C=${C}
ST=${ST}
L=${L}
O=${O}
OU=${OU}
CN=${CN}
emailAddress=${emailAddress}
EOF
}
buildExtCnf() {
cat << EOF > ${tmp}/v3.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = ${CN}
EOF
}
# Build TLS Certificate
build() {
# Santizie domain name for file name
FILENAME=${CN/\*\./}
# Generate CA key & crt
openssl genrsa -out ${tmp}/tmp.key 2048
openssl req -x509 -new -nodes -key ${tmp}/tmp.key -sha256 -days ${DURATION} -out ${OUTPATH}${FILENAME}_CA.pem -subj "/C=${C}/ST=${ST}/L=${L}/O=${O}/OU=${OU}/CN=${CN}/emailAddress=${emailAddress}"
# CSR Configuration
buildCsrCnf
# Create v3.ext configuration file
buildExtCnf
# Server key
openssl req -new -sha256 -nodes -out ${OUTPATH}${FILENAME}.csr -newkey rsa:2048 -keyout ${OUTPATH}${FILENAME}.key -config <( cat ${tmp}/tmp.csr.cnf )
# Server certificate
openssl x509 -req -in ${OUTPATH}${FILENAME}.csr -CA ${OUTPATH}${FILENAME}_CA.pem -CAkey ${tmp}/tmp.key -CAcreateserial -out ${OUTPATH}${FILENAME}.crt -days ${DURATION} -sha256 -extfile ${tmp}/v3.ext
}
checkVariables
build
# showVals
safeExit