From d68e4d564dfc8868ee3badac1ace4b1e554f664d Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Wed, 4 Feb 2015 22:46:40 +0000 Subject: [PATCH] ACME Signature: proper verify, tests --- letsencrypt/acme/other.py | 6 ++- letsencrypt/acme/other_test.py | 70 +++++++++++++++++++++++++++------- 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/letsencrypt/acme/other.py b/letsencrypt/acme/other.py index 7b6185f84..b920282a2 100644 --- a/letsencrypt/acme/other.py +++ b/letsencrypt/acme/other.py @@ -80,10 +80,12 @@ class Signature(object): :param str msg: Message that was used in signing. """ - return self == self.from_msg(msg, self.jwk.key, self.nonce) + hashed = Crypto.Hash.SHA256.new(self.nonce + msg) + return Crypto.Signature.PKCS1_v1_5.new(self.jwk.key).verify( + hashed, self.sig) def to_json(self): - """Seriliaze to JSON.""" + """Prepare JSON serializable object.""" return { 'alg': self.alg, 'sig': jose.b64encode(self.sig), diff --git a/letsencrypt/acme/other_test.py b/letsencrypt/acme/other_test.py index 7300a2009..0498443d9 100644 --- a/letsencrypt/acme/other_test.py +++ b/letsencrypt/acme/other_test.py @@ -1,4 +1,6 @@ """Tests for letsencrypt.acme.sig.""" +import functools +import operator import pkg_resources import unittest @@ -14,9 +16,11 @@ RSA512_KEY = Crypto.PublicKey.RSA.importKey(pkg_resources.resource_string( class SigatureTest(unittest.TestCase): + # pylint: disable=too-many-instance-attributes """Tests for letsencrypt.acme.sig.Signature.""" def setUp(self): + self.msg = 'message' self.alg = 'RS256' self.sig = ('IC\xd8*\xe7\x14\x9e\x19S\xb7\xcf\xec3\x12\xe2\x8a\x03' '\x98u\xff\xf0\x94\xe2\xd7<\x8f\xa8\xed\xa4KN\xc3\xaa' @@ -25,32 +29,70 @@ class SigatureTest(unittest.TestCase): self.nonce = '\xec\xd6\xf2oYH\xeb\x13\xd5#q\xe0\xdd\xa2\x92\xa9' self.jwk = jose.JWK(RSA256_KEY) - self.b64sig = ('SUPYKucUnhlTt8_sMxLiigOYdf_wlOLXPI-o7aRLTsOquVjDd6r' - 'AX9AFJHk-bCMQPJbSzXKjG6H1IWbvxjS2Ew') - self.b64nonce = '7Nbyb1lI6xPVI3Hg3aKSqQ' - self.jsig = { - 'nonce': self.b64nonce, + b64sig = ('SUPYKucUnhlTt8_sMxLiigOYdf_wlOLXPI-o7aRLTsOquVjDd6r' + 'AX9AFJHk-bCMQPJbSzXKjG6H1IWbvxjS2Ew') + b64nonce = '7Nbyb1lI6xPVI3Hg3aKSqQ' + self.jsig_to = { + 'nonce': b64nonce, 'alg': self.alg, 'jwk': self.jwk, - 'sig': self.b64sig, + 'sig': b64sig, } + self.pub_jwk = jose.JWK(RSA256_KEY.publickey()) + self.jsig_from = { + 'nonce': b64nonce, + 'alg': self.alg, + 'jwk': self.pub_jwk.to_json(), + 'sig': b64sig, + } + + self.signature = self._from_msg(self.msg, RSA256_KEY, self.nonce) + from letsencrypt.acme.other import Signature + self.pub_signature = Signature( + self.alg, self.sig, self.nonce, self.pub_jwk) + @classmethod def _from_msg(cls, *args, **kwargs): from letsencrypt.acme.other import Signature return Signature.from_msg(*args, **kwargs) - def test_from_msg(self): - sig = self._from_msg('message', RSA256_KEY, self.nonce) - self.assertEqual(sig.alg, self.alg) - self.assertEqual(sig.sig, self.sig) - self.assertEqual(sig.nonce, self.nonce) - self.assertEqual(sig.jwk, self.jwk) + def test_verify_with_private_key(self): + self.assertTrue(self.signature.verify(self.msg)) - def test_from_random_nonce(self): - sig = self._from_msg('message', RSA256_KEY) + def test_verify_without_private_key(self): + self.assertTrue(self.pub_signature.verify(self.msg)) + + def test_verify_bad_fails(self): + self.signature.sig = self.sig + "foo" + self.assertFalse(self.signature.verify(self.msg)) + + def test_create_from_msg(self): + self.assertEqual(self.signature.nonce, self.nonce) + self.assertEqual(self.signature.alg, self.alg) + self.assertEqual(self.signature.sig, self.sig) + self.assertEqual(self.signature.jwk, self.jwk) + + def test_create_from_msg_random_nonce(self): + sig = self._from_msg(self.msg, RSA256_KEY) self.assertEqual(sig.alg, self.alg) self.assertEqual(sig.jwk, self.jwk) + self.assertTrue(sig.verify(self.msg)) + + def test_to_json(self): + self.assertEqual(self.signature.to_json(), self.jsig_to) + + def test_from_json(self): + from letsencrypt.acme.other import Signature + signature = Signature.from_json(self.jsig_from) + self.assertEqual(self.pub_signature, signature) + + def test_sig_and_pub_sig_not_equal(self): + self.assertNotEqual(self.pub_signature, self.signature) + + def test_eq_raises_type_error(self): + self.assertRaises( + TypeError, functools.partial(operator.eq, self.signature), "foo") if __name__ == '__main__':