Merge pull request #327 from kuba/hashable-key

HashableRSAKey
This commit is contained in:
James Kasten
2015-03-30 13:17:47 -07:00
10 changed files with 81 additions and 17 deletions
+4 -2
View File
@@ -13,8 +13,10 @@ from letsencrypt.acme import other
CERT = jose.ComparableX509(M2Crypto.X509.load_cert( CERT = jose.ComparableX509(M2Crypto.X509.load_cert(
pkg_resources.resource_filename( pkg_resources.resource_filename(
'letsencrypt.client.tests', 'testdata/cert.pem'))) 'letsencrypt.client.tests', 'testdata/cert.pem')))
KEY = Crypto.PublicKey.RSA.importKey(pkg_resources.resource_string( KEY = jose.HashableRSAKey(Crypto.PublicKey.RSA.importKey(
'letsencrypt.client.tests', os.path.join('testdata', 'rsa256_key.pem'))) pkg_resources.resource_string(
'letsencrypt.client.tests',
os.path.join('testdata', 'rsa256_key.pem'))))
class SimpleHTTPSTest(unittest.TestCase): class SimpleHTTPSTest(unittest.TestCase):
+1
View File
@@ -70,5 +70,6 @@ from letsencrypt.acme.jose.jws import JWS
from letsencrypt.acme.jose.util import ( from letsencrypt.acme.jose.util import (
ComparableX509, ComparableX509,
HashableRSAKey,
ImmutableMap, ImmutableMap,
) )
+7 -2
View File
@@ -83,7 +83,11 @@ class JWKOct(JWK):
@JWK.register @JWK.register
class JWKRSA(JWK): class JWKRSA(JWK):
"""RSA JWK.""" """RSA JWK.
:ivar key: `Crypto.PublicKey.RSA` wrapped in `.HashableRSAKey`
"""
typ = 'RSA' typ = 'RSA'
__slots__ = ('key',) __slots__ = ('key',)
@@ -114,7 +118,8 @@ class JWKRSA(JWK):
:rtype: :class:`JWKRSA` :rtype: :class:`JWKRSA`
""" """
return cls(key=Crypto.PublicKey.RSA.importKey(string)) return cls(key=util.HashableRSAKey(
Crypto.PublicKey.RSA.importKey(string)))
def public(self): def public(self):
return type(self)(key=self.key.publickey()) return type(self)(key=self.key.publickey())
+20
View File
@@ -41,6 +41,26 @@ class ComparableX509(object): # pylint: disable=too-few-public-methods
return self.as_der() == other.as_der() return self.as_der() == other.as_der()
class HashableRSAKey(object): # pylint: disable=too-few-public-methods
"""Wrapper for `Crypto.PublicKey.RSA` objects that supports hashing."""
def __init__(self, wrapped):
self._wrapped = wrapped
def __getattr__(self, name):
return getattr(self._wrapped, name)
def __eq__(self, other):
return self._wrapped == other
def __hash__(self):
return hash((type(self), self.exportKey(format='DER')))
def publickey(self):
"""Get wrapped public key."""
return type(self)(self._wrapped.publickey())
class ImmutableMap(collections.Mapping, collections.Hashable): class ImmutableMap(collections.Mapping, collections.Hashable):
# pylint: disable=too-few-public-methods # pylint: disable=too-few-public-methods
"""Immutable key to value mapping with attribute access.""" """Immutable key to value mapping with attribute access."""
+29
View File
@@ -1,7 +1,36 @@
"""Tests for letsencrypt.acme.jose.util.""" """Tests for letsencrypt.acme.jose.util."""
import functools import functools
import os
import pkg_resources
import unittest import unittest
import Crypto.PublicKey.RSA
class HashableRSAKeyTest(unittest.TestCase):
"""Tests for letsencrypt.acme.jose.util.HashableRSAKey."""
def setUp(self):
from letsencrypt.acme.jose.util import HashableRSAKey
self.key = HashableRSAKey(Crypto.PublicKey.RSA.importKey(
pkg_resources.resource_string(
__name__, os.path.join('testdata', 'rsa256_key.pem'))))
self.key_same = HashableRSAKey(Crypto.PublicKey.RSA.importKey(
pkg_resources.resource_string(
__name__, os.path.join('testdata', 'rsa256_key.pem'))))
def test_eq(self):
# if __eq__ is not defined, then two HashableRSAKeys with same
# _wrapped do not equate
self.assertEqual(self.key, self.key_same)
def test_hash(self):
self.assertTrue(isinstance(hash(self.key), int))
def test_publickey(self):
from letsencrypt.acme.jose.util import HashableRSAKey
self.assertTrue(isinstance(self.key.publickey(), HashableRSAKey))
class ImmutableMapTest(unittest.TestCase): class ImmutableMapTest(unittest.TestCase):
"""Tests for letsencrypt.acme.jose.util.ImmutableMap.""" """Tests for letsencrypt.acme.jose.util.ImmutableMap."""
+3 -2
View File
@@ -11,8 +11,9 @@ from letsencrypt.acme import jose
from letsencrypt.acme import other from letsencrypt.acme import other
KEY = Crypto.PublicKey.RSA.importKey(pkg_resources.resource_string( KEY = jose.HashableRSAKey(Crypto.PublicKey.RSA.importKey(
'letsencrypt.client.tests', 'testdata/rsa256_key.pem')) pkg_resources.resource_string(
'letsencrypt.client.tests', 'testdata/rsa256_key.pem')))
CERT = jose.ComparableX509(M2Crypto.X509.load_cert( CERT = jose.ComparableX509(M2Crypto.X509.load_cert(
pkg_resources.resource_filename( pkg_resources.resource_filename(
'letsencrypt.client.tests', 'testdata/cert.pem'))) 'letsencrypt.client.tests', 'testdata/cert.pem')))
+6 -4
View File
@@ -7,10 +7,12 @@ import Crypto.PublicKey.RSA
from letsencrypt.acme import jose from letsencrypt.acme import jose
RSA256_KEY = Crypto.PublicKey.RSA.importKey(pkg_resources.resource_string( RSA256_KEY = jose.HashableRSAKey(Crypto.PublicKey.RSA.importKey(
'letsencrypt.client.tests', 'testdata/rsa256_key.pem')) pkg_resources.resource_string(
RSA512_KEY = Crypto.PublicKey.RSA.importKey(pkg_resources.resource_string( 'letsencrypt.client.tests', 'testdata/rsa256_key.pem')))
'letsencrypt.client.tests', 'testdata/rsa512_key.pem')) RSA512_KEY = jose.HashableRSAKey(
Crypto.PublicKey.RSA.importKey(pkg_resources.resource_string(
'letsencrypt.client.tests', 'testdata/rsa512_key.pem')))
class SignatureTest(unittest.TestCase): class SignatureTest(unittest.TestCase):
+3 -2
View File
@@ -5,6 +5,7 @@ import sys
import Crypto.PublicKey.RSA import Crypto.PublicKey.RSA
from letsencrypt.acme import challenges from letsencrypt.acme import challenges
from letsencrypt.acme import jose
from letsencrypt.acme import messages from letsencrypt.acme import messages
from letsencrypt.client import achallenges from letsencrypt.client import achallenges
@@ -119,8 +120,8 @@ class AuthHandler(object): # pylint: disable=too-many-instance-attributes
nonce=self.msgs[domain].nonce, nonce=self.msgs[domain].nonce,
responses=self.responses[domain], responses=self.responses[domain],
name=domain, name=domain,
key=Crypto.PublicKey.RSA.importKey( key=jose.HashableRSAKey(Crypto.PublicKey.RSA.importKey(
self.authkey[domain].pem)), self.authkey[domain].pem))),
messages.Authorization) messages.Authorization)
logging.info("Received Authorization for %s", domain) logging.info("Received Authorization for %s", domain)
return auth return auth
+4 -3
View File
@@ -6,8 +6,8 @@ import sys
import Crypto.PublicKey.RSA import Crypto.PublicKey.RSA
import M2Crypto import M2Crypto
from letsencrypt.acme import jose
from letsencrypt.acme import messages from letsencrypt.acme import messages
from letsencrypt.acme.jose import util as jose_util
from letsencrypt.client import auth_handler from letsencrypt.client import auth_handler
from letsencrypt.client import client_authenticator from letsencrypt.client import client_authenticator
@@ -130,9 +130,10 @@ class Client(object):
logging.info("Preparing and sending CSR...") logging.info("Preparing and sending CSR...")
return self.network.send_and_receive_expected( return self.network.send_and_receive_expected(
messages.CertificateRequest.create( messages.CertificateRequest.create(
csr=jose_util.ComparableX509( csr=jose.ComparableX509(
M2Crypto.X509.load_request_der_string(csr_der)), M2Crypto.X509.load_request_der_string(csr_der)),
key=Crypto.PublicKey.RSA.importKey(self.authkey.pem)), key=jose.HashableRSAKey(Crypto.PublicKey.RSA.importKey(
self.authkey.pem))),
messages.Certificate) messages.Certificate)
def save_certificate(self, certificate_msg, cert_path, chain_path): def save_certificate(self, certificate_msg, cert_path, chain_path):
+4 -2
View File
@@ -8,8 +8,10 @@ from letsencrypt.acme import challenges
from letsencrypt.acme import jose from letsencrypt.acme import jose
KEY = Crypto.PublicKey.RSA.importKey(pkg_resources.resource_string( KEY = jose.HashableRSAKey(Crypto.PublicKey.RSA.importKey(
"letsencrypt.client.tests", os.path.join("testdata", "rsa256_key.pem"))) pkg_resources.resource_string(
"letsencrypt.client.tests",
os.path.join("testdata", "rsa256_key.pem"))))
# Challenges # Challenges
SIMPLE_HTTPS = challenges.SimpleHTTPS( SIMPLE_HTTPS = challenges.SimpleHTTPS(