gpg: rename main API

This commit is contained in:
Roman Zeyde
2016-05-21 17:25:01 +03:00
parent f626d34e21
commit ee4bcddd22
3 changed files with 61 additions and 62 deletions

View File

@@ -56,11 +56,6 @@ class AgentSigner(object):
"""Connect to the agent and retrieve required public key.""" """Connect to the agent and retrieve required public key."""
self.sock = agent.connect() self.sock = agent.connect()
self.keygrip = agent.get_keygrip(user_id) self.keygrip = agent.get_keygrip(user_id)
self.public_key = decode.load_from_gpg(user_id)
def pubkey(self):
"""Return public key as VerifyingKey object."""
return self.public_key['verifying_key']
def sign(self, digest): def sign(self, digest):
"""Sign the digest and return an ECDSA signature.""" """Sign the digest and return an ECDSA signature."""
@@ -77,7 +72,7 @@ def _time_format(t):
return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(t)) return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(t))
class Signer(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):
@@ -102,9 +97,9 @@ class Signer(object):
`pubkey` should be loaded via `decode.load_from_gpg(user_id)` `pubkey` should be loaded via `decode.load_from_gpg(user_id)`
from the local GPG keyring. from the local GPG keyring.
""" """
s = Signer(user_id=user_id, s = cls(user_id=user_id,
created=pubkey['created'], created=pubkey['created'],
curve_name=proto.find_curve_by_algo_id(pubkey['algo'])) curve_name=proto.find_curve_by_algo_id(pubkey['algo']))
assert s.pubkey.key_id() == pubkey['key_id'] assert s.pubkey.key_id() == pubkey['key_id']
return s return s
@@ -112,8 +107,8 @@ class Signer(object):
"""Close connection and turn off the screen of the device.""" """Close connection and turn off the screen of the device."""
self.conn.close() self.conn.close()
def export(self): def create_primary(self):
"""Export GPG public key, ready for "gpg2 --import".""" """Export new primary GPG public key, ready for "gpg2 --import"."""
pubkey_packet = proto.packet(tag=6, blob=self.pubkey.data()) pubkey_packet = proto.packet(tag=6, blob=self.pubkey.data())
user_id_packet = proto.packet(tag=13, blob=self.user_id) user_id_packet = proto.packet(tag=13, blob=self.user_id)
@@ -137,7 +132,7 @@ class Signer(object):
proto.subpacket(16, self.pubkey.key_id()), # issuer key id proto.subpacket(16, self.pubkey.key_id()), # issuer key id
proto.CUSTOM_SUBPACKET] proto.CUSTOM_SUBPACKET]
signature = _make_signature( signature = proto.make_signature(
signer_func=self.conn.sign, signer_func=self.conn.sign,
public_algo=self.pubkey.algo_id, public_algo=self.pubkey.algo_id,
data_to_sign=data_to_sign, data_to_sign=data_to_sign,
@@ -148,8 +143,8 @@ class Signer(object):
sign_packet = proto.packet(tag=2, blob=signature) sign_packet = proto.packet(tag=2, blob=signature)
return pubkey_packet + user_id_packet + sign_packet return pubkey_packet + user_id_packet + sign_packet
def subkey(self): def create_subkey(self):
"""Export a subkey to `self.user_id` GPG primary key.""" """Export new subkey to `self.user_id` GPG primary key."""
subkey_packet = proto.packet(tag=14, blob=self.pubkey.data()) subkey_packet = proto.packet(tag=14, blob=self.pubkey.data())
primary = decode.load_from_gpg(self.user_id) primary = decode.load_from_gpg(self.user_id)
log.info('adding subkey to primary GPG key "%s" (%s)', log.info('adding subkey to primary GPG key "%s" (%s)',
@@ -162,12 +157,13 @@ class Signer(object):
unhashed_subpackets = [ unhashed_subpackets = [
proto.subpacket(16, self.pubkey.key_id())] # issuer key id proto.subpacket(16, self.pubkey.key_id())] # issuer key id
log.info('confirm signing subkey with hardware device') log.info('confirm signing subkey with hardware device')
embedded_sig = _make_signature(signer_func=self.conn.sign, embedded_sig = proto.make_signature(
data_to_sign=data_to_sign, signer_func=self.conn.sign,
public_algo=self.pubkey.algo_id, data_to_sign=data_to_sign,
sig_type=0x19, public_algo=self.pubkey.algo_id,
hashed_subpackets=hashed_subpackets, sig_type=0x19,
unhashed_subpackets=unhashed_subpackets) hashed_subpackets=hashed_subpackets,
unhashed_subpackets=unhashed_subpackets)
# Subkey Binding Signature # Subkey Binding Signature
hashed_subpackets = [ hashed_subpackets = [
@@ -179,16 +175,17 @@ class Signer(object):
proto.CUSTOM_SUBPACKET] 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 = _make_signature(signer_func=gpg_agent.sign, signature = proto.make_signature(
data_to_sign=data_to_sign, signer_func=gpg_agent.sign,
public_algo=primary['algo'], data_to_sign=data_to_sign,
sig_type=0x18, public_algo=primary['algo'],
hashed_subpackets=hashed_subpackets, sig_type=0x18,
unhashed_subpackets=unhashed_subpackets) hashed_subpackets=hashed_subpackets,
unhashed_subpackets=unhashed_subpackets)
sign_packet = proto.packet(tag=2, blob=signature) sign_packet = proto.packet(tag=2, blob=signature)
return subkey_packet + sign_packet return subkey_packet + sign_packet
def sign(self, msg, sign_time=None): def sign_message(self, msg, sign_time=None):
"""Sign GPG message at specified time.""" """Sign GPG message at specified time."""
if sign_time is None: if sign_time is None:
sign_time = int(time.time()) sign_time = int(time.time())
@@ -199,32 +196,10 @@ class Signer(object):
unhashed_subpackets = [ unhashed_subpackets = [
proto.subpacket(16, self.pubkey.key_id())] # issuer key id proto.subpacket(16, self.pubkey.key_id())] # issuer key id
blob = _make_signature(signer_func=self.conn.sign, blob = proto.make_signature(
data_to_sign=msg, signer_func=self.conn.sign,
public_algo=self.pubkey.algo_id, data_to_sign=msg,
hashed_subpackets=hashed_subpackets, public_algo=self.pubkey.algo_id,
unhashed_subpackets=unhashed_subpackets) hashed_subpackets=hashed_subpackets,
unhashed_subpackets=unhashed_subpackets)
return proto.packet(tag=2, blob=blob) return proto.packet(tag=2, blob=blob)
def _make_signature(signer_func, data_to_sign, public_algo,
hashed_subpackets, unhashed_subpackets, sig_type=0):
# pylint: disable=too-many-arguments
header = struct.pack('>BBBB',
4, # version
sig_type, # rfc4880 (section-5.2.1)
public_algo,
8) # hash_alg (SHA256)
hashed = proto.subpackets(*hashed_subpackets)
unhashed = proto.subpackets(*unhashed_subpackets)
tail = b'\x04\xff' + struct.pack('>L', len(header) + len(hashed))
data_to_hash = data_to_sign + header + hashed + tail
log.debug('hashing %d bytes', len(data_to_hash))
digest = hashlib.sha256(data_to_hash).digest()
log.info('signing digest: %s', util.hexlify(digest))
sig = signer_func(digest=digest)
return bytes(header + hashed + unhashed +
digest[:2] + # used for decoder's sanity check
sig) # actual ECDSA signature

View File

@@ -154,3 +154,27 @@ def armor(blob, type_str):
checksum = base64.b64encode(util.crc24(blob)) checksum = base64.b64encode(util.crc24(blob))
tail = '-----END PGP {}-----\n'.format(type_str) tail = '-----END PGP {}-----\n'.format(type_str)
return head + _split_lines(body, 64) + '=' + checksum + '\n' + tail return head + _split_lines(body, 64) + '=' + checksum + '\n' + tail
def make_signature(signer_func, data_to_sign, public_algo,
hashed_subpackets, unhashed_subpackets, sig_type=0):
"""Create new GPG signature."""
# pylint: disable=too-many-arguments
header = struct.pack('>BBBB',
4, # version
sig_type, # rfc4880 (section-5.2.1)
public_algo,
8) # hash_alg (SHA256)
hashed = subpackets(*hashed_subpackets)
unhashed = subpackets(*unhashed_subpackets)
tail = b'\x04\xff' + struct.pack('>L', len(header) + len(hashed))
data_to_hash = data_to_sign + header + hashed + tail
log.debug('hashing %d bytes', len(data_to_hash))
digest = hashlib.sha256(data_to_hash).digest()
log.info('signing digest: %s', util.hexlify(digest))
sig = signer_func(digest=digest)
return bytes(header + hashed + unhashed +
digest[:2] + # used for decoder's sanity check
sig) # actual ECDSA signature

View File

@@ -16,16 +16,16 @@ log = logging.getLogger(__name__)
def run_create(args): 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']
s = encode.Signer(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)
with contextlib.closing(s): with contextlib.closing(f):
if args.subkey: if args.subkey:
subkey = s.subkey() subkey = f.create_subkey()
primary = sp.check_output(['gpg2', '--export', user_id]) primary = sp.check_output(['gpg2', '--export', user_id])
result = primary + subkey result = primary + subkey
else: else:
result = s.export() result = f.create_primary()
sys.stdout.write(proto.armor(result, 'PUBLIC KEY BLOCK')) sys.stdout.write(proto.armor(result, 'PUBLIC KEY BLOCK'))
@@ -33,13 +33,13 @@ def run_create(args):
def run_sign(args): def run_sign(args):
"""Generate a GPG signature using hardware-based device.""" """Generate a GPG signature using hardware-based device."""
pubkey = decode.load_from_gpg(user_id=None, use_custom=True) pubkey = decode.load_from_gpg(user_id=None, use_custom=True)
s = encode.Signer.from_public_key(pubkey=pubkey, user_id=pubkey['user_id']) f = encode.Factory.from_public_key(pubkey=pubkey, user_id=pubkey['user_id'])
with contextlib.closing(s): with contextlib.closing(f):
if args.filename: if args.filename:
data = open(args.filename, 'rb').read() data = open(args.filename, 'rb').read()
else: else:
data = sys.stdin.read() data = sys.stdin.read()
sig = s.sign(data) sig = f.sign_message(data)
sig = proto.armor(sig, 'SIGNATURE') sig = proto.armor(sig, 'SIGNATURE')
decode.verify(pubkey=pubkey, signature=sig, original_data=data) decode.verify(pubkey=pubkey, signature=sig, original_data=data)