HACK: create subkey with ECDH support

This commit is contained in:
Roman Zeyde
2016-06-02 22:54:01 +03:00
parent 7da7f5c256
commit 49c343df94
3 changed files with 43 additions and 24 deletions

View File

@@ -16,7 +16,7 @@ def run_create(args):
"""Generate a new pubkey for a new/existing GPG identity.""" """Generate a new pubkey for a new/existing GPG identity."""
user_id = os.environ['TREZOR_GPG_USER_ID'] user_id = os.environ['TREZOR_GPG_USER_ID']
f = encode.Factory(user_id=user_id, created=args.time, f = encode.Factory(user_id=user_id, created=args.time,
curve_name=args.ecdsa_curve) curve_name=args.ecdsa_curve, ecdh=args.ecdh)
with contextlib.closing(f): with contextlib.closing(f):
if args.subkey: if args.subkey:
@@ -38,6 +38,7 @@ def main():
create = subparsers.add_parser('create') create = subparsers.add_parser('create')
create.add_argument('-s', '--subkey', action='store_true', default=False) create.add_argument('-s', '--subkey', action='store_true', default=False)
create.add_argument('--ecdh', action='store_true', default=False)
create.add_argument('-e', '--ecdsa-curve', default='nist256p1') create.add_argument('-e', '--ecdsa-curve', default='nist256p1')
create.add_argument('-t', '--time', type=int, default=int(time.time())) create.add_argument('-t', '--time', type=int, default=int(time.time()))
create.set_defaults(run=run_create) create.set_defaults(run=run_create)

View File

