2014-03-10 18:24:33 +00:00
|
|
|
#!/usr/bin/python
|
|
|
|
import subprocess
|
|
|
|
import os
|
|
|
|
import json
|
|
|
|
import time
|
|
|
|
import ecdsa
|
|
|
|
import hashlib
|
|
|
|
import binascii
|
|
|
|
from google.protobuf.descriptor_pb2 import FileDescriptorSet
|
|
|
|
|
|
|
|
PROTOBUF_PROTO_DIR=os.environ.get('PROTOBUF_PROTO_DIR', '/usr/include/')
|
|
|
|
TREZOR_PROTO_DIR=os.environ.get('TREZOR_PROTO_DIR', '../protob/')
|
|
|
|
|
|
|
|
def compile_config():
|
|
|
|
cmd = "protoc --python_out=../signer/ -I" + PROTOBUF_PROTO_DIR + " -I./ config.proto"
|
|
|
|
subprocess.check_call(cmd.split(), cwd=TREZOR_PROTO_DIR)
|
|
|
|
|
|
|
|
def parse_json():
|
|
|
|
return json.loads(open('config.json', 'r').read())
|
|
|
|
|
|
|
|
|
|
|
|
def get_compiled_proto():
|
|
|
|
# Compile trezor.proto to binary format
|
|
|
|
pdir = os.path.abspath(TREZOR_PROTO_DIR)
|
|
|
|
pfile = os.path.join(pdir, "messages.proto")
|
|
|
|
cmd = "protoc --include_imports -I" + PROTOBUF_PROTO_DIR + " -I" + pdir + " " + pfile + " -otrezor.bin"
|
|
|
|
|
|
|
|
subprocess.check_call(cmd.split())
|
|
|
|
|
|
|
|
# Load compiled protocol description to string
|
|
|
|
proto = open('trezor.bin', 'r').read()
|
|
|
|
os.unlink('trezor.bin')
|
|
|
|
|
|
|
|
# Parse it into FileDescriptorSet structure
|
|
|
|
compiled = FileDescriptorSet()
|
|
|
|
compiled.ParseFromString(proto)
|
|
|
|
return compiled
|
|
|
|
|
|
|
|
def compose_message(json, proto):
|
|
|
|
import config_pb2
|
|
|
|
|
|
|
|
cfg = config_pb2.Configuration()
|
|
|
|
cfg.valid_until = int(time.time()) + json['valid_days'] * 3600 * 24
|
|
|
|
cfg.wire_protocol.MergeFrom(proto)
|
|
|
|
|
|
|
|
for url in json['whitelist_urls']:
|
|
|
|
cfg.whitelist_urls.append(str(url))
|
|
|
|
|
|
|
|
for url in json['blacklist_urls']:
|
|
|
|
cfg.blacklist_urls.append(str(url))
|
|
|
|
|
|
|
|
for dev in json['known_devices']:
|
|
|
|
desc = cfg.known_devices.add()
|
|
|
|
desc.vendor_id = int(dev[0], 16)
|
|
|
|
desc.product_id = int(dev[1], 16)
|
|
|
|
|
|
|
|
return cfg.SerializeToString()
|
|
|
|
|
2015-03-02 18:16:45 +00:00
|
|
|
def sign_message(data, key):
|
|
|
|
if key.startswith('-----BEGIN'):
|
|
|
|
key = ecdsa.keys.SigningKey.from_pem(key)
|
|
|
|
else:
|
|
|
|
key = ecdsa.keys.SigningKey.from_secret_exponent(secexp = int(key, 16), curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256)
|
2014-03-10 18:24:33 +00:00
|
|
|
|
|
|
|
verify = key.get_verifying_key()
|
|
|
|
print "Verifying key:"
|
|
|
|
print verify.to_pem()
|
|
|
|
|
|
|
|
return key.sign_deterministic(data, hashfunc=hashlib.sha256)
|
|
|
|
|
|
|
|
def pack_datafile(filename, signature, data):
|
|
|
|
if len(signature) != 64:
|
|
|
|
raise Exception("Signature must be 64 bytes long")
|
|
|
|
|
|
|
|
fp = open(filename, 'w')
|
|
|
|
fp.write(binascii.hexlify(signature))
|
|
|
|
fp.write(binascii.hexlify(data))
|
|
|
|
fp.close()
|
|
|
|
|
|
|
|
print "Signature and data stored to", filename
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2015-03-02 18:16:45 +00:00
|
|
|
key = ''
|
|
|
|
print "Paste ECDSA private key (in PEM format or SECEXP format) and press Enter:"
|
2014-03-10 18:24:33 +00:00
|
|
|
while True:
|
|
|
|
inp = raw_input()
|
|
|
|
if inp == '':
|
|
|
|
break
|
|
|
|
|
2015-03-02 18:16:45 +00:00
|
|
|
key += inp + "\n"
|
2014-03-10 18:24:33 +00:00
|
|
|
|
2015-03-02 18:16:45 +00:00
|
|
|
# key = open('sample.key', 'r').read()
|
2014-03-10 18:24:33 +00:00
|
|
|
|
|
|
|
compile_config()
|
|
|
|
json = parse_json()
|
|
|
|
proto = get_compiled_proto()
|
|
|
|
|
|
|
|
data = compose_message(json, proto)
|
2015-03-02 18:16:45 +00:00
|
|
|
signature = sign_message(data, key)
|
2014-03-10 18:24:33 +00:00
|
|
|
|
|
|
|
pack_datafile('config_signed.bin', signature, data)
|