From 447faf973c5487e0d720b6066b6fb142f926a08d Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sun, 17 Apr 2016 23:03:41 +0300 Subject: [PATCH] signer should export public key or sign a file --- gpg/check.py | 4 ++-- gpg/decode.py | 8 ++++---- gpg/demo.sh | 11 ++++++++--- gpg/signer.py | 27 ++++++++++++++++++++++----- 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/gpg/check.py b/gpg/check.py index 25a82dd..db4e0e1 100755 --- a/gpg/check.py +++ b/gpg/check.py @@ -28,7 +28,7 @@ def check(pubkey, sig_file): parser = decode.Parser(decode.Reader(d), original_data(sig_file)) signature, = list(parser) decode.verify_digest(pubkey=pubkey, digest=signature['digest'], - signature=signature['sig'], label=sig_file) + signature=signature['sig'], label='GPG signature') def main(): @@ -38,7 +38,7 @@ def main(): p.add_argument('pubkey') p.add_argument('signature') args = p.parse_args() - check(pubkey=decode.load_public_key(args.pubkey), + check(pubkey=decode.load_public_key(open(args.pubkey, 'rb')), sig_file=args.signature) if __name__ == '__main__': diff --git a/gpg/decode.py b/gpg/decode.py index ec89336..c936c03 100644 --- a/gpg/decode.py +++ b/gpg/decode.py @@ -224,12 +224,12 @@ class Parser(object): next = __next__ -def load_public_key(filename): - parser = Parser(Reader(open(filename, 'rb'))) +def load_public_key(stream): + parser = Parser(Reader(stream)) pubkey, userid, signature = list(parser) log.info('loaded %s public key', userid['value']) verify_digest(pubkey=pubkey, digest=signature['digest'], - signature=signature['sig'], label=filename) + signature=signature['sig'], label='GPG public key') return pubkey @@ -246,5 +246,5 @@ def verify_digest(pubkey, digest, signature, label): sigdecode=lambda rs, order: rs) log.info('%s is OK', label) except ecdsa.keys.BadSignatureError: - log.error('%s has bad signature!', label) + log.error('Bad %s!', label) raise diff --git a/gpg/demo.sh b/gpg/demo.sh index 6bc7480..a012157 100755 --- a/gpg/demo.sh +++ b/gpg/demo.sh @@ -4,11 +4,16 @@ CREATED=1460731897 # needed for consistent public key creation NAME="trezor_key" # will be used as GPG user id and public key name echo "Hello GPG World!" > EXAMPLE -./signer.py $NAME --time $CREATED --public-key --file EXAMPLE --verbose -./check.py $NAME.pub EXAMPLE.sig # pure Python verification +# Create, sign and export the public key +./signer.py $NAME --time $CREATED --public-key --verbose -# Install GPG v2.1 (modern) and verify the signature +# Install GPG v2.1 (modern) and import the public key gpg2 --import $NAME.pub gpg2 --list-keys $NAME + +# Perform actual GPG signature using TREZOR +./signer.py $NAME --file EXAMPLE --verbose +./check.py $NAME.pub EXAMPLE.sig # pure Python verification + # gpg2 --edit-key trezor_key trust # optional: mark it as trusted gpg2 --verify EXAMPLE.sig diff --git a/gpg/signer.py b/gpg/signer.py index 310711c..ac64fe3 100755 --- a/gpg/signer.py +++ b/gpg/signer.py @@ -3,12 +3,15 @@ import argparse import base64 import binascii import hashlib +import io import logging import struct +import subprocess import time import ecdsa +import decode import trezor_agent.client import trezor_agent.formats import trezor_agent.util @@ -196,20 +199,29 @@ def armor(blob, type_str): return head + split_lines(body, 64) + '=' + checksum + '\n' + tail +def load_from_gpg(user_id): + pubkey_bytes = subprocess.check_output(['gpg2', '--export', user_id]) + pubkey = decode.load_public_key(io.BytesIO(pubkey_bytes)) + return pubkey + + def main(): p = argparse.ArgumentParser() p.add_argument('user_id') p.add_argument('-t', '--time', type=int, default=int(time.time())) - p.add_argument('-f', '--filename') p.add_argument('-a', '--armor', action='store_true', default=False) - p.add_argument('-p', '--public-key', action='store_true', default=False) p.add_argument('-v', '--verbose', action='store_true', default=False) + g = p.add_mutually_exclusive_group() + g.add_argument('-f', '--filename', help='File to sign') + g.add_argument('-p', '--public-key', action='store_true', default=False) + args = p.parse_args() logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO, format='%(asctime)s %(levelname)-10s %(message)s') - s = Signer(user_id=args.user_id.encode('ascii'), created=args.time) + user_id = args.user_id.encode('ascii') if args.public_key: + s = Signer(user_id=user_id, created=args.time) pubkey = s.export() ext = '.pub' if args.armor: @@ -217,11 +229,16 @@ def main(): ext = '.asc' open(args.user_id + ext, 'wb').write(pubkey) - if args.filename: + elif args.filename: + pubkey = load_from_gpg(args.user_id) + s = Signer(user_id=user_id, created=pubkey['created']) + assert s.key_id == pubkey['key_id'] + data = open(args.filename, 'rb').read() sig, ext = s.sign(data), '.sig' if args.armor: - sig, ext = armor(sig, 'SIGNATURE'), '.asc' + sig = armor(sig, 'SIGNATURE') + ext = '.asc' open(args.filename + ext, 'wb').write(sig) s.close()