Merge branch 'master' into neopg-wip
This commit is contained in:
@@ -148,6 +148,7 @@ export PATH={0}
|
||||
-vv \
|
||||
--pin-entry-binary={pin_entry_binary} \
|
||||
--passphrase-entry-binary={passphrase_entry_binary} \
|
||||
--cache-expiry-seconds={cache_expiry_seconds} \
|
||||
$*
|
||||
""".format(os.environ['PATH'], agent_path, **vars(args)))
|
||||
check_call(['chmod', '700', f.name])
|
||||
@@ -179,7 +180,8 @@ fi
|
||||
# Generate new GPG identity and import into GPG keyring
|
||||
pubkey = write_file(os.path.join(homedir, 'pubkey.asc'),
|
||||
export_public_key(device_type, args))
|
||||
check_call(keyring.gpg_command(['--homedir', homedir, '--quiet',
|
||||
verbosity = ('-' + ('v' * args.verbose)) if args.verbose else '--quiet'
|
||||
check_call(keyring.gpg_command(['--homedir', homedir, verbosity,
|
||||
'--import', pubkey.name]))
|
||||
|
||||
# Make new GPG identity with "ultimate" trust (via its fingerprint)
|
||||
@@ -229,6 +231,8 @@ def run_agent(device_type):
|
||||
help='Path to PIN entry UI helper.')
|
||||
p.add_argument('--passphrase-entry-binary', type=str, default='pinentry',
|
||||
help='Path to passphrase entry UI helper.')
|
||||
p.add_argument('--cache-expiry-seconds', type=float, default=float('inf'),
|
||||
help='Expire passphrase from cache after this duration.')
|
||||
|
||||
args, _ = p.parse_known_args()
|
||||
|
||||
@@ -245,6 +249,8 @@ def run_agent(device_type):
|
||||
pubkey_bytes = keyring.export_public_keys(env=env)
|
||||
device_type.ui = device.ui.UI(device_type=device_type,
|
||||
config=vars(args))
|
||||
device_type.cached_passphrase_ack = util.ExpiringCache(
|
||||
seconds=float(args.cache_expiry_seconds))
|
||||
handler = agent.Handler(device=device_type(),
|
||||
pubkey_bytes=pubkey_bytes)
|
||||
|
||||
@@ -272,7 +278,9 @@ def run_agent(device_type):
|
||||
|
||||
def main(device_type):
|
||||
"""Parse command-line arguments."""
|
||||
parser = argparse.ArgumentParser()
|
||||
epilog = ('See https://github.com/romanz/trezor-agent/blob/master/'
|
||||
'doc/README-GPG.md for usage examples.')
|
||||
parser = argparse.ArgumentParser(epilog=epilog)
|
||||
|
||||
agent_package = device_type.package_name()
|
||||
resources_map = {r.key: r for r in pkg_resources.require(agent_package)}
|
||||
@@ -299,6 +307,8 @@ def main(device_type):
|
||||
help='Path to PIN entry UI helper.')
|
||||
p.add_argument('--passphrase-entry-binary', type=str, default='pinentry',
|
||||
help='Path to passphrase entry UI helper.')
|
||||
p.add_argument('--cache-expiry-seconds', type=float, default=float('inf'),
|
||||
help='Expire passphrase from cache after this duration.')
|
||||
|
||||
p.set_defaults(func=run_init)
|
||||
|
||||
@@ -308,5 +318,7 @@ def main(device_type):
|
||||
|
||||
args = parser.parse_args()
|
||||
device_type.ui = device.ui.UI(device_type=device_type, config=vars(args))
|
||||
device_type.cached_passphrase_ack = util.ExpiringCache(
|
||||
seconds=float(args.cache_expiry_seconds))
|
||||
|
||||
return args.func(device_type=device_type, args=args)
|
||||
|
||||
@@ -92,7 +92,7 @@ class Handler(object):
|
||||
b'OPTION': lambda _, args: self.handle_option(*args),
|
||||
b'SETKEYDESC': None,
|
||||
b'NOP': None,
|
||||
b'GETINFO': lambda conn, _: keyring.sendline(conn, b'D ' + self.version),
|
||||
b'GETINFO': self.handle_getinfo,
|
||||
b'AGENT_ID': lambda conn, _: keyring.sendline(conn, b'D TREZOR'), # "Fake" agent ID
|
||||
b'SIGKEY': lambda _, args: self.set_key(*args),
|
||||
b'SETKEY': lambda _, args: self.set_key(*args),
|
||||
@@ -102,6 +102,7 @@ class Handler(object):
|
||||
b'HAVEKEY': lambda _, args: self.have_key(*args),
|
||||
b'KEYINFO': _key_info,
|
||||
b'SCD': self.handle_scd,
|
||||
b'GET_PASSPHRASE': self.handle_get_passphrase,
|
||||
}
|
||||
|
||||
def reset(self):
|
||||
@@ -115,6 +116,32 @@ class Handler(object):
|
||||
self.options.append(opt)
|
||||
log.debug('options: %s', self.options)
|
||||
|
||||
def handle_get_passphrase(self, conn, _):
|
||||
"""Allow simple GPG symmetric encryption (using a passphrase)."""
|
||||
p1 = self.client.device.ui.get_passphrase('Symmetric encryption')
|
||||
p2 = self.client.device.ui.get_passphrase('Re-enter encryption')
|
||||
if p1 == p2:
|
||||
result = b'D ' + util.assuan_serialize(p1.encode('ascii'))
|
||||
keyring.sendline(conn, result, confidential=True)
|
||||
else:
|
||||
log.warning('Passphrase does not match!')
|
||||
|
||||
def handle_getinfo(self, conn, args):
|
||||
"""Handle some of the GETINFO messages."""
|
||||
result = None
|
||||
if args[0] == b'version':
|
||||
result = self.version
|
||||
elif args[0] == b's2k_count':
|
||||
# Use highest number of S2K iterations.
|
||||
# https://www.gnupg.org/documentation/manuals/gnupg/OpenPGP-Options.html
|
||||
# https://tools.ietf.org/html/rfc4880#section-3.7.1.3
|
||||
result = '{}'.format(64 << 20).encode('ascii')
|
||||
else:
|
||||
log.warning('Unknown GETINFO command: %s', args)
|
||||
|
||||
if result:
|
||||
keyring.sendline(conn, b'D ' + result)
|
||||
|
||||
def handle_scd(self, conn, args):
|
||||
"""No support for smart-card device protocol."""
|
||||
reply = {
|
||||
|
||||
@@ -48,9 +48,9 @@ def communicate(sock, msg):
|
||||
return recvline(sock)
|
||||
|
||||
|
||||
def sendline(sock, msg):
|
||||
def sendline(sock, msg, confidential=False):
|
||||
"""Send a binary message, followed by EOL."""
|
||||
log.debug('<- %r', msg)
|
||||
log.debug('<- %r', ('<snip>' if confidential else msg))
|
||||
sock.sendall(msg + b'\n')
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user