Compare commits
184 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 | 7 years ago |
Jonathan Roelofs | ec97cd0c44 | 7 years ago |
Jonathan Roelofs | 4cd7dc02eb | 7 years ago |
Roman Zeyde | 8fe9460ed6 | 7 years ago |
Roman Zeyde | db16aa3d1c | 7 years ago |
Roman Zeyde | 41ccd2f332 | 7 years ago |
Roman Zeyde | cb14d1e00b | 7 years ago |
Roman Zeyde | cc6ee31deb | 7 years ago |
Roman Zeyde | b1f302151b | 7 years ago |
Roman Zeyde | fde50f04ab | 7 years ago |
Roman Zeyde | 7e42e455a1 | 7 years ago |
Roman Zeyde | 13cd6be2d1 | 7 years ago |
Roman Zeyde | 40469c4100 | 7 years ago |
Roman Zeyde | 0d059587a7 | 7 years ago |
Roman Zeyde | 283cb3d7e8 | 7 years ago |
Roman Zeyde | 51cc716e3f | 7 years ago |
Roman Zeyde | 8b4850b0ce | 7 years ago |
Roman Zeyde | f22c07e970 | 7 years ago |
Roman Zeyde | 29c7234ef4 | 7 years ago |
Roman Zeyde | 1942e3999b | 7 years ago |
Roman Zeyde | f2e52a88be | 7 years ago |
Roman Zeyde | b26a4cc7b0 | 7 years ago |
Roman Zeyde | c4dfca04f2 | 7 years ago |
Roman Zeyde | a1ecbf447e | 7 years ago |
Roman Zeyde | 1f9d457e92 | 7 years ago |
Roman Zeyde | cb3477fc69 | 7 years ago |
Roman Zeyde | 9bbc66cc16 | 7 years ago |
Roman Zeyde | 06afc971db | 7 years ago |
Dirk-Willem van Gulik | 2b51a85c26 | 7 years ago |
Dirk-Willem van Gulik | 1906e6d9b0 | 7 years ago |
Dirk-Willem van Gulik | b3f6e39b48 | 7 years ago |
Aitor Pazos | 8b03b649d5 | 7 years ago |
Roman Zeyde | 90cbc41b17 | 7 years ago |
Roman Zeyde | 4926d4f4d3 | 7 years ago |
Roman Zeyde | d52f295326 | 7 years ago |
Max Pixel | 47a8a53247 | 7 years ago |
Roman Zeyde | 9530c4d7db | 7 years ago |
Roman Zeyde | a2d0c1067d | 7 years ago |
Roman Zeyde | 3d5717dca1 | 7 years ago |
Roman Zeyde | 08fef24e39 | 7 years ago |
Roman Zeyde | bab46dae5c | 7 years ago |
Roman Zeyde | e2625cc521 | 7 years ago |
Roman Zeyde | 7ed76fe472 | 7 years ago |
Roman Zeyde | a5929eed62 | 7 years ago |
Roman Zeyde | 5f722f8ae1 | 7 years ago |
Roman Zeyde | 7212b2fa37 | 7 years ago |
Avishaan | 55e1c614a7 | 7 years ago |
Roman Zeyde | 8cf1f0463a | 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,51 @@
|
||||
# Design
|
||||
|
||||
Most cryptographic tools (such as gpg, ssh and openssl) allow the offloading of some key cryptographic steps to *engines* or *agents*. This is to allow sensitive operations, such as asking for a password or doing the actual encryption step, to be kept separate from the larger body of code. This makes it easier to secure those steps, move them onto hardware or easier to audit.
|
||||
|
||||
SSH and GPG do this by means of a simple interprocess communication protocol (usually a unix domain socket) and an agent (`ssh-agent`) or GPG key daemon (`gpg-agent`). The `trezor-agent` mimics these two protocols.
|
||||
|
||||
These two agents make the connection between the front end (e.g. a `gpg --sign` command, or an `ssh user@fqdn`). And then they wait for a request from the 'front end', and then do the actual asking for a password and subsequent using the private key to sign or decrypt something.
|
||||
|
||||
The various hardware wallets (Trezor, KeepKey and Ledger) each have the ability (as of Firmware 1.3.4) to use the NIST P-256 elliptic curve to sign, encrypt or decrypt. This curve can be used with S/MIME, GPG and SSH.
|
||||
|
||||
So when you `ssh` to a machine - rather than consult the normal ssh-agent (which in turn will use your private SSH key in files such as `~/.ssh/id_rsa`) -- the trezor-agent will aks your hardware wallet to use its private key to sign the challenge.
|
||||
|
||||
## Key Naming
|
||||
|
||||
`trezor-agent` goes to great length to avoid using the valuable parent key.
|
||||
|
||||
The rationale behind this is that `trezor-agent` is to some extent condemned to *blindly* signing any NONCE given to it (e.g. as part of a challenge respone, or as the hash/hmac of someting to sign).
|
||||
|
||||
And doing so with the master private key is risky - as rogue (ssh) server could possibly provide a doctored NONCE that happens to be tied to a transaction or something else.
|
||||
|
||||
It therefore uses only derived child keys pairs instead (according to the [BIP-0032: Hierarchical Deterministic Wallets][1] system) - and ones on different leafs. So the parent key is only used within the device for creating the child keys - and not exposed in any way to `trezor-agent`.
|
||||
|
||||
### SSH
|
||||
|
||||
It is common for SSH users to use one (or a few) private keys with SSH on all servers they log into. The `trezor-agent` is slightly more cautious and derives a child key that is *unique* to the server and username you are logging into from your master private key on the device.
|
||||
|
||||
So taking a commmand such as:
|
||||
|
||||
$ trezor-agent -c user@fqdn.com
|
||||
|
||||
The `trezor-agent` will take the `user`@`fqdn.com`; canonicalise it (e.g. to add the ssh default port number if none was specified) and then apply some simple hashing (See [SLIP-0013 : Authentication using deterministic hierarchy][2]). The resulting 128bit hash is then used to construct a lead 'HD node' that contains an extened public private *child* key.
|
||||
|
||||
This way they keypair is specific to the server/hostname/port and protocol combination used. And it is this private key that is used to sign the nonce passed by the SSH server (as opposed to the master key).
|
||||
|
||||
The `trezor-agent` then instructs SSH to connect to the server. It will then engage in the normal challenge response process, ask the hardware wallet to blindly sign any nonce flashed by the server with the derived child private key and return this to the server. It then hands over to normal SSH for the rest of the logged in session.
|
||||
|
||||
### GPG
|
||||
|
||||
GPG uses much the same approach as SSH, except in this case it relies on [SLIP-0017 : ECDH using deterministic hierarchy][3] for the mapping to an ECDH key and it maps these to the normal GPG child key infrastructure.
|
||||
|
||||
Note: Keepkey does not support en-/de-cryption at this time.
|
||||
|
||||
### Index
|
||||
|
||||
The canonicalisation process ([SLIP-0013][2] and [SLIP-0017][3]) of an email address or ssh address allows for the mixing in of an extra 'index' - a unsigned 32 bit number. This allows one to have multiple, different keys, for the same address.
|
||||
|
||||
This feature is currently not used -- it is set to '0'. This may change in the future.
|
||||
|
||||
[1]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
|
||||
[2]: https://github.com/satoshilabs/slips/blob/master/slip-0013.md
|
||||
[3]: https://github.com/satoshilabs/slips/blob/master/slip-0017.md
|
@ -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 as Error
|
||||
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