Compare commits
145 Commits
Author | SHA1 | Date |
---|---|---|
Roman Zeyde | 71f357c1bf | 6 years ago |
Eli Boyarski | 8f1d008eb2 | 6 years ago |
Roman Zeyde | 7a351acf15 | 6 years ago |
Roman Zeyde | 7f9aa2b147 | 6 years ago |
Roman Zeyde | eed168341c | 6 years ago |
matejcik | 8b85090fba | 6 years ago |
matejcik | 8708b1e16d | 6 years ago |
Roman Zeyde | 03e7fc48e9 | 6 years ago |
Roman Zeyde | 4968ca7ff3 | 6 years ago |
Roman Zeyde | 6b6d9f5d20 | 6 years ago |
Roman Zeyde | c22109df24 | 6 years ago |
Roman Zeyde | 47ce035e79 | 6 years ago |
Roman Zeyde | 36cbba6c57 | 6 years ago |
Roman Zeyde | 6afe20350b | 6 years ago |
Roman Zeyde | fa171e8923 | 6 years ago |
Roman Zeyde | f0bda9a3e6 | 6 years ago |
Roman Zeyde | 71b56e15d7 | 6 years ago |
Roman Zeyde | 3b9c00e02a | 6 years ago |
Roman Zeyde | dcee59a19e | 6 years ago |
Roman Zeyde | a274de30b8 | 6 years ago |
Roman Zeyde | 4fe9e437ad | 6 years ago |
Roman Zeyde | d04527a8ed | 6 years ago |
Roman Zeyde | 3329c29cb4 | 6 years ago |
Roman Zeyde | df2cb52f8d | 6 years ago |
Roman Zeyde | f36ef4ffe0 | 6 years ago |
Roman Zeyde | f74de828fc | 6 years ago |
Roman Zeyde | 912b1cde7a | 6 years ago |
Roman Zeyde | b7a8c42893 | 6 years ago |
Roman Zeyde | 1e6c4e6930 | 6 years ago |
Roman Zeyde | a8f19e4150 | 6 years ago |
Roman Zeyde | 6a9fdf75e2 | 6 years ago |
Roman Zeyde | 6bc5b6af5e | 6 years ago |
Roman Zeyde | 8672a6901a | 6 years ago |
Roman Zeyde | 672af98ad7 | 6 years ago |
Roman Zeyde | ed531cfff8 | 6 years ago |
Bram | bd1ae0f091 | 6 years ago |
Roman Zeyde | 0c762e8998 | 6 years ago |
Roman Zeyde | bd0df4f801 | 6 years ago |
Roman Zeyde | 3d1639d271 | 6 years ago |
Roman Zeyde | bea899d1ef | 6 years ago |
Roman Zeyde | ccc2174775 | 6 years ago |
Roman Zeyde | afa3fdb89c | 6 years ago |
Roman Zeyde | 2ca3941cfa | 6 years ago |
Roman Zeyde | b1bd6cb690 | 6 years ago |
Roman Zeyde | 766536d2c4 | 6 years ago |
Roman Zeyde | 91f70e7a96 | 6 years ago |
Roman Zeyde | cf5bfd960a | 6 years ago |
pruflyos | 4bd769f138 | 6 years ago |
Bram | 91b850f184 | 6 years ago |
Roman Zeyde | c6bb090dfc | 6 years ago |
Timothy Hobbs | fef4fd06c9 | 6 years ago |
Roman Zeyde | bc691ae795 | 6 years ago |
Roman Zeyde | 61e516e200 | 6 years ago |
Roman Zeyde | 543ff7021d | 6 years ago |
Roman Zeyde | 2e0cfc8088 | 6 years ago |
Roman Zeyde | 18f33f8a08 | 6 years ago |
Roman Zeyde | 2973413995 | 6 years ago |
Jakub Vysoký | 2360693dc5 | 6 years ago |
Roman Zeyde | 7443fc6512 | 6 years ago |
Roman Zeyde | 5efb752979 | 6 years ago |
Roman Zeyde | 4546cd674b | 6 years ago |
Roman Zeyde | 5dba12f144 | 6 years ago |
Roman Zeyde | 887561de9f | 6 years ago |
Roman Zeyde | 6d730e0a5b | 6 years ago |
Roman Zeyde | d0732d16e8 | 6 years ago |
Roman Zeyde | dafb80ad7a | 6 years ago |
Roman Zeyde | df6249b071 | 6 years ago |
rendaw | 942f01418b | 6 years ago |
rendaw | 93b548b737 | 6 years ago |
rendaw | 329f07249a | 6 years ago |
rendaw | a1f7088d33 | 6 years ago |
rendaw | 25f066e113 | 6 years ago |
Roman Zeyde | 0699273d49 | 6 years ago |
Roman Zeyde | 92c352e860 | 6 years ago |
Roman Zeyde | 34c03a462c | 6 years ago |
Roman Zeyde | 51dbecd4c2 | 6 years ago |
Roman Zeyde | ceae65aa5a | 6 years ago |
Roman Zeyde | d0497b0137 | 6 years ago |
Roman Zeyde | 870152a7af | 6 years ago |
Roman Zeyde | cbdc52c0a4 | 6 years ago |
Roman Zeyde | 0c9fc33757 | 6 years ago |
Roman Zeyde | 17ea941add | 6 years ago |
Roman Zeyde | 64064b5ecc | 6 years ago |
Roman Zeyde | 601a2b1336 | 6 years ago |
Roman Zeyde | 2e688ccac9 | 6 years ago |
Roman Zeyde | b6181bb5b5 | 6 years ago |
Roman Zeyde | b6da299cb0 | 6 years ago |
Roman Zeyde | 04627f0899 | 6 years ago |
Roman Zeyde | 54ce6f2cec | 6 years ago |
Roman Zeyde | a1047ba7b1 | 6 years ago |
Roman Zeyde | e90bd0cd81 | 6 years ago |
slush | 66e3e60370 | 6 years ago |
slush | 3f1604d609 | 6 years ago |
slush | d0f4cccfd2 | 6 years ago |
Roman Zeyde | 08d81c992c | 6 years ago |
Roman Zeyde | 55a899f929 | 6 years ago |
Roman Zeyde | e7604dff68 | 6 years ago |
rendaw | 8849545700 | 6 years ago |
rendaw | d109cd73b5 | 6 years ago |
rendaw | 95e98d6eda | 6 years ago |
rendaw | 9e78d52721 | 6 years ago |
Roman Zeyde | 2a76ef6819 | 6 years ago |
Roman Zeyde | 654a3c465a | 6 years ago |
Roman Zeyde | 2168115b06 | 6 years ago |
Roman Zeyde | 4a9140c42d | 6 years ago |
Roman Zeyde | b20d98bf57 | 6 years ago |
Roman Zeyde | 199fb299c3 | 6 years ago |
rendaw | 06e169f141 | 6 years ago |
rendaw | 131111bc0e | 6 years ago |
Roman Zeyde | f4208009e0 | 6 years ago |
Roman Zeyde | 73d60dbec0 | 6 years ago |
Roman Zeyde | 34ea224290 | 6 years ago |
Roman Zeyde | 7803026f61 | 6 years ago |
Roman Zeyde | 34ce1005fd | 6 years ago |
Roman Zeyde | 8677c8ebaa | 6 years ago |
Serge Pokhodyaev | 6363eb0d4a | 6 years ago |
Serge Pokhodyaev | a32bfc749b | 6 years ago |
Roman Zeyde | 75d117ad0d | 6 years ago |
Roman Zeyde | cefc5f180a | 6 years ago |
Roman Zeyde | 0f5c71b748 | 6 years ago |
Roman Zeyde | d5f97b7efa | 6 years ago |
Roman Zeyde | 4a12bfa0b7 | 6 years ago |
Roman Zeyde | cac889ff7d | 6 years ago |
Roman Zeyde | 92c6e680ed | 6 years ago |
Roman Zeyde | bf294beb56 | 6 years ago |
Roman Zeyde | 713345918e | 6 years ago |
Roman Zeyde | eb60c2f475 | 6 years ago |
Roman Zeyde | 6d8d43db9b | 6 years ago |
Roman Zeyde | 3e67bc9f0e | 6 years ago |
Roman Zeyde | 38b50485de | 6 years ago |
Roman Zeyde | 9cba27b31a | 6 years ago |
Eli Boyarski | 00a65a9820 | 6 years ago |
Roman Zeyde | 52ad601e66 | 6 years ago |
Eli Boyarski | d96a2820ff | 6 years ago |
Roman Zeyde | 29aaf777ad | 6 years ago |
Roman Zeyde | 385fc9457b | 6 years ago |
Jonathan Roelofs | 9cf73f677a | 6 years ago |
Jonathan Roelofs | ec97cd0c44 | 6 years ago |
Jonathan Roelofs | 4cd7dc02eb | 6 years ago |
Roman Zeyde | 8fe9460ed6 | 6 years ago |
Roman Zeyde | db16aa3d1c | 6 years ago |
Roman Zeyde | 41ccd2f332 | 6 years ago |
Roman Zeyde | cb14d1e00b | 7 years ago |
Roman Zeyde | cc6ee31deb | 7 years ago |
Roman Zeyde | b1f302151b | 7 years ago |
@ -0,0 +1,7 @@
|
||||
[bumpversion]
|
||||
commit = True
|
||||
tag = True
|
||||
current_version = 0.12.0
|
||||
|
||||
[bumpversion:file:setup.py]
|
||||
|
@ -1,5 +1,5 @@
|
||||
[MESSAGES CONTROL]
|
||||
disable=invalid-name, missing-docstring, locally-disabled, unbalanced-tuple-unpacking,no-else-return
|
||||
disable=invalid-name, missing-docstring, locally-disabled, unbalanced-tuple-unpacking,no-else-return,fixme,duplicate-code
|
||||
|
||||
[SIMILARITIES]
|
||||
min-similarity-lines=5
|
||||
|
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
|
||||
agent = 'trezor-gpg-agent'
|
||||
binary = 'neopg'
|
||||
|
||||
if sys.argv[1:2] == ['agent']:
|
||||
os.execvp(agent, [agent, '-vv'] + sys.argv[2:])
|
||||
else:
|
||||
# HACK: pass this script's path as argv[0], so it will be invoked again
|
||||
# when NeoPG tries to run its own agent:
|
||||
# https://github.com/das-labor/neopg/blob/1fe50460abe01febb118641e37aa50bc429a1786/src/neopg.cpp#L114
|
||||
# https://github.com/das-labor/neopg/blob/1fe50460abe01febb118641e37aa50bc429a1786/legacy/gnupg/common/asshelp.cpp#L217
|
||||
os.execvp(binary, [__file__, 'gpg2'] + sys.argv[1:])
|
@ -0,0 +1,31 @@
|
||||
# NeoPG experimental support
|
||||
|
||||
1. Download build and install NeoPG from [source code](https://github.com/das-labor/neopg#installation).
|
||||
|
||||
2. Generate Ed25519-based identity (using a [special wrapper](https://github.com/romanz/trezor-agent/blob/c22109df24c6eb8263aa40183a016be3437b1a0c/contrib/neopg-trezor) to invoke TREZOR-based agent):
|
||||
|
||||
```bash
|
||||
$ export NEOPG_BINARY=$PWD/contrib/neopg-trezor
|
||||
$ $NEOPG_BINARY --help
|
||||
|
||||
$ export GNUPGHOME=/tmp/homedir
|
||||
$ trezor-gpg init "FooBar" -e ed25519
|
||||
sec ed25519 2018-07-01 [SC]
|
||||
802AF7E2DCF4491FFBB2F032341E95EF57CD7D5E
|
||||
uid [ultimate] FooBar
|
||||
ssb cv25519 2018-07-01 [E]
|
||||
```
|
||||
|
||||
3. Sign and verify signatures:
|
||||
```
|
||||
$ $NEOPG_BINARY -v --detach-sign FILE
|
||||
neopg: starting agent '/home/roman/Code/trezor/trezor-agent/contrib/neopg-trezor'
|
||||
neopg: using pgp trust model
|
||||
neopg: writing to 'FILE.sig'
|
||||
neopg: EDDSA/SHA256 signature from: "341E95EF57CD7D5E FooBar"
|
||||
|
||||
$ $NEOPG_BINARY --verify FILE.sig FILE
|
||||
neopg: Signature made Sun Jul 1 11:52:51 2018 IDT
|
||||
neopg: using EDDSA key 802AF7E2DCF4491FFBB2F032341E95EF57CD7D5E
|
||||
neopg: Good signature from "FooBar" [ultimate]
|
||||
```
|
@ -0,0 +1,69 @@
|
||||
# Custom PIN entry
|
||||
|
||||
In order to use the default GPG pinentry program, install one of the following Linux packages:
|
||||
|
||||
```
|
||||
$ apt install pinentry-{curses,gnome3,qt}
|
||||
```
|
||||
|
||||
or (on macOS):
|
||||
|
||||
```
|
||||
$ brew install pinentry
|
||||
```
|
||||
|
||||
By default a standard GPG PIN entry program is used when entering your Trezor PIN, but it's difficult to use if you don't have a numeric keypad or want to use your mouse.
|
||||
|
||||
You can specify a custom PIN entry program such as [trezor-gpg-pinentry-tk](https://github.com/rendaw/trezor-gpg-pinentry-tk) (and separately, a passphrase entry program) to match your workflow.
|
||||
|
||||
The below examples use `trezor-gpg-pinentry-tk` but any GPG compatible PIN entry can be used.
|
||||
|
||||
##### 1. Install the PIN entry
|
||||
|
||||
Run
|
||||
|
||||
```
|
||||
pip install trezor-gpg-pinentry-tk
|
||||
```
|
||||
|
||||
##### 2. SSH
|
||||
|
||||
Add the flag `--pin-entry-binary trezor-gpg-pinentry-tk` to all calls to `trezor-agent`.
|
||||
|
||||
To automatically use this flag, add the line `pinentry=trezor-gpg-pinentry-tk` to `~/.ssh/agent.config`. **Note** this is currently broken due to [this dependency issue](https://github.com/bw2/ConfigArgParse/issues/114).
|
||||
|
||||
If you run the SSH agent with Systemd you'll need to add `--pin-entry-binary` to the `ExecStart` command. You may also need to add this line:
|
||||
|
||||
```
|
||||
Environment="DISPLAY=:0"
|
||||
```
|
||||
|
||||
to the `[Service]` section to tell the PIN entry program how to connect to the X11 server.
|
||||
|
||||
##### 3. GPG
|
||||
|
||||
If you haven't completed initialization yet, run:
|
||||
|
||||
```
|
||||
$ (trezor|keepkey|ledger)-gpg init --pin-entry-binary trezor-gpg-pinentry-tk "Roman Zeyde <roman.zeyde@gmail.com>"
|
||||
```
|
||||
|
||||
to configure the PIN entry at the same time.
|
||||
|
||||
Otherwise, open `$GNUPGHOME/trezor/run-agent.sh` and change the `--pin-entry-binary` option to `trezor-gpg-pinentry-tk` and run:
|
||||
|
||||
```
|
||||
killall trezor-gpg-agent
|
||||
```
|
||||
|
||||
##### 4. Troubleshooting
|
||||
|
||||
Any problems running the PIN entry program with GPG should appear in `$HOME/.gnupg/trezor/gpg-agent.log`.
|
||||
|
||||
You can get similar logs for SSH by specifying `--log-file` in the SSH command line.
|
||||
|
||||
The passphrase is cached by the agent (after its first entry), which needs to be restarted in order to reset the passphrase:
|
||||
```
|
||||
$ killall trezor-agent # (for SSH)
|
||||
$ killall trezor-gpg-agent # (for GPG)
|
||||
```
|
@ -1,3 +1,3 @@
|
||||
"""Cryptographic hardware device management."""
|
||||
|
||||
from . import interface
|
||||
from . import interface, ui
|
||||
|
@ -1,10 +1,28 @@
|
||||
"""TREZOR-related definitions."""
|
||||
|
||||
# pylint: disable=unused-import,import-error
|
||||
import os
|
||||
import logging
|
||||
|
||||
from trezorlib.client import CallException, PinException
|
||||
from trezorlib.client import TrezorClient as Client
|
||||
from trezorlib.messages_pb2 import PassphraseAck, PinMatrixAck
|
||||
from trezorlib.transport_bridge import BridgeTransport
|
||||
from trezorlib.transport_hid import HidTransport
|
||||
from trezorlib.types_pb2 import IdentityType
|
||||
from trezorlib.messages import IdentityType, PassphraseAck, PinMatrixAck, PassphraseStateAck
|
||||
|
||||
try:
|
||||
from trezorlib.transport import get_transport
|
||||
except ImportError:
|
||||
from trezorlib.device import TrezorDevice
|
||||
get_transport = TrezorDevice.find_by_path
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def find_device():
|
||||
"""Selects a transport based on `TREZOR_PATH` environment variable.
|
||||
|
||||
If unset, picks first connected device.
|
||||
"""
|
||||
try:
|
||||
return get_transport(os.environ.get("TREZOR_PATH"))
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
log.debug("Failed to find a Trezor device: %s", e)
|
||||
|
@ -0,0 +1,129 @@
|
||||
"""UIs for PIN/passphrase entry."""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from .. import util
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UI:
|
||||
"""UI for PIN/passphrase entry (for TREZOR devices)."""
|
||||
|
||||
def __init__(self, device_type, config=None):
|
||||
"""C-tor."""
|
||||
default_pinentry = 'pinentry' # by default, use GnuPG pinentry tool
|
||||
if config is None:
|
||||
config = {}
|
||||
self.pin_entry_binary = config.get('pin_entry_binary',
|
||||
default_pinentry)
|
||||
self.passphrase_entry_binary = config.get('passphrase_entry_binary',
|
||||
default_pinentry)
|
||||
self.options_getter = create_default_options_getter()
|
||||
self.device_name = device_type.__name__
|
||||
|
||||
def get_pin(self, name=None):
|
||||
"""Ask the user for (scrambled) PIN."""
|
||||
description = (
|
||||
'Use the numeric keypad to describe number positions.\n'
|
||||
'The layout is:\n'
|
||||
' 7 8 9\n'
|
||||
' 4 5 6\n'
|
||||
' 1 2 3')
|
||||
return interact(
|
||||
title='{} PIN'.format(name or self.device_name),
|
||||
prompt='PIN:',
|
||||
description=description,
|
||||
binary=self.pin_entry_binary,
|
||||
options=self.options_getter())
|
||||
|
||||
def get_passphrase(self, name=None):
|
||||
"""Ask the user for passphrase."""
|
||||
return interact(
|
||||
title='{} passphrase'.format(name or self.device_name),
|
||||
prompt='Passphrase:',
|
||||
description=None,
|
||||
binary=self.passphrase_entry_binary,
|
||||
options=self.options_getter())
|
||||
|
||||
|
||||
def create_default_options_getter():
|
||||
"""Return current TTY and DISPLAY settings for GnuPG pinentry."""
|
||||
options = []
|
||||
try:
|
||||
ttyname = subprocess.check_output(args=['tty']).strip()
|
||||
options.append(b'ttyname=' + ttyname)
|
||||
except subprocess.CalledProcessError as e:
|
||||
log.warning('no TTY found: %s', e)
|
||||
|
||||
display = os.environ.get('DISPLAY')
|
||||
if display is not None:
|
||||
options.append('display={}'.format(display).encode('ascii'))
|
||||
else:
|
||||
log.warning('DISPLAY not defined')
|
||||
|
||||
log.info('using %s for pinentry options', options)
|
||||
return lambda: options
|
||||
|
||||
|
||||
def write(p, line):
|
||||
"""Send and flush a single line to the subprocess' stdin."""
|
||||
log.debug('%s <- %r', p.args, line)
|
||||
p.stdin.write(line)
|
||||
p.stdin.flush()
|
||||
|
||||
|
||||
class UnexpectedError(Exception):
|
||||
"""Unexpected response."""
|
||||
|
||||
|
||||
def expect(p, prefixes, confidential=False):
|
||||
"""Read a line and return it without required prefix."""
|
||||
resp = p.stdout.readline()
|
||||
log.debug('%s -> %r', p.args, resp if not confidential else '********')
|
||||
for prefix in prefixes:
|
||||
if resp.startswith(prefix):
|
||||
return resp[len(prefix):]
|
||||
raise UnexpectedError(resp)
|
||||
|
||||
|
||||
def interact(title, description, prompt, binary, options):
|
||||
"""Use GPG pinentry program to interact with the user."""
|
||||
args = [binary]
|
||||
p = subprocess.Popen(args=args,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
env=os.environ)
|
||||
p.args = args # TODO: remove after Python 2 deprecation.
|
||||
expect(p, [b'OK'])
|
||||
|
||||
title = util.assuan_serialize(title.encode('ascii'))
|
||||
write(p, b'SETTITLE ' + title + b'\n')
|
||||
expect(p, [b'OK'])
|
||||
|
||||
if description:
|
||||
description = util.assuan_serialize(description.encode('ascii'))
|
||||
write(p, b'SETDESC ' + description + b'\n')
|
||||
expect(p, [b'OK'])
|
||||
|
||||
if prompt:
|
||||
prompt = util.assuan_serialize(prompt.encode('ascii'))
|
||||
write(p, b'SETPROMPT ' + prompt + b'\n')
|
||||
expect(p, [b'OK'])
|
||||
|
||||
log.debug('setting %d options', len(options))
|
||||
for opt in options:
|
||||
write(p, b'OPTION ' + opt + b'\n')
|
||||
expect(p, [b'OK', b'ERR'])
|
||||
|
||||
write(p, b'GETPIN\n')
|
||||
pin = expect(p, [b'OK', b'D '], confidential=True)
|
||||
|
||||
p.communicate() # close stdin and wait for the process to exit
|
||||
exit_code = p.wait()
|
||||
if exit_code:
|
||||
raise subprocess.CalledProcessError(exit_code, binary)
|
||||
|
||||
return pin.decode('ascii').strip()
|
@ -0,0 +1,11 @@
|
||||
from .. import agent
|
||||
|
||||
|
||||
def test_sig_encode():
|
||||
SIG = (
|
||||
b'(7:sig-val(5:ecdsa(1:r32:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x0c)(1:s32:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00")))')
|
||||
assert agent.sig_encode(12, 34) == SIG
|
@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
set -eux
|
||||
rm -rv dist/*
|
||||
python3 setup.py sdist
|
||||
gpg2 -v --detach-sign -a dist/*.tar.gz
|
||||
twine upload dist/*
|
Loading…
Reference in New Issue