@@ -71,7 +71,7 @@ def _time_format(t):
class Factory(object): class Factory(object):
"""Performs GPG signing operations.""" """Performs GPG signing operations."""
def __init__(self, user_id, created, curve_name): def __init__(self, user_id, created, curve_name, ecdh=False):
"""Construct and loads a public key from the device.""" """Construct and loads a public key from the device."""
self.user_id = user_id self.user_id = user_id
assert curve_name in formats.SUPPORTED_CURVES assert curve_name in formats.SUPPORTED_CURVES
@@ -79,7 +79,8 @@ class Factory(object):
self.conn = HardwareSigner(user_id, curve_name=curve_name) self.conn = HardwareSigner(user_id, curve_name=curve_name)
self.pubkey = proto.PublicKey( self.pubkey = proto.PublicKey(
curve_name=curve_name, created=created, curve_name=curve_name, created=created,
verifying_key=self.conn.pubkey()) verifying_key=self.conn.pubkey(), ecdh=ecdh)
self.ecdh = ecdh
log.info('%s created at %s for "%s"', log.info('%s created at %s for "%s"',
self.pubkey, _time_format(self.pubkey.created), user_id) self.pubkey, _time_format(self.pubkey.created), user_id)
@@ -142,28 +143,38 @@ class Factory(object):
self.user_id, util.hexlify(primary['key_id'])) self.user_id, util.hexlify(primary['key_id']))
data_to_sign = primary['_to_hash'] + self.pubkey.data_to_hash() data_to_sign = primary['_to_hash'] + self.pubkey.data_to_hash()
# Primary Key Binding Signature if self.ecdh:
hashed_subpackets = [ embedded_sig = None
proto.subpacket_time(self.pubkey.created)] # signature time else:
unhashed_subpackets = [ # Primary Key Binding Signature
proto.subpacket(16, self.pubkey.key_id())] # issuer key id hashed_subpackets = [
log.info('confirm signing subkey with hardware device') proto.subpacket_time(self.pubkey.created)] # signature time
embedded_sig = proto.make_signature( unhashed_subpackets = [
signer_func=self.conn.sign, proto.subpacket(16, self.pubkey.key_id())] # issuer key id
data_to_sign=data_to_sign, log.info('confirm signing subkey with hardware device')
public_algo=self.pubkey.algo_id, embedded_sig = proto.make_signature(
sig_type=0x19, signer_func=self.conn.sign,
hashed_subpackets=hashed_subpackets, data_to_sign=data_to_sign,
unhashed_subpackets=unhashed_subpackets) public_algo=self.pubkey.algo_id,
sig_type=0x19,
hashed_subpackets=hashed_subpackets,
unhashed_subpackets=unhashed_subpackets)
# Subkey Binding Signature # Subkey Binding Signature
flags = 2 # key flags (certify & sign)
if self.ecdh:
flags = 4 | 8
hashed_subpackets = [ hashed_subpackets = [
proto.subpacket_time(self.pubkey.created), # signature time proto.subpacket_time(self.pubkey.created), # signature time
proto.subpacket_byte(0x1B, 2)] # key flags (certify & sign) proto.subpacket_byte(0x1B, flags)]
unhashed_subpackets = [
proto.subpacket(16, primary['key_id']), # issuer key id unhashed_subpackets = []
proto.subpacket(32, embedded_sig), unhashed_subpackets.append(proto.subpacket(16, primary['key_id']))
proto.CUSTOM_SUBPACKET] if embedded_sig is not None:
unhashed_subpackets.append(proto.subpacket(32, embedded_sig))
unhashed_subpackets.append(proto.CUSTOM_SUBPACKET)
log.info('confirm signing subkey with gpg-agent') log.info('confirm signing subkey with gpg-agent')
gpg_agent = AgentSigner(self.user_id) gpg_agent = AgentSigner(self.user_id)
signature = proto.make_signature( signature = proto.make_signature(

View File

@@ -131,6 +131,7 @@ SUPPORTED_CURVES = {
} }
} }
ECDH_ALGO_ID = 18
CUSTOM_SUBPACKET = subpacket(100, b'TREZOR-GPG') # marks "our" pubkey CUSTOM_SUBPACKET = subpacket(100, b'TREZOR-GPG') # marks "our" pubkey
@@ -145,12 +146,18 @@ def find_curve_by_algo_id(algo_id):
class PublicKey(object): class PublicKey(object):
"""GPG representation for public key packets.""" """GPG representation for public key packets."""
def __init__(self, curve_name, created, verifying_key): def __init__(self, curve_name, created, verifying_key, ecdh=False):
"""Contruct using a ECDSA VerifyingKey object.""" """Contruct using a ECDSA VerifyingKey object."""
self.curve_info = SUPPORTED_CURVES[curve_name] self.curve_info = SUPPORTED_CURVES[curve_name]
self.created = int(created) # time since Epoch self.created = int(created) # time since Epoch
self.verifying_key = verifying_key self.verifying_key = verifying_key
self.algo_id = self.curve_info['algo_id'] if ecdh:
self.algo_id = ECDH_ALGO_ID
self.ecdh_packet = b'\x03\x01\x08\x07'
else:
self.algo_id = self.curve_info['algo_id']
self.ecdh_packet = b''
self.keygrip = self.curve_info['keygrip'](verifying_key) self.keygrip = self.curve_info['keygrip'](verifying_key)
hex_key_id = util.hexlify(self.key_id())[-8:] hex_key_id = util.hexlify(self.key_id())[-8:]
self.desc = 'GPG public key {}/{}'.format(curve_name, hex_key_id) self.desc = 'GPG public key {}/{}'.format(curve_name, hex_key_id)
@@ -163,7 +170,7 @@ class PublicKey(object):
self.algo_id) # public key algorithm ID self.algo_id) # public key algorithm ID
oid = util.prefix_len('>B', self.curve_info['oid']) oid = util.prefix_len('>B', self.curve_info['oid'])
blob = self.curve_info['serialize'](self.verifying_key) blob = self.curve_info['serialize'](self.verifying_key)
return header + oid + blob return header + oid + blob + self.ecdh_packet
def data_to_hash(self): def data_to_hash(self):
"""Data for digest computation.""" """Data for digest computation."""