diff --git a/scripts/gpg-init b/scripts/gpg-init index 54bd098..d5d44b4 100755 --- a/scripts/gpg-init +++ b/scripts/gpg-init @@ -5,15 +5,26 @@ USER_ID="${1}" HOMEDIR=~/.gnupg/trezor CURVE=${CURVE:="nist256p1"} # or "ed25519" +# Prepare new GPG home directory for TREZOR-based identity rm -rf "${HOMEDIR}" mkdir -p "${HOMEDIR}" chmod 700 "${HOMEDIR}" -trezor-gpg -v create "${USER_ID}" -e "${CURVE}" > "${HOMEDIR}/pubkey.asc" +# Generate new GPG identity and import into GPG keyring +trezor-gpg-create -v "${USER_ID}" -e "${CURVE}" > "${HOMEDIR}/pubkey.asc" gpg2 --homedir "${HOMEDIR}" --import < "${HOMEDIR}/pubkey.asc" +rm -f "${HOMEDIR}/S.gpg-agent" # (otherwise, our agent won't be started automatically) -# Mark new key as trusted in gpg.conf +# Make new GPG identity with "ultimate" trust (via its fingerprint) FINGERPRINT=$(gpg2 --homedir "${HOMEDIR}" --list-public-keys --with-colons | sed --quiet --regexp-extended 's/^fpr:::::::::([0-9A-F]+):$/\1/p' | head -n1) -KEY_ID="0x${FINGERPRINT:(-16)}" # take last 8 bytes of the fingerprint -echo "Marking ${KEY_ID} as trusted..." -echo "trusted-key ${KEY_ID}" > "${HOMEDIR}/gpg.conf" +echo "${FINGERPRINT}:6" | gpg2 --homedir "${HOMEDIR}" --import-ownertrust + +# Prepare GPG configuration file +echo "# TREZOR-based GPG configuration +agent-program $(which trezor-gpg-agent) +" | tee "${HOMEDIR}/gpg.conf" + +echo "# TREZOR-based GPG agent emulator +log-file ${HOMEDIR}/gpg-agent.log +verbosity 2 +" | tee "${HOMEDIR}/gpg-agent.conf" diff --git a/scripts/gpg-shell b/scripts/gpg-shell index 44f220f..68cbb8f 100755 --- a/scripts/gpg-shell +++ b/scripts/gpg-shell @@ -2,15 +2,6 @@ set -eu export GNUPGHOME=~/.gnupg/trezor -gpg2 --list-public-keys --with-keygrip +gpg2 --list-public-keys -killall -q trezor-gpg || true -trezor-gpg -v agent & -AGENT_PID=$! -sleep 1 - -echo "Starting GPG-enabled shell..." -${SHELL} || true -echo "Stopping GPG-enabled shell..." - -kill ${AGENT_PID} +${SHELL} diff --git a/setup.py b/setup.py index eb2840f..eb3f91b 100644 --- a/setup.py +++ b/setup.py @@ -34,6 +34,7 @@ setup( entry_points={'console_scripts': [ 'trezor-agent = trezor_agent.__main__:run_agent', 'trezor-git = trezor_agent.__main__:run_git', - 'trezor-gpg = trezor_agent.gpg.__main__:main', + 'trezor-gpg-create = trezor_agent.gpg.__main__:main_create', + 'trezor-gpg-agent = trezor_agent.gpg.__main__:main_agent', ]}, ) diff --git a/trezor_agent/gpg/__main__.py b/trezor_agent/gpg/__main__.py index e3c12aa..d069eb5 100755 --- a/trezor_agent/gpg/__main__.py +++ b/trezor_agent/gpg/__main__.py @@ -4,6 +4,7 @@ import argparse import contextlib import io import logging +import os import sys import time @@ -73,34 +74,13 @@ def run_create(args): sys.stdout.write(protocol.armor(result, 'PUBLIC KEY BLOCK')) -def run_agent(args): # pylint: disable=unused-argument - """Run a simple GPG-agent server.""" - sock_path = keyring.get_agent_sock_path() - with server.unix_domain_socket_server(sock_path) as sock: - for conn in agent.yield_connections(sock): - with contextlib.closing(conn): - try: - agent.handle_connection(conn) - except Exception as e: # pylint: disable=broad-except - log.exception('gpg-agent failed: %s', e) - - -def main(): - """Main function.""" +def main_create(): + """Main function for GPG identity creation.""" p = argparse.ArgumentParser() + p.add_argument('user_id') + p.add_argument('-e', '--ecdsa-curve', default='nist256p1') + p.add_argument('-t', '--time', type=int, default=int(time.time())) p.add_argument('-v', '--verbose', default=0, action='count') - subparsers = p.add_subparsers() - subparsers.required = True - subparsers.dest = 'command' - - create_cmd = subparsers.add_parser('create') - create_cmd.add_argument('user_id') - create_cmd.add_argument('-e', '--ecdsa-curve', default='nist256p1') - create_cmd.add_argument('-t', '--time', type=int, default=int(time.time())) - create_cmd.set_defaults(run=run_create) - - agent_cmd = subparsers.add_parser('agent') - agent_cmd.set_defaults(run=run_agent) args = p.parse_args() util.setup_logging(verbosity=args.verbose) @@ -111,11 +91,27 @@ def main(): existing_gpg = keyring.gpg_version().decode('ascii') required_gpg = '>=2.1.15' if semver.match(existing_gpg, required_gpg): - args.run(args) + run_create(args) else: log.error('Existing gpg2 has version "%s" (%s required)', existing_gpg, required_gpg) -if __name__ == '__main__': - main() +def main_agent(): + """Run a simple GPG-agent server.""" + home_dir = os.environ.get('GNUPGHOME', os.path.expanduser('~/.gnupg/trezor')) + config_file = os.path.join(home_dir, 'gpg-agent.conf') + lines = (line.strip() for line in open(config_file)) + lines = (line for line in lines if line and not line.startswith('#')) + config = dict(line.split(' ', 1) for line in lines) + + util.setup_logging(verbosity=int(config['verbosity']), + filename=config['log-file']) + sock_path = keyring.get_agent_sock_path() + with server.unix_domain_socket_server(sock_path) as sock: + for conn in agent.yield_connections(sock): + with contextlib.closing(conn): + try: + agent.handle_connection(conn) + except Exception as e: # pylint: disable=broad-except + log.exception('gpg-agent failed: %s', e) diff --git a/trezor_agent/util.py b/trezor_agent/util.py index 24ca636..e9b7409 100644 --- a/trezor_agent/util.py +++ b/trezor_agent/util.py @@ -229,10 +229,10 @@ def get_bip32_address(identity, ecdh=False): return [(hardened | value) for value in address_n] -def setup_logging(verbosity): +def setup_logging(verbosity, **kwargs): """Configure logging for this tool.""" fmt = ('%(asctime)s %(levelname)-12s %(message)-100s ' '[%(filename)s:%(lineno)d]') levels = [logging.WARNING, logging.INFO, logging.DEBUG] level = levels[min(verbosity, len(levels) - 1)] - logging.basicConfig(format=fmt, level=level) + logging.basicConfig(format=fmt, level=level, **kwargs)