Split the package into a shared library and separate per-device packages

nistp521
Roman Zeyde 7 years ago
parent eb525e1b62
commit 4af881b3cb
No known key found for this signature in database
GPG Key ID: 87CAE5FA46917CBB

@ -10,24 +10,17 @@ cache:
directories: directories:
- $HOME/.cache/pip - $HOME/.cache/pip
addons:
apt:
packages:
- libudev-dev
- libusb-1.0-0-dev
before_install: before_install:
- pip install -U setuptools pylint coverage pep8 pydocstyle "pip>=7.0" wheel google - pip install -U setuptools pylint coverage pep8 pydocstyle "pip>=7.0" wheel
- pip install -e git+https://github.com/keepkey/python-keepkey@6e8baa8b935e830d05f87b6dfd9bc7c927a96dc3#egg=keepkey
install: install:
- pip install -e . - pip install -e .
script: script:
- pep8 trezor_agent - pep8 libagent
- pylint --reports=no --rcfile .pylintrc trezor_agent - pylint --reports=no --rcfile .pylintrc libagent
- pydocstyle trezor_agent - pydocstyle libagent
- coverage run --source trezor_agent/ -m py.test -v - coverage run --source libagent/ -m py.test -v
after_success: after_success:
- coverage report - coverage report

@ -0,0 +1,5 @@
import libagent.gpg
import libagent.ssh
from libagent.device import keepkey
ssh_agent = lambda: libagent.ssh.main(keepkey.KeepKey)

@ -0,0 +1,34 @@
#!/usr/bin/env python
from setuptools import setup
setup(
name='keepkey_agent',
version='0.9.0',
description='Using KeepKey as hardware SSH agent',
author='Roman Zeyde',
author_email='roman.zeyde@gmail.com',
url='http://github.com/romanz/trezor-agent',
scripts=['keepkey_agent.py'],
install_requires=['libagent>=0.9.0', 'keepkey>=0.7.3'],
platforms=['POSIX'],
classifiers=[
'Environment :: Console',
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Intended Audience :: Information Technology',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)',
'Operating System :: POSIX',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: System :: Networking',
'Topic :: Communications',
'Topic :: Security',
'Topic :: Utilities',
],
entry_points={'console_scripts': [
'keepkey-agent = keepkey_agent:ssh_agent',
]},
)

@ -0,0 +1,7 @@
import libagent.gpg
import libagent.ssh
from libagent.device.ledger import LedgerNanoS as DeviceType
ssh_agent = lambda: libagent.ssh.main(DeviceType)
gpg_tool = lambda: libagent.gpg.main(DeviceType)
gpg_agent = lambda: libagent.gpg.run_agent(DeviceType)

@ -0,0 +1,36 @@
#!/usr/bin/env python
from setuptools import setup
setup(
name='ledger_agent',
version='0.9.0',
description='Using Ledger as hardware SSH agent',
author='Roman Zeyde',
author_email='roman.zeyde@gmail.com',
url='http://github.com/romanz/trezor-agent',
scripts=['ledger_agent.py'],
install_requires=['libagent>=0.9.0', 'ledgerblue>=0.1.8'],
platforms=['POSIX'],
classifiers=[
'Environment :: Console',
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Intended Audience :: Information Technology',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)',
'Operating System :: POSIX',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: System :: Networking',
'Topic :: Communications',
'Topic :: Security',
'Topic :: Utilities',
],
entry_points={'console_scripts': [
'ledger-agent = ledger_agent:ssh_agent',
'ledger-gpg = ledger_agent:gpg_tool',
'ledger-gpg-agent = ledger_agent:gpg_agent',
]},
)

@ -0,0 +1,36 @@
#!/usr/bin/env python
from setuptools import setup
setup(
name='trezor_agent',
version='0.9.0',
description='Using Trezor as hardware SSH agent',
author='Roman Zeyde',
author_email='roman.zeyde@gmail.com',
url='http://github.com/romanz/trezor-agent',
scripts=['trezor_agent.py'],
install_requires=['libagent>=0.9.0', 'trezor>=0.7.6'],
platforms=['POSIX'],
classifiers=[
'Environment :: Console',
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Intended Audience :: Information Technology',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)',
'Operating System :: POSIX',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: System :: Networking',
'Topic :: Communications',
'Topic :: Security',
'Topic :: Utilities',
],
entry_points={'console_scripts': [
'trezor-agent = trezor_agent:ssh_agent',
'trezor-gpg = trezor_agent:gpg_tool',
'trezor-gpg-agent = trezor_agent:gpg_agent',
]},
)

