mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-25 15:58:08 +00:00
tools: drop combine_sign; rework keyctl into 3 tools
This commit is contained in:
parent
5ede6864d5
commit
81ff60c3e1
@ -156,7 +156,7 @@ env.Replace(
|
|||||||
|
|
||||||
env.Replace(
|
env.Replace(
|
||||||
BINCTL='tools/binctl',
|
BINCTL='tools/binctl',
|
||||||
COMBINE_SIGN='tools/combine_sign',
|
KEYCTL='tools/keyctl',
|
||||||
)
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -182,5 +182,5 @@ program_bin = env.Command(
|
|||||||
action=[
|
action=[
|
||||||
'$OBJCOPY -O binary -j .header -j .flash -j .data $SOURCE $TARGET',
|
'$OBJCOPY -O binary -j .header -j .flash -j .data $SOURCE $TARGET',
|
||||||
'$BINCTL $TARGET -h',
|
'$BINCTL $TARGET -h',
|
||||||
'$BINCTL $TARGET -s 1:2 `$COMBINE_SIGN bootloader $TARGET 4141414141414141414141414141414141414141414141414141414141414141 4242424242424242424242424242424242424242424242424242424242424242`',
|
'$BINCTL $TARGET -s 1:2 `$KEYCTL sign bootloader $TARGET 4141414141414141414141414141414141414141414141414141414141414141 4242424242424242424242424242424242424242424242424242424242424242`',
|
||||||
], )
|
], )
|
||||||
|
@ -336,7 +336,7 @@ env.Replace(
|
|||||||
|
|
||||||
env.Replace(
|
env.Replace(
|
||||||
BINCTL='tools/binctl',
|
BINCTL='tools/binctl',
|
||||||
COMBINE_SIGN='tools/combine_sign',
|
KEYCTL='tools/keyctl',
|
||||||
PYTHON='python',
|
PYTHON='python',
|
||||||
MAKEQSTRDATA='$PYTHON vendor/micropython/py/makeqstrdata.py',
|
MAKEQSTRDATA='$PYTHON vendor/micropython/py/makeqstrdata.py',
|
||||||
MAKEVERSIONHDR='$PYTHON vendor/micropython/py/makeversionhdr.py',
|
MAKEVERSIONHDR='$PYTHON vendor/micropython/py/makeversionhdr.py',
|
||||||
@ -418,5 +418,5 @@ program_bin = env.Command(
|
|||||||
action=[
|
action=[
|
||||||
'$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data $SOURCE $TARGET',
|
'$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data $SOURCE $TARGET',
|
||||||
'$BINCTL $TARGET -h',
|
'$BINCTL $TARGET -h',
|
||||||
'$BINCTL $TARGET -s 1:2 `$COMBINE_SIGN firmware $TARGET 4747474747474747474747474747474747474747474747474747474747474747 4848484848484848484848484848484848484848484848484848484848484848`',
|
'$BINCTL $TARGET -s 1:2 `$KEYCTL sign firmware $TARGET 4747474747474747474747474747474747474747474747474747474747474747 4848484848484848484848484848484848484848484848484848484848484848`',
|
||||||
], )
|
], )
|
||||||
|
@ -120,7 +120,7 @@ env.Replace(
|
|||||||
|
|
||||||
env.Replace(
|
env.Replace(
|
||||||
BINCTL='tools/binctl',
|
BINCTL='tools/binctl',
|
||||||
COMBINE_SIGN='tools/combine_sign',
|
KEYCTL='tools/keyctl',
|
||||||
)
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -154,5 +154,5 @@ program_bin = env.Command(
|
|||||||
action=[
|
action=[
|
||||||
'$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data $SOURCE $TARGET',
|
'$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data $SOURCE $TARGET',
|
||||||
'$BINCTL $TARGET -h',
|
'$BINCTL $TARGET -h',
|
||||||
'$BINCTL $TARGET -s 1:2 `$COMBINE_SIGN firmware $TARGET 4747474747474747474747474747474747474747474747474747474747474747 4848484848484848484848484848484848484848484848484848484848484848`',
|
'$BINCTL $TARGET -s 1:2 `$KEYCTL sign firmware $TARGET 4747474747474747474747474747474747474747474747474747474747474747 4848484848484848484848484848484848484848484848484848484848484848`',
|
||||||
], )
|
], )
|
||||||
|
@ -120,7 +120,7 @@ env.Replace(
|
|||||||
|
|
||||||
env.Replace(
|
env.Replace(
|
||||||
BINCTL='tools/binctl',
|
BINCTL='tools/binctl',
|
||||||
COMBINE_SIGN='tools/combine_sign',
|
KEYCTL='tools/keyctl',
|
||||||
)
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -154,5 +154,5 @@ program_bin = env.Command(
|
|||||||
action=[
|
action=[
|
||||||
'$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data $SOURCE $TARGET',
|
'$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data $SOURCE $TARGET',
|
||||||
'$BINCTL $TARGET -h',
|
'$BINCTL $TARGET -h',
|
||||||
'$BINCTL $TARGET -s 1:2 `$COMBINE_SIGN firmware $TARGET 4747474747474747474747474747474747474747474747474747474747474747 4848484848484848484848484848484848484848484848484848484848484848`',
|
'$BINCTL $TARGET -s 1:2 `$KEYCTL sign firmware $TARGET 4747474747474747474747474747474747474747474747474747474747474747 4848484848484848484848484848484848484848484848484848484848484848`',
|
||||||
], )
|
], )
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
TOOLDIR=$(dirname $0)
|
|
||||||
|
|
||||||
TYPE=$1
|
|
||||||
FILE=$2
|
|
||||||
shift
|
|
||||||
shift
|
|
||||||
SECKEYS=$*
|
|
||||||
|
|
||||||
COMMITS=""
|
|
||||||
|
|
||||||
for seckey in $SECKEYS; do
|
|
||||||
commit=$( $TOOLDIR/keyctl commit $TYPE $FILE $seckey )
|
|
||||||
COMMITS="$COMMITS $commit"
|
|
||||||
done
|
|
||||||
|
|
||||||
global_commit=$( $TOOLDIR/keyctl global_commit $COMMITS )
|
|
||||||
|
|
||||||
SIGS=""
|
|
||||||
|
|
||||||
for seckey in $SECKEYS; do
|
|
||||||
sig=$( $TOOLDIR/keyctl sign $TYPE $FILE $global_commit $seckey )
|
|
||||||
SIGS="$SIGS $sig"
|
|
||||||
done
|
|
||||||
|
|
||||||
$TOOLDIR/keyctl global_sign $TYPE $FILE $global_commit $SIGS
|
|
121
tools/keyctl
121
tools/keyctl
@ -1,13 +1,10 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import binascii
|
import binascii
|
||||||
|
import struct
|
||||||
import click
|
import click
|
||||||
import pyblake2
|
import pyblake2
|
||||||
import struct
|
|
||||||
|
|
||||||
from trezorlib import ed25519raw, ed25519cosi
|
from trezorlib import ed25519raw, ed25519cosi
|
||||||
|
|
||||||
|
|
||||||
indexmap = {
|
indexmap = {
|
||||||
'bootloader': 0,
|
'bootloader': 0,
|
||||||
'vendorheader': 1,
|
'vendorheader': 1,
|
||||||
@ -15,31 +12,19 @@ indexmap = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_trezor():
|
def header_digest(index, filename):
|
||||||
from trezorlib.client import TrezorClient
|
data = open(filename, 'rb').read()
|
||||||
from trezorlib.transport_hid import HidTransport
|
|
||||||
devices = HidTransport.enumerate()
|
|
||||||
if len(devices) > 0:
|
|
||||||
return TrezorClient(devices[0])
|
|
||||||
else:
|
|
||||||
raise Exception('No TREZOR found')
|
|
||||||
|
|
||||||
|
|
||||||
def header_to_sign(index, data):
|
|
||||||
z = bytes(65 * [0x00])
|
z = bytes(65 * [0x00])
|
||||||
if index == 'bootloader':
|
if index == 'bootloader':
|
||||||
return data[:0x03BF] + z
|
header = data[:0x03BF] + z
|
||||||
elif index == 'vendorheader':
|
elif index == 'vendorheader':
|
||||||
return data[:-65] + z
|
header = data[:-65] + z
|
||||||
elif index == 'firmware':
|
elif index == 'firmware':
|
||||||
vhdrlen = struct.unpack('<I', data[4:8])[0]
|
vhdrlen = struct.unpack('<I', data[4:8])[0]
|
||||||
return data[vhdrlen:vhdrlen + 0x03BF] + z
|
header = data[vhdrlen:vhdrlen + 0x03BF] + z
|
||||||
else:
|
else:
|
||||||
raise ValueError('Unknown index "%s"' % index)
|
raise ValueError('Unknown index "%s"' % index)
|
||||||
|
return pyblake2.blake2s(header).digest()
|
||||||
|
|
||||||
def get_path(index):
|
|
||||||
return "10018'/%d'" % indexmap[index]
|
|
||||||
|
|
||||||
|
|
||||||
@click.group()
|
@click.group()
|
||||||
@ -47,65 +32,27 @@ def cli():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@cli.command(help='')
|
|
||||||
@click.argument('index', type=click.Choice(indexmap.keys()))
|
|
||||||
def getkey(index):
|
|
||||||
t = get_trezor()
|
|
||||||
path = get_path(index)
|
|
||||||
node = t.get_public_node(t.expand_path(path), ecdsa_curve_name='ed25519').node
|
|
||||||
print('%s' % (binascii.hexlify(node.public_key[1:]).decode()))
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command(help='')
|
@cli.command(help='')
|
||||||
@click.argument('index', type=click.Choice(indexmap.keys()))
|
@click.argument('index', type=click.Choice(indexmap.keys()))
|
||||||
@click.argument('filename')
|
@click.argument('filename')
|
||||||
@click.argument('seckey', required=False)
|
@click.argument('seckeys', nargs=-1)
|
||||||
def commit(index, filename, seckey):
|
def sign(index, filename, seckeys):
|
||||||
data = open(filename, 'rb').read()
|
# compute header digest
|
||||||
data = header_to_sign(index, data)
|
digest = header_digest(index, filename)
|
||||||
digest = pyblake2.blake2s(data).digest()
|
# collect commits
|
||||||
ctr = 0
|
pks, Rs = [], []
|
||||||
if seckey:
|
for ctr, seckey in enumerate(seckeys):
|
||||||
sk = binascii.unhexlify(seckey)
|
sk = binascii.unhexlify(seckey)
|
||||||
pk = ed25519raw.publickey(sk)
|
pk = ed25519raw.publickey(sk)
|
||||||
_, R = ed25519cosi.get_nonce(sk, digest, ctr)
|
_, R = ed25519cosi.get_nonce(sk, digest, ctr)
|
||||||
else:
|
pks.append(pk)
|
||||||
t = get_trezor()
|
Rs.append(R)
|
||||||
path = get_path(index)
|
# compute global commit
|
||||||
print('commiting to hash %s with path %s' % (binascii.hexlify(digest).decode(), path))
|
global_pk = ed25519cosi.combine_keys(pks)
|
||||||
commit = t.cosi_commit(t.expand_path(path), digest)
|
global_R = ed25519cosi.combine_keys(Rs)
|
||||||
pk = commit.pubkey
|
# collect signatures
|
||||||
R = commit.commitment
|
sigs = []
|
||||||
print('%s+%s' % (binascii.hexlify(pk).decode(), binascii.hexlify(R).decode()))
|
for ctr, seckey in enumerate(seckeys):
|
||||||
|
|
||||||
|
|
||||||
@cli.command(help='')
|
|
||||||
@click.argument('commits', nargs=-1)
|
|
||||||
def global_commit(commits):
|
|
||||||
if len(commits) < 1:
|
|
||||||
raise Exception('Need to provide at least one commit')
|
|
||||||
pk, R = [], []
|
|
||||||
for c in commits:
|
|
||||||
a, b = c.split('+')
|
|
||||||
pk.append(binascii.unhexlify(a))
|
|
||||||
R.append(binascii.unhexlify(b))
|
|
||||||
global_pk = ed25519cosi.combine_keys(pk)
|
|
||||||
global_R = ed25519cosi.combine_keys(R)
|
|
||||||
print('%s+%s' % (binascii.hexlify(global_pk).decode(), binascii.hexlify(global_R).decode()))
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command(help='')
|
|
||||||
@click.argument('index', type=click.Choice(indexmap.keys()))
|
|
||||||
@click.argument('filename')
|
|
||||||
@click.argument('global_commit')
|
|
||||||
@click.argument('seckey', required=False)
|
|
||||||
def sign(index, filename, global_commit, seckey):
|
|
||||||
data = open(filename, 'rb').read()
|
|
||||||
data = header_to_sign(index, data)
|
|
||||||
digest = pyblake2.blake2s(data).digest()
|
|
||||||
global_pk, global_R = [binascii.unhexlify(x) for x in global_commit.split('+')]
|
|
||||||
ctr = 0
|
|
||||||
if seckey:
|
|
||||||
sk = binascii.unhexlify(seckey)
|
sk = binascii.unhexlify(seckey)
|
||||||
r, _ = ed25519cosi.get_nonce(sk, digest, ctr)
|
r, _ = ed25519cosi.get_nonce(sk, digest, ctr)
|
||||||
h = ed25519raw.H(sk)
|
h = ed25519raw.H(sk)
|
||||||
@ -113,27 +60,9 @@ def sign(index, filename, global_commit, seckey):
|
|||||||
a = 2 ** (b - 2) + sum(2 ** i * ed25519raw.bit(h, i) for i in range(3, b - 2))
|
a = 2 ** (b - 2) + sum(2 ** i * ed25519raw.bit(h, i) for i in range(3, b - 2))
|
||||||
S = (r + ed25519raw.Hint(global_R + global_pk + digest) * a) % ed25519raw.l
|
S = (r + ed25519raw.Hint(global_R + global_pk + digest) * a) % ed25519raw.l
|
||||||
sig = ed25519raw.encodeint(S)
|
sig = ed25519raw.encodeint(S)
|
||||||
else:
|
sigs.append(sig)
|
||||||
t = get_trezor()
|
# compute global signature
|
||||||
path = get_path(index)
|
sig = ed25519cosi.combine_sig(global_R, sigs)
|
||||||
print('signing hash %s with path %s' % (binascii.hexlify(digest).decode(), path))
|
|
||||||
signature = t.cosi_sign(t.expand_path(path), digest, global_R, global_pk)
|
|
||||||
sig = signature.signature
|
|
||||||
print(binascii.hexlify(sig).decode())
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command(help='')
|
|
||||||
@click.argument('index', type=click.Choice(indexmap.keys()))
|
|
||||||
@click.argument('filename')
|
|
||||||
@click.argument('global_commit')
|
|
||||||
@click.argument('signatures', nargs=-1)
|
|
||||||
def global_sign(index, filename, global_commit, signatures):
|
|
||||||
data = open(filename, 'rb').read()
|
|
||||||
data = header_to_sign(index, data)
|
|
||||||
digest = pyblake2.blake2s(data).digest()
|
|
||||||
global_pk, global_R = [binascii.unhexlify(x) for x in global_commit.split('+')]
|
|
||||||
signatures = [binascii.unhexlify(x) for x in signatures]
|
|
||||||
sig = ed25519cosi.combine_sig(global_R, signatures)
|
|
||||||
ed25519raw.checkvalid(sig, digest, global_pk)
|
ed25519raw.checkvalid(sig, digest, global_pk)
|
||||||
print(binascii.hexlify(sig).decode())
|
print(binascii.hexlify(sig).decode())
|
||||||
|
|
||||||
|
76
tools/keyctl-coordinator
Executable file
76
tools/keyctl-coordinator
Executable file
@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import binascii
|
||||||
|
import struct
|
||||||
|
import click
|
||||||
|
import pyblake2
|
||||||
|
import Pyro4
|
||||||
|
import serpent
|
||||||
|
from trezorlib import ed25519raw, ed25519cosi
|
||||||
|
|
||||||
|
PORT = 5001
|
||||||
|
indexmap = {
|
||||||
|
'bootloader': 0,
|
||||||
|
'vendorheader': 1,
|
||||||
|
'firmware': 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def header_digest(index, filename):
|
||||||
|
data = open(filename, 'rb').read()
|
||||||
|
z = bytes(65 * [0x00])
|
||||||
|
if index == 'bootloader':
|
||||||
|
header = data[:0x03BF] + z
|
||||||
|
elif index == 'vendorheader':
|
||||||
|
header = data[:-65] + z
|
||||||
|
elif index == 'firmware':
|
||||||
|
vhdrlen = struct.unpack('<I', data[4:8])[0]
|
||||||
|
header = data[vhdrlen:vhdrlen + 0x03BF] + z
|
||||||
|
else:
|
||||||
|
raise ValueError('Unknown index "%s"' % index)
|
||||||
|
return pyblake2.blake2s(header).digest()
|
||||||
|
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
def cli():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command(help='')
|
||||||
|
@click.argument('index', type=click.Choice(indexmap.keys()))
|
||||||
|
@click.argument('filename')
|
||||||
|
@click.argument('participants', nargs=-1)
|
||||||
|
def sign(index, filename, participants):
|
||||||
|
# compute header digest
|
||||||
|
digest = header_digest(index, filename)
|
||||||
|
# create participant proxies
|
||||||
|
if len(participants) < 1:
|
||||||
|
raise ValueError('Not enough participants')
|
||||||
|
print('connecting to %d participants:' % len(participants))
|
||||||
|
proxy = []
|
||||||
|
for p in participants:
|
||||||
|
uri = 'PYRO:keyctl@%s:%d' % (p, PORT)
|
||||||
|
proxy.append(Pyro4.Proxy(uri))
|
||||||
|
# collect commits
|
||||||
|
pks, Rs = [], []
|
||||||
|
for p in proxy:
|
||||||
|
pk, R = p.get_commit(index, digest)
|
||||||
|
pk, R = serpent.tobytes(pk), serpent.tobytes(R)
|
||||||
|
pks.append(pk)
|
||||||
|
Rs.append(R)
|
||||||
|
# compute global commit
|
||||||
|
global_pk = ed25519cosi.combine_keys(pks)
|
||||||
|
global_R = ed25519cosi.combine_keys(Rs)
|
||||||
|
# collect signatures
|
||||||
|
sigs = []
|
||||||
|
for p in proxy:
|
||||||
|
sig = p.get_signature(index, digest, global_R, global_pk)
|
||||||
|
sig = serpent.tobytes(sig)
|
||||||
|
sigs.append(sig)
|
||||||
|
# compute global signature
|
||||||
|
sig = ed25519cosi.combine_sig(global_R, sigs)
|
||||||
|
ed25519raw.checkvalid(sig, digest, global_pk)
|
||||||
|
print(binascii.hexlify(sig).decode())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
cli()
|
67
tools/keyctl-proxy
Executable file
67
tools/keyctl-proxy
Executable file
@ -0,0 +1,67 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import binascii
|
||||||
|
import sys
|
||||||
|
import netifaces
|
||||||
|
import Pyro4
|
||||||
|
import serpent
|
||||||
|
|
||||||
|
PORT = 5001
|
||||||
|
indexmap = {
|
||||||
|
'bootloader': 0,
|
||||||
|
'vendorheader': 1,
|
||||||
|
'firmware': 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_trezor():
|
||||||
|
from trezorlib.client import TrezorClient
|
||||||
|
from trezorlib.transport_hid import HidTransport
|
||||||
|
devices = HidTransport.enumerate()
|
||||||
|
if len(devices) > 0:
|
||||||
|
return TrezorClient(devices[0])
|
||||||
|
else:
|
||||||
|
raise Exception('No TREZOR found')
|
||||||
|
|
||||||
|
|
||||||
|
def get_path(index):
|
||||||
|
return "10018'/%d'" % indexmap[index]
|
||||||
|
|
||||||
|
|
||||||
|
@Pyro4.expose
|
||||||
|
class KeyctlProxy(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(KeyctlProxy, self).__init__()
|
||||||
|
|
||||||
|
def get_commit(self, index, digest):
|
||||||
|
digest = serpent.tobytes(digest)
|
||||||
|
t = get_trezor()
|
||||||
|
path = get_path(index)
|
||||||
|
print('commiting to hash %s with path %s' % (binascii.hexlify(digest).decode(), path))
|
||||||
|
commit = t.cosi_commit(t.expand_path(path), digest)
|
||||||
|
pk = commit.pubkey
|
||||||
|
R = commit.commitment
|
||||||
|
return (pk, R)
|
||||||
|
|
||||||
|
def get_signature(self, index, digest, global_R, global_pk):
|
||||||
|
digest, global_R, global_pk = serpent.tobytes(digest), serpent.tobytes(global_R), serpent.tobytes(global_pk)
|
||||||
|
t = get_trezor()
|
||||||
|
path = get_path(index)
|
||||||
|
print('signing hash %s with path %s' % (binascii.hexlify(digest).decode(), path))
|
||||||
|
signature = t.cosi_sign(t.expand_path(path), digest, global_R, global_pk)
|
||||||
|
sig = signature.signature
|
||||||
|
return sig
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
iface = sys.argv[1]
|
||||||
|
else:
|
||||||
|
print('Usage: keyctl-proxy interface')
|
||||||
|
sys.exit(1)
|
||||||
|
host = netifaces.ifaddresses(iface)[netifaces.AF_INET][0]['addr']
|
||||||
|
daemon = Pyro4.Daemon(host=host, port=PORT)
|
||||||
|
proxy = KeyctlProxy()
|
||||||
|
uri = daemon.register(proxy, 'keyctl')
|
||||||
|
print('keyctl-proxy running at URI: "%s"' % uri)
|
||||||
|
daemon.requestLoop()
|
Loading…
Reference in New Issue
Block a user