acme.util.ComparableX509

This commit is contained in:
Jakub Warmuz
2015-02-12 14:40:19 +00:00
parent a57574cbba
commit a2e807debf
4 changed files with 47 additions and 25 deletions
+16 -14
View File
@@ -262,17 +262,10 @@ class Certificate(Message):
fields["refresh"] = self.refresh fields["refresh"] = self.refresh
return fields return fields
def __eq__(self, other):
# pylint: disable=redefined-outer-name
# M2Crypto.X509 does not implement __eq__, do it manually
return isinstance(other, Certificate) and self.certificate.as_der(
) == other.certificate.as_der() and [
cert.as_der() for cert in self.chain] == [
cert.as_der() for cert in other.chain]
@classmethod @classmethod
def _decode_cert(cls, b64der): def _decode_cert(cls, b64der):
return M2Crypto.X509.load_cert_der_string(jose.b64decode(b64der)) return util.ComparableX509(M2Crypto.X509.load_cert_der_string(
jose.b64decode(b64der)))
@classmethod @classmethod
def _encode_cert(cls, cert): def _encode_cert(cls, cert):
@@ -290,7 +283,7 @@ class Certificate(Message):
class CertificateRequest(Message): class CertificateRequest(Message):
"""ACME "certificateRequest" message. """ACME "certificateRequest" message.
:ivar str csr: DER encoded CSR. :ivar str csr: CSR.
:ivar signature: Signature. :ivar signature: Signature.
:type signature: :class:`letsencrypt.acme.other.Signature` :type signature: :class:`letsencrypt.acme.other.Signature`
@@ -313,7 +306,7 @@ class CertificateRequest(Message):
""" """
return cls(signature=other.Signature.from_msg( return cls(signature=other.Signature.from_msg(
kwargs["csr"], key, sig_nonce), **kwargs) kwargs["csr"].as_der(), key, sig_nonce), **kwargs)
def verify(self): def verify(self):
"""Verify signature. """Verify signature.
@@ -324,17 +317,26 @@ class CertificateRequest(Message):
""" """
# TODO: must also check that the public key encoded in the JWK object # TODO: must also check that the public key encoded in the JWK object
# is the correct key for a given context. # is the correct key for a given context.
return self.signature.verify(self.csr) return self.signature.verify(self.csr.as_der())
@classmethod
def _decode_csr(cls, b64der):
return util.ComparableX509(M2Crypto.X509.load_request_der_string(
jose.b64decode(b64der)))
@classmethod
def _encode_csr(cls, csr):
return jose.b64encode(csr.as_der())
def _fields_to_json(self): def _fields_to_json(self):
return { return {
"csr": jose.b64encode(self.csr), "csr": self._encode_csr(self.csr),
"signature": self.signature, "signature": self.signature,
} }
@classmethod @classmethod
def _from_valid_json(cls, jobj): def _from_valid_json(cls, jobj):
return cls(csr=jose.b64decode(jobj["csr"]), return cls(csr=cls._decode_csr(jobj["csr"]),
signature=other.Signature.from_json( signature=other.Signature.from_json(
jobj["signature"], validate=False)) jobj["signature"], validate=False))
+10 -9
View File
@@ -13,8 +13,10 @@ from letsencrypt.acme import other
KEY = Crypto.PublicKey.RSA.importKey(pkg_resources.resource_string( KEY = Crypto.PublicKey.RSA.importKey(pkg_resources.resource_string(
'letsencrypt.client.tests', 'testdata/rsa256_key.pem')) 'letsencrypt.client.tests', 'testdata/rsa256_key.pem'))
CERT = M2Crypto.X509.load_cert_string(pkg_resources.resource_string( CERT = M2Crypto.X509.load_cert(pkg_resources.resource_filename(
'letsencrypt.client.tests', 'testdata/cert.pem')) 'letsencrypt.client.tests', 'testdata/cert.pem'))
CSR = M2Crypto.X509.load_request(pkg_resources.resource_filename(
'letsencrypt.client.tests', 'testdata/csr.pem'))
class MessageTest(unittest.TestCase): class MessageTest(unittest.TestCase):
@@ -294,28 +296,27 @@ class CertificateTest(unittest.TestCase):
class CertificateRequestTest(unittest.TestCase): class CertificateRequestTest(unittest.TestCase):
def setUp(self): def setUp(self):
self.csr = 'TODO: real DER CSR?'
signature = other.Signature( signature = other.Signature(
alg='RS256', jwk=jose.JWK(key=KEY.publickey()), alg='RS256', jwk=jose.JWK(key=KEY.publickey()),
sig='\x1cD\x157\x83\x14\xd7 \xeb\x02\xb3\xf6O\xb5\x99C]\x97' sig='\x15\xed\x84\xaa:\xf2DO\x0e9 \xbcg\xf8\xc0\xcf\x87\x9a'
'\x94p\xa7\xe48\x13>\x06\xf9yd\xf9\xfe\xf8\xd1>\x9aKH' '\x95\xeb\xffT[\x84[\xec\x85\x7f\x8eK\xe9\xc2\x12\xc8Q'
'\xd7\xba\xb9a1\xf5!p\x1b\xd7}\xbaj\xa7\xe3\xd9\xd9\t%' '\xafo\xc6h\x07\xba\xa6\xdf\xd1\xa7"$\xba=Z\x13n\x14\x0b'
'\xbb\xba\xc9\x00\xdaW\x16\xe9', 'k\xfe\xee\xb4\xe4\xc8\x05\x9a\x08\xa7',
nonce='\xec\xd6\xf2oYH\xeb\x13\xd5#q\xe0\xdd\xa2\x92\xa9') nonce='\xec\xd6\xf2oYH\xeb\x13\xd5#q\xe0\xdd\xa2\x92\xa9')
from letsencrypt.acme.messages import CertificateRequest from letsencrypt.acme.messages import CertificateRequest
self.msg = CertificateRequest(csr=self.csr, signature=signature) self.msg = CertificateRequest(csr=CSR, signature=signature)
self.jmsg = { self.jmsg = {
'type': 'certificateRequest', 'type': 'certificateRequest',
'csr': 'VE9ETzogcmVhbCBERVIgQ1NSPw', 'csr': jose.b64encode(CSR.as_der()),
'signature': signature, 'signature': signature,
} }
def test_create(self): def test_create(self):
from letsencrypt.acme.messages import CertificateRequest from letsencrypt.acme.messages import CertificateRequest
self.assertEqual(self.msg, CertificateRequest.create( self.assertEqual(self.msg, CertificateRequest.create(
csr=self.csr, key=KEY, csr=CSR, key=KEY,
sig_nonce='\xec\xd6\xf2oYH\xeb\x13\xd5#q\xe0\xdd\xa2\x92\xa9')) sig_nonce='\xec\xd6\xf2oYH\xeb\x13\xd5#q\xe0\xdd\xa2\x92\xa9'))
def test_verify(self): def test_verify(self):
+19
View File
@@ -9,6 +9,25 @@ from letsencrypt.acme import errors
from letsencrypt.acme import interfaces from letsencrypt.acme import interfaces
class ComparableX509(object): # pylint: disable=too-few-public-methods
"""Wrapper for M2Crypto.X509.* objects that supports __eq__.
Wraps around:
- :class:`M2Crypto.X509.X509`
- :class:`M2Crypto.X509.Request`
"""
def __init__(self, wrapped):
self._wrapped = wrapped
def __getattr__(self, name):
return getattr(self._wrapped, name)
def __eq__(self, other):
return self.as_der() == other.as_der()
def load_schema(name): def load_schema(name):
"""Load JSON schema from distribution.""" """Load JSON schema from distribution."""
return json.load(open(pkg_resources.resource_filename( return json.load(open(pkg_resources.resource_filename(
+2 -2
View File
@@ -130,8 +130,8 @@ 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(
acme.messages.CertificateRequest.create( acme.messages.CertificateRequest.create(
csr=csr_der, key=Crypto.PublicKey.RSA.importKey( csr=M2Crypto.X509.load_request_der_string(csr_der),
self.authkey.pem)), key=Crypto.PublicKey.RSA.importKey(self.authkey.pem)),
acme.messages.Certificate) acme.messages.Certificate)
def save_certificate(self, certificate_msg, cert_path, chain_path): def save_certificate(self, certificate_msg, cert_path, chain_path):