@ -0,0 +1,7 @@
import libagent.gpg
import libagent.ssh
from libagent.device.trezor import Trezor as DeviceType
ssh_agent = lambda: libagent.ssh.main(DeviceType)
gpg_tool = lambda: libagent.gpg.main(DeviceType)
gpg_agent = lambda: libagent.gpg.run_agent(DeviceType)

@ -0,0 +1,3 @@
"""Cryptographic hardware device management."""
from . import interface

@ -1,6 +1,6 @@
"""KeepKey-related definitions.""" """KeepKey-related definitions."""
# pylint: disable=unused-import # pylint: disable=unused-import,import-error
from keepkeylib.client import CallException as Error from keepkeylib.client import CallException as Error
from keepkeylib.client import KeepKeyClient as Client from keepkeylib.client import KeepKeyClient as Client

@ -4,7 +4,7 @@ import binascii
import logging import logging
import struct import struct
from ledgerblue import comm from ledgerblue import comm # pylint: disable=import-error
from . import interface from . import interface

@ -1,6 +1,6 @@
"""TREZOR-related definitions.""" """TREZOR-related definitions."""
# pylint: disable=unused-import # pylint: disable=unused-import,import-error
from trezorlib.client import CallException as Error from trezorlib.client import CallException as Error
from trezorlib.client import TrezorClient as Client from trezorlib.client import TrezorClient as Client

