Merge branch 'master' into python3
Conflicts: setup.py
This commit is contained in:
3
setup.py
3
setup.py
@@ -8,7 +8,8 @@ setup(
|
||||
author='Roman Zeyde',
|
||||
author_email='roman.zeyde@gmail.com',
|
||||
url='http://github.com/romanz/trezor-agent',
|
||||
packages=['trezor_agent'],
|
||||
packages=['trezor_agent', 'trezor_agent.gpg'],
|
||||
scripts=['trezor_agent/gpg/trezor-git-gpg-wrapper.sh'],
|
||||
install_requires=['ecdsa>=0.13', 'ed25519>=1.4', 'Cython>=0.23.4', 'protobuf>=3.0.0b2.post2', 'trezor>=0.6.12', 'semver>=2.2'],
|
||||
platforms=['POSIX'],
|
||||
classifiers=[
|
||||
|
||||
@@ -1,22 +1,56 @@
|
||||
# Generate new stand-alone GPG identity
|
||||
# Using TREZOR as hardware GPG agent
|
||||
|
||||
## Generate new GPG signing key:
|
||||
First, verify that you have GPG 2.1+ [installed](https://gist.github.com/vt0r/a2f8c0bcb1400131ff51):
|
||||
```
|
||||
$ USER_ID="Satoshi Nakamoto <satoshi@nakamoto.bit>"
|
||||
$ trezor-gpg create "${USER_ID}" > identity.pub # create new TREZOR-based GPG identity
|
||||
$ gpg2 --import identity.pub # import into local GPG public keyring
|
||||
$ gpg2 --edit "${USER_ID}" trust # OPTIONAL: mark the key as trusted
|
||||
$ gpg2 --version | head -n1
|
||||
gpg (GnuPG) 2.1.11
|
||||
```
|
||||
|
||||
# Generate new subkey for existing GPG identity
|
||||
Install the latest development version of `trezor-agent`:
|
||||
```
|
||||
$ USER_ID="Satoshi Nakamoto <satoshi@nakamoto.bit>"
|
||||
$ gpg2 --list-keys "${USER_ID}" # make sure this identity already exists
|
||||
$ trezor-gpg create --subkey "${USER_ID}" > identity.pub # create new TREZOR-based GPG public key
|
||||
$ gpg2 --import identity.pub # append it to existing identity
|
||||
$ pip install git+https://github.com/romanz/trezor-agent.git@master
|
||||
```
|
||||
|
||||
# Generate signatures using the TREZOR device
|
||||
Define your GPG user ID as an environment variable:
|
||||
```
|
||||
$ trezor-gpg sign EXAMPLE > EXAMPLE.sig # confirm signature using the device
|
||||
$ gpg2 --verify EXAMPLE.sig # verify using standard GPG binary
|
||||
$ export TREZOR_GPG_USER_ID="John Doe <john@doe.bit>"
|
||||
```
|
||||
|
||||
There are two ways to generate TREZOR-based GPG public keys, as described below.
|
||||
|
||||
### (1) create new GPG identity:
|
||||
```
|
||||
$ trezor-gpg create > identity.pub # create new TREZOR-based GPG identity
|
||||
$ gpg2 --import identity.pub # import into local GPG public keyring
|
||||
$ gpg2 --list-keys # verify that the new identity is created correctly
|
||||
$ gpg2 --edit "${TREZOR_GPG_USER_ID}" trust # OPTIONAL: mark the key as trusted
|
||||
```
|
||||
[](https://asciinema.org/a/44880)
|
||||
|
||||
### (2) create new subkey for an existing GPG identity:
|
||||
```
|
||||
$ gpg2 --list-keys "${TREZOR_GPG_USER_ID}" # make sure this identity already exists
|
||||
$ trezor-gpg create --subkey > identity.pub # create new TREZOR-based GPG subkey
|
||||
$ gpg2 --import identity.pub # append it to an existing identity
|
||||
$ gpg2 --list-keys "${TREZOR_GPG_USER_ID}" # verify that the new subkey is added to keyring
|
||||
```
|
||||
[](https://asciinema.org/a/8t78s6pqo5yocisaiolqnjp63)
|
||||
|
||||
## Generate GPG signatures using a TREZOR device:
|
||||
```
|
||||
$ trezor-gpg sign EXAMPLE # confirm signature using the device
|
||||
$ gpg2 --verify EXAMPLE.asc # verify using standard GPG binary
|
||||
```
|
||||
[](https://asciinema.org/a/f1unkptesb7anq09i8wugoko6)
|
||||
|
||||
## Git commit & tag signatures:
|
||||
Git can use GPG to sign and verify commits and tags (see [here](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work)):
|
||||
```
|
||||
$ git config --local gpg.program "trezor-git-gpg-wrapper.sh"
|
||||
$ git commit --gpg-sign # create GPG-signed commit
|
||||
$ git log --show-signature -1 # verify commit signature
|
||||
$ git tag --sign "TAG" # create GPG-signed tag
|
||||
$ git verify-tag "TAG" # verify tag signature
|
||||
```
|
||||
[](https://asciinema.org/a/44879)
|
||||
|
||||
@@ -123,10 +123,11 @@ def sign(sock, keygrip, digest):
|
||||
line = _unescape(line)
|
||||
log.debug('line: %r', line)
|
||||
prefix, sig = line.split(' ', 1)
|
||||
assert prefix == 'D'
|
||||
if prefix != 'D':
|
||||
raise ValueError(line)
|
||||
|
||||
sig, leftover = _parse(sig)
|
||||
assert not leftover
|
||||
assert not leftover, leftover
|
||||
return _parse_sig(sig)
|
||||
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""Check GPG v2 signature for a given public key."""
|
||||
import argparse
|
||||
import logging
|
||||
|
||||
from . import decode
|
||||
from .. import util
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function."""
|
||||
p = argparse.ArgumentParser()
|
||||
p.add_argument('pubkey')
|
||||
p.add_argument('-v', '--verbose', action='store_true', default=False)
|
||||
args = p.parse_args()
|
||||
logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO,
|
||||
format='%(asctime)s %(levelname)-10s %(message)s')
|
||||
stream = open(args.pubkey, 'rb')
|
||||
parser = decode.parse_packets(util.Reader(stream))
|
||||
pubkey, userid, sig1, subkey, sig2 = parser
|
||||
|
||||
digest = decode.digest_packets([pubkey, userid, sig1])
|
||||
assert sig1['hash_prefix'] == digest[:2]
|
||||
decode.verify_digest(
|
||||
pubkey=pubkey, digest=digest,
|
||||
signature=sig1['sig'], label='GPG public key (self sig)')
|
||||
|
||||
digest = decode.digest_packets([pubkey, subkey, sig2])
|
||||
assert sig2['hash_prefix'] == digest[:2]
|
||||
decode.verify_digest(
|
||||
pubkey=pubkey, digest=digest,
|
||||
signature=sig2['sig'], label='GPG subkey (1st sig)')
|
||||
|
||||
sig3, = sig2['embedded']
|
||||
digest = decode.digest_packets([pubkey, subkey, sig3])
|
||||
decode.verify_digest(
|
||||
pubkey=subkey, digest=digest,
|
||||
signature=sig3['sig'], label='GPG subkey (2nd sig)')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
CREATED=1460731897 # needed for consistent public key creation
|
||||
NAME="trezor_demo" # will be used as GPG user id and public key name
|
||||
|
||||
echo "Hello GPG World!" > EXAMPLE
|
||||
# Create, sign and export the public key
|
||||
trezor-gpg $NAME --time $CREATED -o $NAME.pub
|
||||
|
||||
# Install GPG v2.1 (modern) and import the public key
|
||||
gpg2 --import $NAME.pub
|
||||
gpg2 --list-keys $NAME
|
||||
# gpg2 --edit-key $NAME trust # optional: mark it as trusted
|
||||
|
||||
# Perform actual GPG signature using TREZOR device
|
||||
trezor-gpg $NAME EXAMPLE
|
||||
|
||||
# Verify signature using GPG2 binary
|
||||
gpg2 --verify EXAMPLE.sig
|
||||
@@ -251,7 +251,7 @@ def _make_signature(signer_func, data_to_sign, public_algo,
|
||||
|
||||
log.debug('hashing %d bytes', len(data_to_hash))
|
||||
digest = hashlib.sha256(data_to_hash).digest()
|
||||
log.info('SHA256 digest to sign: %s', util.hexlify(digest))
|
||||
log.info('signing digest: %s', util.hexlify(digest))
|
||||
sig = signer_func(digest=digest)
|
||||
|
||||
return bytes(header + hashed + unhashed +
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""A simple wrapper for Git commit/tag GPG signing."""
|
||||
import logging
|
||||
import subprocess as sp
|
||||
import sys
|
||||
|
||||
from . import decode, encode
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function."""
|
||||
logging.basicConfig(level=logging.INFO,
|
||||
format='%(asctime)s %(levelname)-10s %(message)s')
|
||||
|
||||
log.debug('sys.argv: %s', sys.argv)
|
||||
args = sys.argv[1:]
|
||||
if '--verify' in args:
|
||||
return sp.call(['gpg2'] + args)
|
||||
else:
|
||||
command = args[0]
|
||||
user_id = ' '.join(args[1:])
|
||||
assert command == '-bsau' # --detach-sign --sign --armor --local-user
|
||||
pubkey = decode.load_from_gpg(user_id, use_custom=True)
|
||||
s = encode.Signer.from_public_key(user_id=user_id, pubkey=pubkey)
|
||||
|
||||
data = sys.stdin.read()
|
||||
sig = s.sign(data)
|
||||
sig = encode.armor(sig, 'SIGNATURE')
|
||||
sys.stdout.write(sig)
|
||||
s.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -5,6 +5,7 @@ import logging
|
||||
import subprocess as sp
|
||||
import sys
|
||||
import time
|
||||
import os
|
||||
|
||||
from . import decode, encode
|
||||
|
||||
@@ -13,17 +14,18 @@ log = logging.getLogger(__name__)
|
||||
|
||||
def run_create(args):
|
||||
"""Generate a new pubkey for a new/existing GPG identity."""
|
||||
s = encode.Signer(user_id=args.user_id, created=args.time,
|
||||
user_id = os.environ['TREZOR_GPG_USER_ID']
|
||||
s = encode.Signer(user_id=user_id, created=args.time,
|
||||
curve_name=args.ecdsa_curve)
|
||||
if args.subkey:
|
||||
subkey = s.subkey()
|
||||
primary = sp.check_output(['gpg2', '--export', args.user_id])
|
||||
primary = sp.check_output(['gpg2', '--export', user_id])
|
||||
result = primary + subkey
|
||||
else:
|
||||
result = s.export()
|
||||
s.close()
|
||||
|
||||
return encode.armor(result, 'PUBLIC KEY BLOCK')
|
||||
sys.stdout.write(encode.armor(result, 'PUBLIC KEY BLOCK'))
|
||||
|
||||
|
||||
def run_sign(args):
|
||||
@@ -39,7 +41,19 @@ def run_sign(args):
|
||||
|
||||
sig = encode.armor(sig, 'SIGNATURE')
|
||||
decode.verify(pubkey=pubkey, signature=sig, original_data=data)
|
||||
return sig
|
||||
|
||||
filename = '-' # write to stdout
|
||||
if args.output:
|
||||
filename = args.output
|
||||
elif args.filename:
|
||||
filename = args.filename + '.asc'
|
||||
|
||||
if filename == '-':
|
||||
output = sys.stdout
|
||||
else:
|
||||
output = open(filename, 'wb')
|
||||
|
||||
output.write(sig)
|
||||
|
||||
|
||||
def main():
|
||||
@@ -49,8 +63,6 @@ def main():
|
||||
subparsers = p.add_subparsers()
|
||||
|
||||
create = subparsers.add_parser('create')
|
||||
create.add_argument('user_id', help='e.g. '
|
||||
'"Satoshi Nakamoto <satoshi@nakamoto.bit>"')
|
||||
create.add_argument('-s', '--subkey', action='store_true', default=False)
|
||||
create.add_argument('-e', '--ecdsa-curve', default='nist256p1')
|
||||
create.add_argument('-t', '--time', type=int, default=int(time.time()))
|
||||
@@ -58,13 +70,13 @@ def main():
|
||||
|
||||
sign = subparsers.add_parser('sign')
|
||||
sign.add_argument('filename', nargs='?')
|
||||
sign.add_argument('-o', '--output', default=None)
|
||||
sign.set_defaults(run=run_sign)
|
||||
|
||||
args = p.parse_args()
|
||||
logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO,
|
||||
format='%(asctime)s %(levelname)-10s %(message)s')
|
||||
result = args.run(args)
|
||||
sys.stdout.write(result)
|
||||
args.run(args)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# NEVER RUN ON YOUR OWN REAL GPG KEYS!!!!! THEY WILL BE DELETED!!!!!
|
||||
set -x -e -u
|
||||
CURVE=ed25519
|
||||
#CURVE=nist256p1
|
||||
(cd ~/.gnupg && rm -rf openpgp-revocs.d/ private-keys-v1.d/ pubring.kbx* trustdb.gpg /tmp/log *.gpg; killall gpg-agent || true)
|
||||
gpg2 --full-gen-key --expert
|
||||
gpg2 --export > romanz.pub
|
||||
NOW=`date +%s`
|
||||
USERID="Roman Zeyde <roman.zeyde@gmail.com>"
|
||||
trezor-gpg -t $NOW -e $CURVE --subkey "$USERID" -o subkey.pub
|
||||
gpg2 -K
|
||||
gpg2 -v --import <(cat romanz.pub subkey.pub)
|
||||
gpg2 -K
|
||||
|
||||
trezor-gpg -t $NOW -e $CURVE "$USERID" EXAMPLE
|
||||
gpg2 --verify EXAMPLE.sig
|
||||
@@ -3,5 +3,5 @@ if [[ "$*" == *"--verify"* ]]
|
||||
then
|
||||
gpg2 $* # verify using GPG2 (for ECDSA and EdDSA keys)
|
||||
else
|
||||
python -m trezor_agent.gpg.git_wrapper $* # sign using TREZOR
|
||||
trezor-gpg sign -o- # sign using TREZOR and write the signature to stdout
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user