gpg: support RSA decode and verify
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user