@ -1,5 +1,13 @@
#!/usr/bin/env python """
"""Create signatures and export public keys for GPG using TREZOR.""" TREZOR support for ECDSA GPG signatures.
See these links for more details:
- https://www.gnupg.org/faq/whats-new-in-2.1.html
- https://tools.ietf.org/html/rfc4880
- https://tools.ietf.org/html/rfc6637
- https://tools.ietf.org/html/draft-irtf-cfrg-eddsa-05
"""
import argparse import argparse
import contextlib import contextlib
import logging import logging
@ -15,14 +23,15 @@ from .. import device, formats, server, util
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def export_public_key(args): def export_public_key(device_type, args):
"""Generate a new pubkey for a new/existing GPG identity.""" """Generate a new pubkey for a new/existing GPG identity."""
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)
d = client.Client(user_id=args.user_id, curve_name=args.ecdsa_curve) c = client.Client(user_id=args.user_id, curve_name=args.ecdsa_curve,
verifying_key = d.pubkey(ecdh=False) device_type=device_type)
decryption_key = d.pubkey(ecdh=True) verifying_key = c.pubkey(ecdh=False)
decryption_key = c.pubkey(ecdh=True)
if args.subkey: # add as subkey if args.subkey: # 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',
@ -38,10 +47,10 @@ def export_public_key(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=d.sign) signer_func=c.sign)
result = encode.create_subkey(primary_bytes=result, result = encode.create_subkey(primary_bytes=result,
subkey=encryption_key, subkey=encryption_key,
signer_func=d.sign) signer_func=c.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)
@ -56,15 +65,15 @@ def export_public_key(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=d.sign) signer_func=c.sign)
result = encode.create_subkey(primary_bytes=result, result = encode.create_subkey(primary_bytes=result,
subkey=subkey, subkey=subkey,
signer_func=d.sign) signer_func=c.sign)
sys.stdout.write(protocol.armor(result, 'PUBLIC KEY BLOCK')) sys.stdout.write(protocol.armor(result, 'PUBLIC KEY BLOCK'))
def run_create(args): def run_create(device_type, args):
"""Export public GPG key.""" """Export public GPG key."""
util.setup_logging(verbosity=args.verbose) util.setup_logging(verbosity=args.verbose)
log.warning('This GPG tool is still in EXPERIMENTAL mode, ' log.warning('This GPG tool is still in EXPERIMENTAL mode, '
@ -74,26 +83,27 @@ def run_create(args):
existing_gpg = keyring.gpg_version().decode('ascii') existing_gpg = keyring.gpg_version().decode('ascii')
required_gpg = '>=2.1.11' required_gpg = '>=2.1.11'
if semver.match(existing_gpg, required_gpg): if semver.match(existing_gpg, required_gpg):
export_public_key(args) export_public_key(device_type, args)
else: else:
log.error('Existing gpg2 has version "%s" (%s required)', log.error('Existing gpg2 has version "%s" (%s required)',
existing_gpg, required_gpg) existing_gpg, required_gpg)
def run_unlock(args): def run_unlock(device_type, args):
"""Unlock hardware device (for future interaction).""" """Unlock hardware device (for future interaction)."""
util.setup_logging(verbosity=args.verbose) util.setup_logging(verbosity=args.verbose)
d = device.detect() with device_type() as d:
log.info('unlocked %s device', d) log.info('unlocked %s device', d)
def run_agent(_): def run_agent(device_type):
"""Run a simple GPG-agent server.""" """Run a simple GPG-agent server."""
home_dir = os.environ.get('GNUPGHOME', os.path.expanduser('~/.gnupg/trezor')) parser = argparse.ArgumentParser()
config_file = os.path.join(home_dir, 'gpg-agent.conf') parser.add_argument('--homedir', default=os.environ.get('GNUPGHOME'))
if not os.path.exists(config_file): args, _ = parser.parse_known_args()
msg = 'No configuration file found: {}'.format(config_file)
raise IOError(msg) assert args.homedir
config_file = os.path.join(args.homedir, 'gpg-agent.conf')
lines = (line.strip() for line in open(config_file)) lines = (line.strip() for line in open(config_file))
lines = (line for line in lines if line and not line.startswith('#')) lines = (line for line in lines if line and not line.startswith('#'))
@ -106,7 +116,7 @@ def run_agent(_):
for conn in agent.yield_connections(sock): for conn in agent.yield_connections(sock):
with contextlib.closing(conn): with contextlib.closing(conn):
try: try:
agent.handle_connection(conn) agent.handle_connection(conn=conn, device_type=device_type)
except StopIteration: except StopIteration:
log.info('stopping gpg-agent') log.info('stopping gpg-agent')
return return
@ -114,14 +124,11 @@ def run_agent(_):
log.exception('gpg-agent failed: %s', e) log.exception('gpg-agent failed: %s', e)
def main(): def main(device_type):
"""Parse command-line arguments.""" """Parse command-line arguments."""
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers() subparsers = parser.add_subparsers()
p = subparsers.add_parser('agent', help='Run GPG agent using a hardware device')
p.set_defaults(func=run_agent)
p = subparsers.add_parser('create', help='Export public GPG key') p = subparsers.add_parser('create', help='Export public GPG key')
p.add_argument('user_id') p.add_argument('user_id')
p.add_argument('-e', '--ecdsa-curve', default='nist256p1') p.add_argument('-e', '--ecdsa-curve', default='nist256p1')
@ -135,8 +142,4 @@ def main():
p.set_defaults(func=run_unlock) p.set_defaults(func=run_unlock)
args = parser.parse_args() args = parser.parse_args()
return args.func(args) return args.func(device_type=device_type, args=args)
if __name__ == '__main__':
main()

@ -36,7 +36,7 @@ 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')))'
def open_connection(keygrip_bytes): def open_connection(keygrip_bytes, device_type):
""" """
Connect to the device for the specified keygrip. Connect to the device for the specified keygrip.
@ -51,7 +51,7 @@ def open_connection(keygrip_bytes):
curve_name = protocol.get_curve_name_by_oid(pubkey_dict['curve_oid']) curve_name = protocol.get_curve_name_by_oid(pubkey_dict['curve_oid'])
ecdh = (pubkey_dict['algo'] == protocol.ECDH_ALGO_ID) ecdh = (pubkey_dict['algo'] == protocol.ECDH_ALGO_ID)
conn = client.Client(user_id, curve_name=curve_name) conn = client.Client(user_id, curve_name=curve_name, device_type=device_type)
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)
@ -60,11 +60,11 @@ def open_connection(keygrip_bytes):
return conn return conn
def pksign(keygrip, digest, algo): def pksign(keygrip, digest, algo, device_type):
"""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)
conn = open_connection(keygrip_bytes) conn = open_connection(keygrip_bytes, device_type=device_type)
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)
@ -92,7 +92,7 @@ def parse_ecdh(line):
return dict(items)[b'e'] return dict(items)[b'e']
def pkdecrypt(keygrip, conn): def pkdecrypt(keygrip, conn, device_type):
"""Handle decryption using ECDH.""" """Handle decryption using ECDH."""
for msg in [b'S INQUIRE_MAXLEN 4096', b'INQUIRE CIPHERTEXT']: for msg in [b'S INQUIRE_MAXLEN 4096', b'INQUIRE CIPHERTEXT']:
keyring.sendline(conn, msg) keyring.sendline(conn, msg)
@ -102,15 +102,16 @@ def pkdecrypt(keygrip, conn):
remote_pubkey = parse_ecdh(line) remote_pubkey = parse_ecdh(line)
keygrip_bytes = binascii.unhexlify(keygrip) keygrip_bytes = binascii.unhexlify(keygrip)
conn = open_connection(keygrip_bytes) conn = open_connection(keygrip_bytes, device_type=device_type)
return _serialize_point(conn.ecdh(remote_pubkey)) return _serialize_point(conn.ecdh(remote_pubkey))
@util.memoize @util.memoize
def have_key(keygrip): def have_key(keygrip, device_type):
"""Check if current keygrip correspond to a TREZOR-based key.""" """Check if current keygrip correspond to a TREZOR-based key."""
try: try:
open_connection(keygrip_bytes=binascii.unhexlify(keygrip)) open_connection(keygrip_bytes=binascii.unhexlify(keygrip),
device_type=device_type)
return True return True
except KeyError as e: except KeyError as e:
log.warning('HAVEKEY(%s) failed: %s', keygrip, e) log.warning('HAVEKEY(%s) failed: %s', keygrip, e)
@ -118,7 +119,7 @@ def have_key(keygrip):
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
def handle_connection(conn): def handle_connection(conn, device_type):
"""Handle connection from GPG binary using the ASSUAN protocol.""" """Handle connection from GPG binary using the ASSUAN protocol."""
keygrip = None keygrip = None
digest = None digest = None
@ -141,13 +142,13 @@ def handle_connection(conn):
elif command == b'SETHASH': elif command == b'SETHASH':
algo, digest = args algo, digest = args
elif command == b'PKSIGN': elif command == b'PKSIGN':
sig = pksign(keygrip, digest, algo) sig = pksign(keygrip, digest, algo, device_type=device_type)
keyring.sendline(conn, b'D ' + sig) keyring.sendline(conn, b'D ' + sig)
elif command == b'PKDECRYPT': elif command == b'PKDECRYPT':
sec = pkdecrypt(keygrip, conn) sec = pkdecrypt(keygrip, conn, device_type=device_type)
keyring.sendline(conn, b'D ' + sec) keyring.sendline(conn, b'D ' + sec)
elif command == b'HAVEKEY': elif command == b'HAVEKEY':
if not have_key(keygrip=args[0]): if not have_key(keygrip=args[0], device_type=device_type):
keyring.sendline(conn, keyring.sendline(conn,
b'ERR 67108881 No secret key <GPG Agent>') b'ERR 67108881 No secret key <GPG Agent>')
return return

