Cryptographer.sigrec_decode assumed signatures where properly encoded.

- Fixes a bug in sigrec_decode where the decoding function assumend that the first by was formatted as 31 + SigRec. Non properly encoded signatures made the function to crash due to an overflow (int_to_bytes(x) for negative x)
This commit is contained in:
Sergi Delgado Segura
2020-04-01 17:04:33 +02:00
parent 2d67fe8638
commit 0e392d1f2a
2 changed files with 22 additions and 5 deletions

View File

@@ -43,6 +43,7 @@ def hash_160(message):
return h160
# NOTCOVERED
def sigrec_encode(rsig_rid):
"""
Encodes a pk-recoverable signature to be used in LN. ```rsig_rid`` can be obtained trough
@@ -63,6 +64,7 @@ def sigrec_encode(rsig_rid):
return sigrec
# NOTCOVERED
def sigrec_decode(sigrec):
"""
Decodes a pk-recoverable signature in the format used by LN to be input to ``PublicKey.from_signature_and_message``.
@@ -72,12 +74,18 @@ def sigrec_decode(sigrec):
Returns:
:obj:`bytes`: the decoded signature.
Raises:
:obj:`ValueError`: if the SigRec is not properly encoded (first byte is not 31 + recovery id)
"""
rid, rsig = int_to_bytes(sigrec[0] - 31), sigrec[1:]
rsig_rid = rsig + rid
int_rid, rsig = sigrec[0] - 31, sigrec[1:]
if int_rid < 0:
raise ValueError("Wrong SigRec")
else:
rid = int_to_bytes(int_rid)
return rsig_rid
return rsig + rid
# FIXME: Common has not log file, so it needs to log in the same log as the caller. This is a temporary fix.
@@ -299,9 +307,9 @@ class Cryptographer:
return None
sigrec = pyzbase32.decode_bytes(zb32_sig)
rsig_recid = sigrec_decode(sigrec)
try:
rsig_recid = sigrec_decode(sigrec)
pk = PublicKey.from_signature_and_message(rsig_recid, LN_MESSAGE_PREFIX + message, hasher=sha256d)
return pk
@@ -313,7 +321,7 @@ class Cryptographer:
except Exception as e:
if "failed to recover ECDSA public key" in str(e):
logger.error("Cannot recover public key from signature".format(type(rsig_recid)))
logger.error("Cannot recover public key from signature")
else:
logger.error("Unknown exception", error=str(e))

View File

@@ -208,6 +208,15 @@ def test_recover_pk():
assert isinstance(rpk, PublicKey)
def test_recover_pk_invalid_sigrec():
message = "Hey, it's me"
signature = "ddbfb019e4d56155b4175066c2b615ab765d317ae7996d188b4a5fae4cc394adf98fef46034d0553149392219ca6d37dca9abdfa6366a8e54b28f19d3e5efa8a14b556205dc7f33a"
# The given signature, when zbase32 decoded, has a fist byte with value lower than 31.
# The first byte of the signature should be 31 + SigRec, so this should fail
assert Cryptographer.recover_pk(message, signature) is None
def test_recover_pk_ground_truth():
# Use a message a signature generated by c-lightning and see if we recover the proper key
message = b"Test message"