From 69c5c574899d4b12cd75370b972037675f233521 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 16 Oct 2021 19:15:33 +0300 Subject: [PATCH] Support "fast-path" key listing https://dev.gnupg.org/rG40da61b89b62dcb77847dc79eb159e885f52f817#change-o4DEJvEV1Dx2 Also, refactor decoding and add a few tests. --- libagent/gpg/agent.py | 12 ++++++++++-- libagent/gpg/decode.py | 21 ++++++++++++++++----- libagent/gpg/tests/romanz-pubkey.gpg | Bin 0 -> 626 bytes libagent/gpg/tests/test_decode.py | 24 ++++++++++++++++++++---- 4 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 libagent/gpg/tests/romanz-pubkey.gpg diff --git a/libagent/gpg/agent.py b/libagent/gpg/agent.py index a4cb99c..63bc157 100644 --- a/libagent/gpg/agent.py +++ b/libagent/gpg/agent.py @@ -99,7 +99,7 @@ class Handler: b'SETHASH': lambda _, args: self.set_hash(*args), b'PKSIGN': lambda conn, _: self.pksign(conn), b'PKDECRYPT': lambda conn, _: self.pkdecrypt(conn), - b'HAVEKEY': lambda _, args: self.have_key(*args), + b'HAVEKEY': lambda conn, args: self.have_key(conn, *args), b'KEYINFO': _key_info, b'SCD': self.handle_scd, b'GET_PASSPHRASE': self.handle_get_passphrase, @@ -198,8 +198,16 @@ class Handler: ec_point = self.client.ecdh(identity=identity, pubkey=remote_pubkey) keyring.sendline(conn, b'D ' + _serialize_point(ec_point)) - def have_key(self, *keygrips): + def have_key(self, conn, *keygrips): """Check if any keygrip corresponds to a TREZOR-based key.""" + if len(keygrips) == 1 and keygrips[0].startswith(b"--list="): + # Support "fast-path" key listing: + # https://dev.gnupg.org/rG40da61b89b62dcb77847dc79eb159e885f52f817 + keygrips = list(decode.iter_keygrips(pubkey_bytes=self.pubkey_bytes)) + log.debug('keygrips: %r', keygrips) + keyring.sendline(conn, b'D ' + util.assuan_serialize(b''.join(keygrips))) + return + for keygrip in keygrips: try: self.get_identity(keygrip=keygrip) diff --git a/libagent/gpg/decode.py b/libagent/gpg/decode.py index 8694dff..1d03b4b 100644 --- a/libagent/gpg/decode.py +++ b/libagent/gpg/decode.py @@ -282,18 +282,20 @@ HASH_ALGORITHMS = { } -def load_by_keygrip(pubkey_bytes, keygrip): - """Return public key and first user ID for specified keygrip.""" +def _parse_pubkey_packets(pubkey_bytes): stream = io.BytesIO(pubkey_bytes) - packets = list(parse_packets(stream)) packets_per_pubkey = [] - for p in packets: + for p in parse_packets(stream): if p['type'] == 'pubkey': # Add a new packet list for each pubkey. packets_per_pubkey.append([]) packets_per_pubkey[-1].append(p) + return packets_per_pubkey - for packets in packets_per_pubkey: + +def load_by_keygrip(pubkey_bytes, keygrip): + """Return public key and first user ID for specified keygrip.""" + for packets in _parse_pubkey_packets(pubkey_bytes): user_ids = [p for p in packets if p['type'] == 'user_id'] for p in packets: if p.get('keygrip') == keygrip: @@ -301,6 +303,15 @@ def load_by_keygrip(pubkey_bytes, keygrip): raise KeyError('{} keygrip not found'.format(util.hexlify(keygrip))) +def iter_keygrips(pubkey_bytes): + """Iterate over all keygrips in this pubkey.""" + for packets in _parse_pubkey_packets(pubkey_bytes): + for p in packets: + keygrip = p.get('keygrip') + if keygrip: + yield keygrip + + def load_signature(stream, original_data): """Load signature from stream, and compute GPG digest for verification.""" signature, = list(parse_packets((stream))) diff --git a/libagent/gpg/tests/romanz-pubkey.gpg b/libagent/gpg/tests/romanz-pubkey.gpg new file mode 100644 index 0000000000000000000000000000000000000000..b80a32fe6d5cfb73a17c61a70a86f88193bbd151 GIT binary patch literal 626 zcmbOc#1bJAwn3OftIgw_Ei)rK6Elm&rJct+e{7R-J{tJ-Xphf^aLt)pY|c+gR%_6Z zuU55aE@n^^u6;c9C9XB;LRz z$H*YYDbRlE=`Xj5HM_Z`LV{eQ{DXAe1KjOTGBUJo-}bTQSW4{rJ826vWT(m)bgbmg zZ`i&eq3QMStqU%+G5mL1SM)sS=CZ#smY2@kU7A~?e{QzLj-aca%t7b7JtgJOZjnK8 zW^Sqj*rh;+>ZPRGbxZ)e&q7R*MfAksaIYsHAI0079)&rFl_{2u!w~3ZR&GuXb|yAa zE=~?^CWzbRK+b32Lb&~?8N)yIIqxhh3SUo{`|^~N-{R}tsS*o*3uFm7cg?T6_(h=p zEW;nZ!nGTE0@oTpV0BIU_;4HJr!6+wExlzI7cuuK`rY@Pupu@5o}SlP(!a4*I>dX*8pbV$ zKbKFln(Db(n3<7-y(5=J0vHpV(3p_s!4>R_KQjDNnA=pV?egTzo{FHam-if~-PbPA zwM*oHWWnS8@|)_KPBHuyO3VDV^h0ITyzWVPug@7*Z', + b'Roman Zeyde ', + ]