mirror of
https://github.com/certbot/certbot.git
synced 2026-01-29 10:02:08 +03:00
ACME Signature: JWK with pubkey only
This commit is contained in:
@@ -17,7 +17,7 @@ def _leading_zeros(arg):
|
||||
class JWK(object):
|
||||
"""JSON Web Key.
|
||||
|
||||
.. todo:: Currently works for RSA keys only.
|
||||
.. todo:: Currently works for RSA public keys only.
|
||||
|
||||
"""
|
||||
zope.interface.implements(interfaces.IJSONSerializable)
|
||||
@@ -32,14 +32,6 @@ class JWK(object):
|
||||
raise TypeError(
|
||||
'Unable to compare JWK object with: {0}'.format(other))
|
||||
|
||||
def same_public_key(self, other):
|
||||
"""Does ``other`` have the same public key?"""
|
||||
if isinstance(other, JWK):
|
||||
return self.key.publickey() == other.key.publickey()
|
||||
else:
|
||||
raise TypeError(
|
||||
'Unable to compare JWK object with: {0}'.format(other))
|
||||
|
||||
@classmethod
|
||||
def _encode_param(cls, param):
|
||||
"""Encode numeric key parameter."""
|
||||
|
||||
@@ -5,26 +5,31 @@ import unittest
|
||||
import Crypto.PublicKey.RSA
|
||||
|
||||
|
||||
RSA256_KEY_PATH = pkg_resources.resource_string(
|
||||
'letsencrypt.client.tests', 'testdata/rsa256_key.pem')
|
||||
RSA256_KEY = Crypto.PublicKey.RSA.importKey(RSA256_KEY_PATH)
|
||||
RSA512_KEY_PATH = pkg_resources.resource_string(
|
||||
'letsencrypt.client.tests', 'testdata/rsa512_key.pem')
|
||||
RSA512_KEY = Crypto.PublicKey.RSA.importKey(RSA512_KEY_PATH)
|
||||
RSA256_KEY = Crypto.PublicKey.RSA.importKey(pkg_resources.resource_string(
|
||||
'letsencrypt.client.tests', 'testdata/rsa256_key.pem'))
|
||||
RSA512_KEY = Crypto.PublicKey.RSA.importKey(pkg_resources.resource_string(
|
||||
'letsencrypt.client.tests', 'testdata/rsa512_key.pem'))
|
||||
|
||||
|
||||
class JWKTest(unittest.TestCase):
|
||||
"""Tests fro letsencrypt.acme.jose.JWK."""
|
||||
|
||||
def setUp(self):
|
||||
from letsencrypt.acme.jose import JWK
|
||||
self.jwk256 = JWK(RSA256_KEY)
|
||||
self.jwk256 = JWK(RSA256_KEY.publickey())
|
||||
self.jwk256json = {
|
||||
'kty': 'RSA',
|
||||
'e': 'AQAB',
|
||||
'n': 'rHVztFHtH92ucFJD_N_HW9AsdRsUuHUBBBDlHwNlRd3fp5'
|
||||
'80rv2-6QWE30cWgdmJS86ObRz6lUTor4R0T-3C5Q',
|
||||
}
|
||||
self.jwk512 = JWK(RSA512_KEY)
|
||||
self.jwk512 = JWK(RSA512_KEY.publickey())
|
||||
self.jwk512json = {
|
||||
'kty': 'RSA',
|
||||
'e': 'AQAB',
|
||||
'n': '9LYRcVE3Nr-qleecEcX8JwVDnjeG1X7ucsCasuuZM0e09c'
|
||||
'mYuUzxIkMjO_9x4AVcvXXRXPEV-LzWWkfkTlzRMw',
|
||||
}
|
||||
|
||||
def test_equals(self):
|
||||
self.assertEqual(self.jwk256, self.jwk256)
|
||||
@@ -37,24 +42,14 @@ class JWKTest(unittest.TestCase):
|
||||
def test_equals_raises_type_error(self):
|
||||
self.assertRaises(TypeError, self.jwk256.__eq__, 123)
|
||||
|
||||
def test_same_public_key(self):
|
||||
from letsencrypt.acme.jose import JWK
|
||||
self.assertTrue(self.jwk256.same_public_key(
|
||||
JWK(Crypto.PublicKey.RSA.importKey(RSA256_KEY_PATH))))
|
||||
|
||||
def test_not_same_public_key(self):
|
||||
self.assertFalse(self.jwk256.same_public_key(self.jwk512))
|
||||
|
||||
def test_same_public_key_raises_type_error(self):
|
||||
self.assertRaises(TypeError, self.jwk256.same_public_key, 5)
|
||||
|
||||
def test_to_json(self):
|
||||
self.assertEqual(self.jwk256.to_json(), self.jwk256json)
|
||||
self.assertEqual(self.jwk512.to_json(), self.jwk512json)
|
||||
|
||||
def test_from_json(self):
|
||||
from letsencrypt.acme.jose import JWK
|
||||
self.assertTrue(self.jwk256.same_public_key(
|
||||
JWK.from_json(self.jwk256json)))
|
||||
self.assertEqual(self.jwk256, JWK.from_json(self.jwk256json))
|
||||
self.assertEqual(self.jwk512, JWK.from_json(self.jwk512json))
|
||||
|
||||
|
||||
# https://en.wikipedia.org/wiki/Base64#Examples
|
||||
|
||||
@@ -64,7 +64,7 @@ class Signature(object):
|
||||
|
||||
logging.debug('%s signed as %s', msg_with_nonce, sig)
|
||||
|
||||
return cls('RS256', sig, nonce, jose.JWK(key))
|
||||
return cls('RS256', sig, nonce, jose.JWK(key.publickey()))
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Signature):
|
||||
|
||||
@@ -27,7 +27,7 @@ class SigatureTest(unittest.TestCase):
|
||||
'\xb9X\xc3w\xaa\xc0_\xd0\x05$y>l#\x10<\x96\xd2\xcdr\xa3'
|
||||
'\x1b\xa1\xf5!f\xef\xc64\xb6\x13')
|
||||
self.nonce = '\xec\xd6\xf2oYH\xeb\x13\xd5#q\xe0\xdd\xa2\x92\xa9'
|
||||
self.jwk = jose.JWK(RSA256_KEY)
|
||||
self.jwk = jose.JWK(RSA256_KEY.publickey())
|
||||
|
||||
b64sig = ('SUPYKucUnhlTt8_sMxLiigOYdf_wlOLXPI-o7aRLTsOquVjDd6r'
|
||||
'AX9AFJHk-bCMQPJbSzXKjG6H1IWbvxjS2Ew')
|
||||
@@ -39,60 +39,53 @@ class SigatureTest(unittest.TestCase):
|
||||
'sig': b64sig,
|
||||
}
|
||||
|
||||
self.pub_jwk = jose.JWK(RSA256_KEY.publickey())
|
||||
self.jsig_from = {
|
||||
'nonce': b64nonce,
|
||||
'alg': self.alg,
|
||||
'jwk': self.pub_jwk.to_json(),
|
||||
'jwk': self.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)
|
||||
self.signature = Signature(self.alg, self.sig, self.nonce, self.jwk)
|
||||
|
||||
def test_attributes(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_verify_good_succeeds(self):
|
||||
self.assertTrue(self.signature.verify(self.msg))
|
||||
|
||||
def test_verify_bad_fails(self):
|
||||
self.assertFalse(self.signature.verify(self.msg + 'x'))
|
||||
|
||||
@classmethod
|
||||
def _from_msg(cls, *args, **kwargs):
|
||||
from letsencrypt.acme.other import Signature
|
||||
return Signature.from_msg(*args, **kwargs)
|
||||
|
||||
def test_verify_with_private_key(self):
|
||||
self.assertTrue(self.signature.verify(self.msg))
|
||||
|
||||
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)
|
||||
signature = self._from_msg(self.msg, RSA256_KEY, self.nonce)
|
||||
self.assertEqual(self.signature, signature)
|
||||
|
||||
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))
|
||||
signature = self._from_msg(self.msg, RSA256_KEY)
|
||||
self.assertEqual(signature.alg, self.alg)
|
||||
self.assertEqual(signature.jwk, self.jwk)
|
||||
self.assertTrue(signature.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)
|
||||
self.assertEqual(self.signature, Signature.from_json(self.jsig_from))
|
||||
|
||||
def test_eq_raises_type_error(self):
|
||||
self.assertRaises(
|
||||
TypeError, functools.partial(operator.eq, self.signature), "foo")
|
||||
TypeError, functools.partial(operator.eq, self.signature), 'foo')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user