From a32bfc749bc7dec10ed87076503f20f5c1da5226 Mon Sep 17 00:00:00 2001 From: Serge Pokhodyaev Date: Sun, 18 Feb 2018 20:24:22 +0300 Subject: [PATCH 1/8] don't overwrite homedir --- libagent/gpg/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libagent/gpg/__init__.py b/libagent/gpg/__init__.py index 351b7da..7513f18 100644 --- a/libagent/gpg/__init__.py +++ b/libagent/gpg/__init__.py @@ -126,7 +126,10 @@ def run_init(device_type, args): homedir = os.path.expanduser('~/.gnupg/{}'.format(device_name)) log.info('GPG home directory: %s', homedir) - check_call(['rm', '-rf', homedir]) + if os.path.exists(homedir): + log.error('GPG home directory exists, remove it manually if required') + exit(1) + check_call(['mkdir', '-p', homedir]) check_call(['chmod', '700', homedir]) From 6363eb0d4a8faeb85aa32ec0a770a65c6ce2f8d2 Mon Sep 17 00:00:00 2001 From: Serge Pokhodyaev Date: Sun, 18 Feb 2018 21:08:36 +0300 Subject: [PATCH 2/8] add -f/--foreground option to run as systemd service --- libagent/ssh/__init__.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libagent/ssh/__init__.py b/libagent/ssh/__init__.py index ac54940..674d22a 100644 --- a/libagent/ssh/__init__.py +++ b/libagent/ssh/__init__.py @@ -88,6 +88,8 @@ def create_agent_parser(device_type): g = p.add_mutually_exclusive_group() g.add_argument('-d', '--daemonize', default=False, action='store_true', help='Daemonize the agent and print its UNIX socket path') + g.add_argument('-f', '--foreground', default=False, action='store_true', + help='Run agent in foreground with specified UNIX socket path') g.add_argument('-s', '--shell', default=False, action='store_true', help=('run ${SHELL} as subprocess under SSH agent, allowing ' 'regular SSH-based tools to be used in the shell')) @@ -234,7 +236,11 @@ def main(device_type): sock_path = args.sock_path if not sock_path: - sock_path = tempfile.mktemp(prefix='trezor-ssh-agent-') + if args.foreground: + log.error("if running in foreground you must specify the socket path") + return 1 + else: + sock_path = tempfile.mktemp(prefix='trezor-ssh-agent-') command = args.command context = _dummy_context() @@ -248,6 +254,8 @@ def main(device_type): sys.stdout.flush() context = daemon.DaemonContext() log.info('running the agent as a daemon on %s', sock_path) + elif args.foreground: + log.info('running the agent on %s', sock_path) use_shell = bool(args.shell) if use_shell: @@ -258,7 +266,7 @@ def main(device_type): conn_factory=lambda: client.Client(device_type()), identities=identities, public_keys=public_keys) - if command or args.daemonize: + if command or args.daemonize or args.foreground: with context: return run_server(conn=conn, command=command, sock_path=sock_path, debug=args.debug, timeout=args.timeout) From f4208009e04d35d960a5c6f5b0970aacf30162ae Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Thu, 22 Feb 2018 11:19:26 +0200 Subject: [PATCH 3/8] trezor: init_device before failing PIN/passphrase entry --- libagent/device/trezor.py | 66 ++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/libagent/device/trezor.py b/libagent/device/trezor.py index 7440e21..5d7cccf 100644 --- a/libagent/device/trezor.py +++ b/libagent/device/trezor.py @@ -57,21 +57,25 @@ class Trezor(interface.Device): cli_handler = conn.callback_PinMatrixRequest def new_handler(msg): - if _is_open_tty(sys.stdin): - result = cli_handler(msg) # CLI-based PIN handler - else: - scrambled_pin = _message_box( - 'Use the numeric keypad to describe number positions.\n' - 'The layout is:\n' - ' 7 8 9\n' - ' 4 5 6\n' - ' 1 2 3\n' - 'Please enter PIN:') - result = self._defs.PinMatrixAck(pin=scrambled_pin) - if not set(result.pin).issubset('123456789'): - raise self._defs.PinException( - None, 'Invalid scrambled PIN: {!r}'.format(result.pin)) - return result + try: + if _is_open_tty(sys.stdin): + result = cli_handler(msg) # CLI-based PIN handler + else: + scrambled_pin = _message_box( + 'Use the numeric keypad to describe number positions.\n' + 'The layout is:\n' + ' 7 8 9\n' + ' 4 5 6\n' + ' 1 2 3\n' + 'Please enter PIN:') + result = self._defs.PinMatrixAck(pin=scrambled_pin) + if not set(result.pin).issubset('123456789'): + raise self._defs.PinException( + None, 'Invalid scrambled PIN: {!r}'.format(result.pin)) + return result + except: # noqa + conn.init_device() + raise conn.callback_PinMatrixRequest = new_handler @@ -81,20 +85,24 @@ class Trezor(interface.Device): cli_handler = conn.callback_PassphraseRequest def new_handler(msg): - if self.__class__.cached_passphrase_ack: - log.debug('re-using cached %s passphrase', self) - return self.__class__.cached_passphrase_ack - - if _is_open_tty(sys.stdin): - # use CLI-based PIN handler - ack = cli_handler(msg) - else: - passphrase = _message_box('Please enter passphrase:') - passphrase = mnemonic.Mnemonic.normalize_string(passphrase) - ack = self._defs.PassphraseAck(passphrase=passphrase) - - self.__class__.cached_passphrase_ack = ack - return ack + try: + if self.__class__.cached_passphrase_ack: + log.debug('re-using cached %s passphrase', self) + return self.__class__.cached_passphrase_ack + + if _is_open_tty(sys.stdin): + # use CLI-based PIN handler + ack = cli_handler(msg) + else: + passphrase = _message_box('Please enter passphrase:') + passphrase = mnemonic.Mnemonic.normalize_string(passphrase) + ack = self._defs.PassphraseAck(passphrase=passphrase) + + self.__class__.cached_passphrase_ack = ack + return ack + except: # noqa + conn.init_device() + raise conn.callback_PassphraseRequest = new_handler From 06e169f14156c201f7a5cecc3d40f3370c90c1c0 Mon Sep 17 00:00:00 2001 From: rendaw Date: Sat, 24 Feb 2018 03:08:46 +0900 Subject: [PATCH 4/8] Add instructions for using SSH agent as systemd unit --- doc/README-SSH.md | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/doc/README-SSH.md b/doc/README-SSH.md index b1d5106..7e56cf9 100644 --- a/doc/README-SSH.md +++ b/doc/README-SSH.md @@ -85,3 +85,55 @@ Note that your local SSH configuration may ignore `trezor-agent`, if it has `Ide If you are failing to connect, try running: $ trezor-agent -vv user@host -- ssh -vv -oIdentitiesOnly=no user@host + +# Start the agent as a systemd unit + +##### 1. Create these files in `~/.config/systemd/user` + +Replace `trezor` with `keepkey` or `ledger` as required. + +###### `trezor-ssh-agent.service` + +```` +[Unit] +Description=trezor-agent SSH agent +Requires=trezor-ssh-agent.socket + +[Service] +Type=Simple +ExecStart=/usr/bin/trezor-agent --sock-path %t/trezor-agent/S.ssh IDENTITY -- tail -f /dev/null +```` + +Replace `IDENTITY` with the identity you used when exporting the public key. + +###### `trezor-ssh-agent.socket` + +```` +[Unit] +Description=trezor-agent SSH agent socket + +[Socket] +ListenStream=%t/trezor-agent/S.ssh +FileDescriptorName=ssh +Service=trezor-ssh-agent.service +SocketMode=0600 +DirectoryMode=0700 + +[Install] +WantedBy=sockets.target +```` + +##### 2. Run + +``` +systemctl --user start trezor-ssh-agent.service trezor-ssh-agent.socket +systemctl --user enable trezor-ssh-agent.socket +``` + +##### 3. Add this line to your `.bashrc` or equivalent file: + +```bash +export SSH_AUTH_SOCK=$(systemctl show --user --property=Listen trezor-ssh-agent.socket | grep -o "/run.*") +``` + +##### 4. SSH will now automatically use your device key in all terminals. From 199fb299c3013fc37d550bbf6c05273b60ba96fa Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 24 Feb 2018 20:46:04 +0200 Subject: [PATCH 5/8] gpg: use 'sys.exit' and log homedir --- libagent/gpg/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libagent/gpg/__init__.py b/libagent/gpg/__init__.py index 7513f18..d4ca9ad 100644 --- a/libagent/gpg/__init__.py +++ b/libagent/gpg/__init__.py @@ -127,8 +127,9 @@ def run_init(device_type, args): log.info('GPG home directory: %s', homedir) if os.path.exists(homedir): - log.error('GPG home directory exists, remove it manually if required') - exit(1) + log.error('GPG home directory %s exists, ' + 'remove it manually if required', homedir) + sys.exit(1) check_call(['mkdir', '-p', homedir]) check_call(['chmod', '700', homedir]) From b20d98bf5749be23338dae0489b328cb3a44250f Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 24 Feb 2018 21:03:30 +0200 Subject: [PATCH 6/8] gpg: move socket path generation into a helper function --- libagent/ssh/__init__.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/libagent/ssh/__init__.py b/libagent/ssh/__init__.py index 674d22a..2bce4ed 100644 --- a/libagent/ssh/__init__.py +++ b/libagent/ssh/__init__.py @@ -213,6 +213,17 @@ def _dummy_context(): yield +def _get_sock_path(args): + sock_path = args.sock_path + if not sock_path: + if args.foreground: + log.error('running in foreground mode requires UNIX socket path') + return 1 + else: + sock_path = tempfile.mktemp(prefix='trezor-ssh-agent-') + return sock_path + + @handle_connection_error def main(device_type): """Run ssh-agent using given hardware client factory.""" @@ -234,13 +245,7 @@ def main(device_type): identity.identity_dict['proto'] = u'ssh' log.info('identity #%d: %s', index, identity.to_string()) - sock_path = args.sock_path - if not sock_path: - if args.foreground: - log.error("if running in foreground you must specify the socket path") - return 1 - else: - sock_path = tempfile.mktemp(prefix='trezor-ssh-agent-') + sock_path = _get_sock_path(args) command = args.command context = _dummy_context() From 2168115b0616155393de2615cd7ba66314b18437 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 24 Feb 2018 21:23:47 +0200 Subject: [PATCH 7/8] ssh: fixup small refactoring bug --- libagent/ssh/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libagent/ssh/__init__.py b/libagent/ssh/__init__.py index 2bce4ed..e378533 100644 --- a/libagent/ssh/__init__.py +++ b/libagent/ssh/__init__.py @@ -217,8 +217,8 @@ def _get_sock_path(args): sock_path = args.sock_path if not sock_path: if args.foreground: - log.error('running in foreground mode requires UNIX socket path') - return 1 + log.error('running in foreground mode requires specifying UNIX socket path') + sys.exit(1) else: sock_path = tempfile.mktemp(prefix='trezor-ssh-agent-') return sock_path From 2a76ef68190291f8197256ae331ba04e956edd66 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 24 Feb 2018 23:49:35 +0200 Subject: [PATCH 8/8] gpg: notice encryption of gpg-agent logs (for privacy) --- doc/README-GPG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/README-GPG.md b/doc/README-GPG.md index a08552e..c032344 100644 --- a/doc/README-GPG.md +++ b/doc/README-GPG.md @@ -3,7 +3,7 @@ and please let me [know](https://github.com/romanz/trezor-agent/issues/new) if s work well for you. If possible: * record the session (e.g. using [asciinema](https://asciinema.org)) - * attach the GPG agent log from `~/.gnupg/{trezor,ledger}/gpg-agent.log` + * attach the GPG agent log from `~/.gnupg/{trezor,ledger}/gpg-agent.log` (can be [encrypted](https://keybase.io/romanz)) Thanks!