gpg: use new device package (instead of factory)

This commit is contained in:
Roman Zeyde
2016-10-28 10:54:24 +03:00
parent 0f79b5ff2e
commit ca507126d6
3 changed files with 36 additions and 61 deletions

View File

@@ -29,10 +29,10 @@ def run_create(args):
log.warning('NOTE: in order to re-generate the exact same GPG key later, ' log.warning('NOTE: in order to re-generate the exact same GPG key later, '
'run this command with "--time=%d" commandline flag (to set ' 'run this command with "--time=%d" commandline flag (to set '
'the timestamp of the GPG key manually).', args.time) 'the timestamp of the GPG key manually).', args.time)
conn = device.HardwareSigner(user_id=args.user_id, d = device.HardwareSigner(user_id=args.user_id,
curve_name=args.ecdsa_curve) curve_name=args.ecdsa_curve)
verifying_key = conn.pubkey(ecdh=False) verifying_key = d.pubkey(ecdh=False)
decryption_key = conn.pubkey(ecdh=True) decryption_key = d.pubkey(ecdh=True)
if key_exists(args.user_id): # add as subkey if key_exists(args.user_id): # add as subkey
log.info('adding %s GPG subkey for "%s" to existing key', log.info('adding %s GPG subkey for "%s" to existing key',
@@ -48,10 +48,10 @@ def run_create(args):
primary_bytes = keyring.export_public_key(args.user_id) primary_bytes = keyring.export_public_key(args.user_id)
result = encode.create_subkey(primary_bytes=primary_bytes, result = encode.create_subkey(primary_bytes=primary_bytes,
subkey=signing_key, subkey=signing_key,
signer_func=conn.sign) signer_func=d.sign)
result = encode.create_subkey(primary_bytes=result, result = encode.create_subkey(primary_bytes=result,
subkey=encryption_key, subkey=encryption_key,
signer_func=conn.sign) signer_func=d.sign)
else: # add as primary else: # add as primary
log.info('creating new %s GPG primary key for "%s"', log.info('creating new %s GPG primary key for "%s"',
args.ecdsa_curve, args.user_id) args.ecdsa_curve, args.user_id)
@@ -66,10 +66,10 @@ def run_create(args):
result = encode.create_primary(user_id=args.user_id, result = encode.create_primary(user_id=args.user_id,
pubkey=primary, pubkey=primary,
signer_func=conn.sign) signer_func=d.sign)
result = encode.create_subkey(primary_bytes=result, result = encode.create_subkey(primary_bytes=result,
subkey=subkey, subkey=subkey,
signer_func=conn.sign) signer_func=d.sign)
sys.stdout.write(protocol.armor(result, 'PUBLIC KEY BLOCK')) sys.stdout.write(protocol.armor(result, 'PUBLIC KEY BLOCK'))

View File

@@ -1,6 +1,5 @@
"""GPG-agent utilities.""" """GPG-agent utilities."""
import binascii import binascii
import contextlib
import logging import logging
from . import decode, device, keyring, protocol from . import decode, device, keyring, protocol
@@ -37,7 +36,6 @@ def sig_encode(r, s):
return b'(7:sig-val(5:ecdsa(1:r32:' + r + b')(1:s32:' + s + b')))' return b'(7:sig-val(5:ecdsa(1:r32:' + r + b')(1:s32:' + s + b')))'
@contextlib.contextmanager
def open_connection(keygrip_bytes): def open_connection(keygrip_bytes):
""" """
Connect to the device for the specified keygrip. Connect to the device for the specified keygrip.
@@ -54,24 +52,23 @@ def open_connection(keygrip_bytes):
ecdh = (pubkey_dict['algo'] == protocol.ECDH_ALGO_ID) ecdh = (pubkey_dict['algo'] == protocol.ECDH_ALGO_ID)
conn = device.HardwareSigner(user_id, curve_name=curve_name) conn = device.HardwareSigner(user_id, curve_name=curve_name)
with contextlib.closing(conn): pubkey = protocol.PublicKey(
pubkey = protocol.PublicKey( curve_name=curve_name, created=pubkey_dict['created'],
curve_name=curve_name, created=pubkey_dict['created'], verifying_key=conn.pubkey(ecdh=ecdh), ecdh=ecdh)
verifying_key=conn.pubkey(ecdh=ecdh), ecdh=ecdh) assert pubkey.key_id() == pubkey_dict['key_id']
assert pubkey.key_id() == pubkey_dict['key_id'] assert pubkey.keygrip == keygrip_bytes
assert pubkey.keygrip == keygrip_bytes return conn
yield conn
def pksign(keygrip, digest, algo): def pksign(keygrip, digest, algo):
"""Sign a message digest using a private EC key.""" """Sign a message digest using a private EC key."""
log.debug('signing %r digest (algo #%s)', digest, algo) log.debug('signing %r digest (algo #%s)', digest, algo)
keygrip_bytes = binascii.unhexlify(keygrip) keygrip_bytes = binascii.unhexlify(keygrip)
with open_connection(keygrip_bytes) as conn: conn = open_connection(keygrip_bytes)
r, s = conn.sign(binascii.unhexlify(digest)) r, s = conn.sign(binascii.unhexlify(digest))
result = sig_encode(r, s) result = sig_encode(r, s)
log.debug('result: %r', result) log.debug('result: %r', result)
return result return result
def _serialize_point(data): def _serialize_point(data):
@@ -105,8 +102,8 @@ def pkdecrypt(keygrip, conn):
remote_pubkey = parse_ecdh(line) remote_pubkey = parse_ecdh(line)
keygrip_bytes = binascii.unhexlify(keygrip) keygrip_bytes = binascii.unhexlify(keygrip)
with open_connection(keygrip_bytes) as conn: conn = open_connection(keygrip_bytes)
return _serialize_point(conn.ecdh(remote_pubkey)) return _serialize_point(conn.ecdh(remote_pubkey))
def handle_connection(conn): def handle_connection(conn):

View File

@@ -2,7 +2,7 @@
import logging import logging
from .. import factory, formats, util from .. import device, formats, util
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@@ -12,55 +12,33 @@ class HardwareSigner(object):
def __init__(self, user_id, curve_name): def __init__(self, user_id, curve_name):
"""Connect to the device and retrieve required public key.""" """Connect to the device and retrieve required public key."""
self.client_wrapper = factory.load() self.device = device.detect(identity_str='',
self.identity = self.client_wrapper.identity_type() curve_name=curve_name)
self.identity.proto = 'gpg' self.device.identity_dict['proto'] = 'gpg'
self.identity.host = user_id self.device.identity_dict['host'] = user_id
self.curve_name = curve_name
self.user_id = user_id self.user_id = user_id
def pubkey(self, ecdh=False): def pubkey(self, ecdh=False):
"""Return public key as VerifyingKey object.""" """Return public key as VerifyingKey object."""
addr = util.get_bip32_address(identity=self.identity, ecdh=ecdh) with self.device:
if ecdh: pubkey = self.device.pubkey(ecdh=ecdh)
curve_name = formats.get_ecdh_curve_name(self.curve_name)
else:
curve_name = self.curve_name
public_node = self.client_wrapper.connection.get_public_node(
n=addr, ecdsa_curve_name=curve_name)
return formats.decompress_pubkey( return formats.decompress_pubkey(
pubkey=public_node.node.public_key, pubkey=pubkey, curve_name=self.device.curve_name)
curve_name=curve_name)
def sign(self, digest): def sign(self, digest):
"""Sign the digest and return a serialized signature.""" """Sign the digest and return a serialized signature."""
log.info('please confirm GPG signature on %s for "%s"...', log.info('please confirm GPG signature on %s for "%s"...',
self.client_wrapper.device_name, self.user_id) self.device, self.user_id)
if self.curve_name == formats.CURVE_NIST256: if self.device.curve_name == formats.CURVE_NIST256:
digest = digest[:32] # sign the first 256 bits digest = digest[:32] # sign the first 256 bits
log.debug('signing digest: %s', util.hexlify(digest)) log.debug('signing digest: %s', util.hexlify(digest))
result = self.client_wrapper.connection.sign_identity( with self.device:
identity=self.identity, sig = self.device.sign(blob=digest)
challenge_hidden=digest,
challenge_visual='',
ecdsa_curve_name=self.curve_name)
assert result.signature[:1] == b'\x00'
sig = result.signature[1:]
return (util.bytes2num(sig[:32]), util.bytes2num(sig[32:])) return (util.bytes2num(sig[:32]), util.bytes2num(sig[32:]))
def ecdh(self, pubkey): def ecdh(self, pubkey):
"""Derive shared secret using ECDH from remote public key.""" """Derive shared secret using ECDH from remote public key."""
log.info('please confirm GPG decryption on %s for "%s"...', log.info('please confirm GPG decryption on %s for "%s"...',
self.client_wrapper.device_name, self.user_id) self.device, self.user_id)
result = self.client_wrapper.connection.get_ecdh_session_key( with self.device:
identity=self.identity, return self.device.ecdh(pubkey=pubkey)
peer_public_key=pubkey,
ecdsa_curve_name=formats.get_ecdh_curve_name(self.curve_name))
assert len(result.session_key) in {65, 33} # NIST256 or Curve25519
assert result.session_key[:1] == b'\x04'
return result.session_key
def close(self):
"""Close the connection to the device."""
self.client_wrapper.connection.close()