diff --git a/README-SSH.md b/README-SSH.md index 71f5de8..97807ea 100644 --- a/README-SSH.md +++ b/README-SSH.md @@ -9,27 +9,6 @@ ## Using for GitHub SSH authentication (via `trezor-git` utility) [![GitHub](https://asciinema.org/a/38337.png)](https://asciinema.org/a/38337) -# Installation - -First, make sure that the latest [trezorlib](https://pypi.python.org/pypi/trezor) Python package -is installed correctly (at least v0.6.6): - - $ apt-get install python-dev libusb-1.0-0-dev libudev-dev - $ pip install Cython trezor - -Then, install the latest [trezor_agent](https://pypi.python.org/pypi/trezor_agent) package: - - $ pip install trezor_agent - -Finally, verify that you are running the latest [TREZOR firmware](https://mytrezor.com/data/firmware/releases.json) version (at least v1.3.4): - - $ trezorctl get_features - vendor: "bitcointrezor.com" - major_version: 1 - minor_version: 3 - patch_version: 4 - ... - # Public key generation Run: diff --git a/README.md b/README.md index 35af86c..aaf1113 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,37 @@ See SatoshiLabs' blog posts about this feature: - [TREZOR Firmware 1.3.4 enables SSH login](https://medium.com/@satoshilabs/trezor-firmware-1-3-4-enables-ssh-login-86a622d7e609) - [TREZOR Firmware 1.3.6 — GPG Signing, SSH Login Updates and Advanced Transaction Features for Segwit](https://medium.com/@satoshilabs/trezor-firmware-1-3-6-20a7df6e692) -For usage with SSH, see the [following instructions](README-SSH.md). +## Installation -For usage with GPG, see the [following instructions](README-GPG.md). +First, make sure that the latest [trezorlib](https://pypi.python.org/pypi/trezor) Python package +is installed correctly (at least v0.6.6): + + $ apt-get install python-dev libusb-1.0-0-dev libudev-dev + $ pip install Cython trezor + $ pip install -U setuptools + +Then, install the latest [trezor_agent](https://pypi.python.org/pypi/trezor_agent) package: + + $ pip install trezor_agent + +Finally, verify that you are running the latest [TREZOR firmware](https://wallet.mytrezor.com/data/firmware/releases.json) version (at least v1.4.0): + + $ trezorctl get_features | head + vendor: "bitcointrezor.com" + major_version: 1 + minor_version: 4 + patch_version: 0 + ... + +## Usage + +For SSH, see the [following instructions](README-SSH.md). + +For GPG, see the [following instructions](README-GPG.md). Questions, suggestions and discussions are welcome: [![Chat](https://badges.gitter.im/romanz/trezor-agent.svg)](https://gitter.im/romanz/trezor-agent) + +## Troubleshooting + +If there is an import problem with the installed `protobuf` package, +see [this issue](https://github.com/romanz/trezor-agent/issues/28) for fixing it. diff --git a/setup.py b/setup.py index f131768..1501fdc 100644 --- a/setup.py +++ b/setup.py @@ -3,13 +3,14 @@ from setuptools import setup setup( name='trezor_agent', - version='0.6.5', + version='0.7.0', description='Using Trezor as hardware SSH agent', author='Roman Zeyde', author_email='roman.zeyde@gmail.com', url='http://github.com/romanz/trezor-agent', packages=['trezor_agent', 'trezor_agent.gpg'], - install_requires=['ecdsa>=0.13', 'ed25519>=1.4', 'Cython>=0.23.4', 'protobuf>=2.6.1', 'trezor>=0.6.12', 'semver>=2.2'], + install_requires=['ecdsa>=0.13', 'ed25519>=1.4', 'Cython>=0.23.4', 'protobuf>=3.0.0', 'trezor>=0.7.4', 'semver>=2.2', + 'keepkey>=0.7.3'], platforms=['POSIX'], classifiers=[ 'Environment :: Console', diff --git a/tox.ini b/tox.ini index 7cd753f..83fd3bb 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27,py34 +envlist = py27,py3 [pep8] max-line-length = 100 [testenv] diff --git a/trezor_agent/client.py b/trezor_agent/client.py index e8d2e35..f3fe760 100644 --- a/trezor_agent/client.py +++ b/trezor_agent/client.py @@ -31,9 +31,8 @@ class Client(object): return self def __exit__(self, *args): - """Forget PIN, shutdown screen and disconnect.""" + """Keep the session open (doesn't forget PIN).""" log.info('disconnected from %s', self.device_name) - self.client.clear_session() self.client.close() def get_identity(self, label, index=0): diff --git a/trezor_agent/factory.py b/trezor_agent/factory.py index c7d770e..e33ce00 100644 --- a/trezor_agent/factory.py +++ b/trezor_agent/factory.py @@ -1,4 +1,5 @@ -"""Thin wrapper around trezor/keepkey/ledger libraries.""" +"""Thin wrapper around trezor/keepkey libraries.""" +from __future__ import absolute_import import binascii import collections import logging diff --git a/trezor_agent/gpg/__main__.py b/trezor_agent/gpg/__main__.py index dd50309..6dbee00 100755 --- a/trezor_agent/gpg/__main__.py +++ b/trezor_agent/gpg/__main__.py @@ -89,6 +89,9 @@ def main(): args = p.parse_args() logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO, format='%(asctime)s %(levelname)-10s %(message)s') + log.warning('This GPG tool is still in EXPERIMENTAL mode, ' + 'so please note that the API and features may ' + 'change without backwards compatibility!') args.run(args) diff --git a/trezor_agent/gpg/keyring.py b/trezor_agent/gpg/keyring.py index f420fa2..eeea055 100644 --- a/trezor_agent/gpg/keyring.py +++ b/trezor_agent/gpg/keyring.py @@ -1,4 +1,5 @@ """Tools for doing signature using gpg-agent.""" +from __future__ import unicode_literals, absolute_import, print_function import binascii import io @@ -15,8 +16,8 @@ log = logging.getLogger(__name__) def get_agent_sock_path(sp=subprocess): """Parse gpgconf output to find out GPG agent UNIX socket path.""" - lines = sp.check_output(['gpgconf', '--list-dirs']).strip().split('\n') - dirs = dict(line.split(':', 1) for line in lines) + lines = sp.check_output(['gpgconf', '--list-dirs']).strip().split(b'\n') + dirs = dict(line.split(b':', 1) for line in lines) return dirs['agent-socket'] @@ -183,14 +184,14 @@ def gpg_command(args, env=None): def get_keygrip(user_id, sp=subprocess): """Get a keygrip of the primary GPG key of the specified user.""" args = gpg_command(['--list-keys', '--with-keygrip', user_id]) - output = sp.check_output(args).decode('ascii') + output = sp.check_output(args) return re.findall(r'Keygrip = (\w+)', output)[0] def gpg_version(sp=subprocess): """Get a keygrip of the primary GPG key of the specified user.""" args = gpg_command(['--version']) - output = sp.check_output(args).decode('ascii') + output = sp.check_output(args) line = output.split(b'\n')[0] # b'gpg (GnuPG) 2.1.11' return line.split(b' ')[-1] # b'2.1.11' diff --git a/trezor_agent/gpg/protocol.py b/trezor_agent/gpg/protocol.py index e0f0709..b4d4e01 100644 --- a/trezor_agent/gpg/protocol.py +++ b/trezor_agent/gpg/protocol.py @@ -47,9 +47,22 @@ def subpacket_byte(subpacket_type, value): return subpacket(subpacket_type, '>B', value) +def subpacket_prefix_len(item): + """Prefix subpacket length according to RFC 4880 section-5.2.3.1.""" + n = len(item) + if n >= 8384: + prefix = b'\xFF' + struct.pack('>L', n) + elif n >= 192: + n = n - 192 + prefix = struct.pack('BB', (n // 256) + 192, n % 256) + else: + prefix = struct.pack('B', n) + return prefix + item + + def subpackets(*items): """Serialize several GPG subpackets.""" - prefixed = [util.prefix_len('>B', item) for item in items] + prefixed = [subpacket_prefix_len(item) for item in items] return util.prefix_len('>H', b''.join(prefixed)) diff --git a/trezor_agent/gpg/tests/test_decode.py b/trezor_agent/gpg/tests/test_decode.py index 00d5eec..5480f80 100644 --- a/trezor_agent/gpg/tests/test_decode.py +++ b/trezor_agent/gpg/tests/test_decode.py @@ -5,7 +5,7 @@ import os import pytest -from .. import decode +from .. import decode, protocol from ... import util @@ -14,6 +14,15 @@ def test_subpackets(): assert decode.parse_subpackets(util.Reader(s)) == [b'\xAB\xCD', b'\xEF'] +def test_subpackets_prefix(): + for n in [0, 1, 2, 4, 5, 10, 191, 192, 193, + 255, 256, 257, 8383, 8384, 65530]: + item = b'?' * n # create dummy subpacket + prefixed = protocol.subpackets(item) + result = decode.parse_subpackets(util.Reader(io.BytesIO(prefixed))) + assert [item] == result + + def test_mpi(): s = io.BytesIO(b'\x00\x09\x01\x23') assert decode.parse_mpi(util.Reader(s)) == 0x123