@ -10,9 +10,9 @@ log = logging.getLogger(__name__)
class Client(object): class Client(object):
"""Sign messages and get public keys from a hardware device.""" """Sign messages and get public keys from a hardware device."""
def __init__(self, user_id, curve_name): def __init__(self, user_id, curve_name, device_type):
"""Connect to the device and retrieve required public key.""" """Connect to the device and retrieve required public key."""
self.device = device.detect() self.device = device_type()
self.user_id = user_id self.user_id = user_id
self.identity = device.interface.Identity( self.identity = device.interface.Identity(
identity_str='gpg://', curve_name=curve_name) identity_str='gpg://', curve_name=curve_name)

@ -7,7 +7,7 @@ import re
import subprocess import subprocess
import sys import sys
from . import client, device, formats, protocol, server, util from .. import client, device, formats, protocol, server, util
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -169,7 +169,7 @@ class JustInTimeConnection(object):
@handle_connection_error @handle_connection_error
def run_agent(client_factory=client.Client): def main(device_type):
"""Run ssh-agent using given hardware client factory.""" """Run ssh-agent using given hardware client factory."""
args = create_agent_parser().parse_args() args = create_agent_parser().parse_args()
util.setup_logging(verbosity=args.verbose) util.setup_logging(verbosity=args.verbose)
@ -195,7 +195,7 @@ def run_agent(client_factory=client.Client):
command = os.environ['SHELL'] command = os.environ['SHELL']
conn = JustInTimeConnection( conn = JustInTimeConnection(
conn_factory=lambda: client_factory(device.detect()), conn_factory=lambda: client.Client(device_type()),
identities=identities) identities=identities)
if command: if command:
return run_server(conn=conn, command=command, debug=args.debug, return run_server(conn=conn, command=command, debug=args.debug,

@ -1,2 +0,0 @@
#!/bin/bash
trezor-gpg agent

@ -4,31 +4,52 @@ set -eu
gpg2 --version >/dev/null # verify that GnuPG 2 is installed gpg2 --version >/dev/null # verify that GnuPG 2 is installed
USER_ID="${1}" USER_ID="${1}"
HOMEDIR=~/.gnupg/trezor DEVICE=${DEVICE:="trezor"} # or "ledger"
CURVE=${CURVE:="nist256p1"} # or "ed25519" CURVE=${CURVE:="nist256p1"} # or "ed25519"
TIMESTAMP=${TIMESTAMP:=`date +%s`} # key creation timestamp TIMESTAMP=${TIMESTAMP:=`date +%s`} # key creation timestamp
HOMEDIR=~/.gnupg/${DEVICE}
# Prepare new GPG home directory for TREZOR-based identity # Prepare new GPG home directory for hardware-based identity
rm -rf "${HOMEDIR}" rm -rf "${HOMEDIR}"
mkdir -p "${HOMEDIR}" mkdir -p "${HOMEDIR}"
chmod 700 "${HOMEDIR}" chmod 700 "${HOMEDIR}"
# Generate new GPG identity and import into GPG keyring # Generate new GPG identity and import into GPG keyring
trezor-gpg create -v "${USER_ID}" -t "${TIMESTAMP}" -e "${CURVE}" > "${HOMEDIR}/pubkey.asc" $DEVICE-gpg create -v "${USER_ID}" -t "${TIMESTAMP}" -e "${CURVE}" > "${HOMEDIR}/pubkey.asc"
gpg2 --homedir "${HOMEDIR}" --import < "${HOMEDIR}/pubkey.asc" gpg2 --homedir "${HOMEDIR}" --import < "${HOMEDIR}/pubkey.asc" 2> /dev/null
rm -f "${HOMEDIR}/S.gpg-agent" # (otherwise, our agent won't be started automatically) rm -f "${HOMEDIR}/S.gpg-agent" # (otherwise, our agent won't be started automatically)
# Make new GPG identity with "ultimate" trust (via its fingerprint) # Make new GPG identity with "ultimate" trust (via its fingerprint)
FINGERPRINT=$(gpg2 --homedir "${HOMEDIR}" --list-public-keys --with-fingerprint --with-colons | sed -n -E 's/^fpr:::::::::([0-9A-F]+):$/\1/p' | head -n1) FINGERPRINT=$(gpg2 --homedir "${HOMEDIR}" --list-public-keys --with-fingerprint --with-colons | sed -n -E 's/^fpr:::::::::([0-9A-F]+):$/\1/p' | head -n1)
echo "${FINGERPRINT}:6" | gpg2 --homedir "${HOMEDIR}" --import-ownertrust echo "${FINGERPRINT}:6" | gpg2 --homedir "${HOMEDIR}" --import-ownertrust 2> /dev/null
AGENT_PATH="$(which ${DEVICE}-gpg-agent)"
# Prepare GPG configuration file # Prepare GPG configuration file
echo "# TREZOR-based GPG configuration echo "# Hardware-based GPG configuration
agent-program $(dirname ${0})/gpg-agent agent-program ${AGENT_PATH}
personal-digest-preferences SHA512 personal-digest-preferences SHA512
" | tee "${HOMEDIR}/gpg.conf" " > "${HOMEDIR}/gpg.conf"
echo "# TREZOR-based GPG agent emulator # Prepare GPG agent configuration file
echo "# Hardware-based GPG agent emulator
log-file ${HOMEDIR}/gpg-agent.log log-file ${HOMEDIR}/gpg-agent.log
verbosity 2 verbosity 2
" | tee "${HOMEDIR}/gpg-agent.conf" " > "${HOMEDIR}/gpg-agent.conf"
# Prepare a helper script for setting up the new identity
echo "#!/bin/bash
set -eu
export GNUPGHOME=${HOMEDIR}
COMMAND=\$*
if [ -z \"\${COMMAND}\" ]
then
\${SHELL}
else
\${COMMAND}
fi
" > "${HOMEDIR}/env"
chmod u+x "${HOMEDIR}/env"
# Load agent and make sure it responds with the new identity
GNUPGHOME="$HOMEDIR" gpg2 -K 2> /dev/null

@ -1,28 +0,0 @@
#!/bin/bash
set -eu
gpg2 --version >/dev/null # verify that GnuPG 2 is installed
export GNUPGHOME=~/.gnupg/trezor
CONFIG_PATH="${GNUPGHOME}/gpg-agent.conf"
if [ ! -f ${CONFIG_PATH} ]
then
echo "No configuration found: ${CONFIG_PATH}"
exit 1
fi
# Make sure that the device is unlocked before starting the shell
trezor-gpg unlock
# Make sure TREZOR-based gpg-agent is running
gpg-connect-agent --agent-program "$(dirname $0)/gpg-agent" </dev/null
COMMAND=$*
if [ -z "${COMMAND}" ]
then
gpg2 --list-public-keys
${SHELL}
else
${COMMAND}
fi

@ -2,18 +2,14 @@
from setuptools import setup from setuptools import setup
setup( setup(
name='trezor_agent', name='libagent',
version='0.8.3', version='0.9.0',
description='Using Trezor as hardware SSH agent', description='Using hardware wallets as SSH/GPG agent',
author='Roman Zeyde', author='Roman Zeyde',
author_email='roman.zeyde@gmail.com', author_email='roman.zeyde@gmail.com',
url='http://github.com/romanz/trezor-agent', url='http://github.com/romanz/trezor-agent',
packages=['trezor_agent', 'trezor_agent.device', 'trezor_agent.gpg'], packages=['libagent', 'libagent.device', 'libagent.gpg', 'libagent.ssh'],
install_requires=[ install_requires=['ecdsa>=0.13', 'ed25519>=1.4', 'semver>=2.2'],
'ecdsa>=0.13', 'ed25519>=1.4', 'Cython>=0.23.4', 'protobuf>=3.0.0', 'semver>=2.2',
'trezor>=0.7.6', 'keepkey>=0.7.3', 'ledgerblue>=0.1.8',
'hidapi==0.7.99.post15' # until https://github.com/keepkey/python-keepkey/pull/8 is merged
],
platforms=['POSIX'], platforms=['POSIX'],
classifiers=[ classifiers=[
'Environment :: Console', 'Environment :: Console',
@ -32,8 +28,4 @@ setup(
'Topic :: Security', 'Topic :: Security',
'Topic :: Utilities', 'Topic :: Utilities',
], ],
entry_points={'console_scripts': [
'trezor-agent = trezor_agent.__main__:run_agent',
'trezor-gpg = trezor_agent.gpg.__main__:main',
]},
) )

@ -15,10 +15,10 @@ deps=
pydocstyle pydocstyle
isort isort
commands= commands=
pep8 trezor_agent pep8 libagent
isort --skip-glob .tox -c -r trezor_agent isort --skip-glob .tox -c -r libagent
pylint --reports=no --rcfile .pylintrc trezor_agent pylint --reports=no --rcfile .pylintrc libagent
pydocstyle trezor_agent pydocstyle libagent
coverage run --omit='trezor_agent/__main__.py' --source trezor_agent -m py.test -v trezor_agent coverage run --source libagent -m py.test -v libagent
coverage report coverage report
coverage html coverage html

@ -1,27 +0,0 @@
"""Cryptographic hardware device management."""
import logging
from . import trezor
from . import keepkey
from . import ledger
from . import interface
log = logging.getLogger(__name__)
DEVICE_TYPES = [
trezor.Trezor,
keepkey.KeepKey,
ledger.LedgerNanoS,
]
def detect():
"""Detect the first available device and return it to the user."""
for device_type in DEVICE_TYPES:
try:
with device_type() as d:
return d
except interface.NotFoundError as e:
log.debug('device not found: %s', e)
raise IOError('No device found!')

@ -1,9 +0,0 @@
"""
TREZOR support for ECDSA GPG signatures.
See these links for more details:
- https://www.gnupg.org/faq/whats-new-in-2.1.html
- https://tools.ietf.org/html/rfc4880
- https://tools.ietf.org/html/rfc6637
- https://tools.ietf.org/html/draft-irtf-cfrg-eddsa-05
"""
Loading…
Cancel
Save