From 9ed978149631a8128c37f7997b814aa0e3f8acc8 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 30 Apr 2016 10:56:15 +0300 Subject: [PATCH] gpg: support RSA decode and verify --- trezor_agent/gpg/agent.py | 12 ++++++++-- trezor_agent/gpg/decode.py | 46 +++++++++++++++++++++++++++++--------- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/trezor_agent/gpg/agent.py b/trezor_agent/gpg/agent.py index 2e1ad93..a03fc61 100644 --- a/trezor_agent/gpg/agent.py +++ b/trezor_agent/gpg/agent.py @@ -86,7 +86,15 @@ def _parse_ecdsa_sig(sig): util.bytes2num(sig_s)) -def sign(sock, keygrip, digest): +def _parse_rsa_sig(sig): + data, (algo, (s, sig_s)) = sig + assert data == 'sig-val' + assert algo == 'rsa' + assert s == 's' + return (util.bytes2num(sig_s),) + + +def sign(sock, keygrip, digest, algo='ecdsa'): """Sign a digest using specified key using GPG agent.""" hash_algo = 8 # SHA256 assert len(digest) == 32 @@ -115,7 +123,7 @@ def sign(sock, keygrip, digest): sig, leftover = _parse(sig) assert not leftover - return _parse_ecdsa_sig(sig) + return {'ecdsa': _parse_ecdsa_sig, 'rsa': _parse_rsa_sig}[algo](sig) def get_keygrip(user_id): diff --git a/trezor_agent/gpg/decode.py b/trezor_agent/gpg/decode.py index fda6e45..96eb3da 100644 --- a/trezor_agent/gpg/decode.py +++ b/trezor_agent/gpg/decode.py @@ -68,11 +68,27 @@ def _parse_ed25519_verifier(mpi): return _ed25519_verify, vk +def _create_rsa_verifier(n, e): + def verifier(signature, digest): + s, = signature + size = n.bit_length() + result = pow(s, e, n) % (2 ** 256) + digest = util.bytes2num(digest) + if result == digest: + log.debug('RSA-%d signature is OK', size) + return True + else: + raise ValueError('invalid RSA signature') + + return verifier + SUPPORTED_CURVES = { b'\x2A\x86\x48\xCE\x3D\x03\x01\x07': _parse_nist256p1_verifier, b'\x2B\x06\x01\x04\x01\xDA\x47\x0F\x01': _parse_ed25519_verifier, } +ECDSA_ALGO_IDS = (19, 22) # (nist256, ed25519) + def _parse_literal(stream): """See https://tools.ietf.org/html/rfc4880#section-5.9 for details.""" @@ -119,7 +135,11 @@ def _parse_signature(stream): p['embedded'] = embedded p['hash_prefix'] = stream.readfmt('2s') - p['sig'] = (parse_mpi(stream), parse_mpi(stream)) + if p['pubkey_alg'] in ECDSA_ALGO_IDS: + p['sig'] = (parse_mpi(stream), parse_mpi(stream)) + else: # RSA + p['sig'] = (parse_mpi(stream),) + assert not stream.read() return p @@ -132,16 +152,23 @@ def _parse_pubkey(stream): p['version'] = stream.readfmt('B') p['created'] = stream.readfmt('>L') p['algo'] = stream.readfmt('B') + if p['algo'] in ECDSA_ALGO_IDS: + # https://tools.ietf.org/html/rfc6637#section-11 + oid_size = stream.readfmt('B') + oid = stream.read(oid_size) + assert oid in SUPPORTED_CURVES, util.hexlify(oid) + parser = SUPPORTED_CURVES[oid] - # https://tools.ietf.org/html/rfc6637#section-11 - oid_size = stream.readfmt('B') - oid = stream.read(oid_size) - assert oid in SUPPORTED_CURVES - parser = SUPPORTED_CURVES[oid] + mpi = parse_mpi(stream) + log.debug('mpi: %x (%d bits)', mpi, mpi.bit_length()) + p['verifier'], p['verifying_key'] = parser(mpi) + else: # RSA + n = parse_mpi(stream) + e = parse_mpi(stream) + log.debug('n: %x (%d bits)', n, n.bit_length()) + log.debug('e: %x (%d bits)', e, e.bit_length()) + p['verifier'] = _create_rsa_verifier(n, e) - mpi = parse_mpi(stream) - log.debug('mpi: %x (%d bits)', mpi, mpi.bit_length()) - p['verifier'], p['verifying_key'] = parser(mpi) assert not stream.read() # https://tools.ietf.org/html/rfc4880#section-12.2 @@ -252,7 +279,6 @@ def load_public_key(stream): subkey = subsig = None if len(packets) == 5: pubkey, userid, signature, subkey, subsig = packets - # TODO: refactor this out! log.debug('subkey: %s', subkey) log.debug('subsig: %s', subsig) else: