acme: M2Crypto -> pyOpenSSL

This commit is contained in:
Jakub Warmuz
2015-07-06 12:18:17 +00:00
parent e0293d81f3
commit 9197fa6b5c
17 changed files with 151 additions and 80 deletions
+5 -4
View File
@@ -5,8 +5,8 @@ import unittest
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
import M2Crypto
import mock
import OpenSSL
import requests
import urlparse
@@ -14,8 +14,8 @@ from acme import jose
from acme import other
CERT = jose.ComparableX509(M2Crypto.X509.load_cert(
pkg_resources.resource_filename(
CERT = jose.ComparableX509(OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string(
'letsencrypt.tests', os.path.join('testdata', 'cert.pem'))))
KEY = jose.ComparableRSAKey(serialization.load_pem_private_key(
pkg_resources.resource_string(
@@ -370,7 +370,8 @@ class ProofOfPossessionHintsTest(unittest.TestCase):
self.jmsg_to = {
'jwk': jwk,
'certFingerprints': cert_fingerprints,
'certs': (jose.b64encode(CERT.as_der()),),
'certs': (jose.b64encode(OpenSSL.crypto.dump_certificate(
OpenSSL.crypto.FILETYPE_ASN1, CERT)),),
'subjectKeyIdentifiers': subject_key_identifiers,
'serialNumbers': serial_numbers,
'issuers': issuers,
+9 -9
View File
@@ -5,7 +5,7 @@ import httplib
import logging
import time
import M2Crypto
import OpenSSL
import requests
import werkzeug
@@ -256,7 +256,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
"""Request issuance.
:param csr: CSR
:type csr: `M2Crypto.X509.Request` wrapped in `.ComparableX509`
:type csr: `OpenSSL.crypto.X509Req` wrapped in `.ComparableX509`
:param authzrs: `list` of `.AuthorizationResource`
@@ -287,8 +287,8 @@ class Client(object): # pylint: disable=too-many-instance-attributes
return messages.CertificateResource(
uri=uri, authzrs=authzrs, cert_chain_uri=cert_chain_uri,
body=jose.ComparableX509(
M2Crypto.X509.load_cert_der_string(response.content)))
body=jose.ComparableX509(OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_ASN1, response.content)))
def poll_and_request_issuance(self, csr, authzrs, mintime=5):
"""Poll and request issuance.
@@ -300,7 +300,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
.. todo:: add `max_attempts` or `timeout`
:param csr: CSR.
:type csr: `M2Crypto.X509.Request` wrapped in `.ComparableX509`
:type csr: `OpenSSL.crypto.X509Req` wrapped in `.ComparableX509`
:param authzrs: `list` of `.AuthorizationResource`
@@ -359,8 +359,8 @@ class Client(object): # pylint: disable=too-many-instance-attributes
content_type = self.DER_CONTENT_TYPE # TODO: make it a param
response = self.net.get(uri, headers={'Accept': content_type},
content_type=content_type)
return response, jose.ComparableX509(
M2Crypto.X509.load_cert_der_string(response.content))
return response, jose.ComparableX509(OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_ASN1, response.content))
def check_cert(self, certr):
"""Check for new cert.
@@ -403,7 +403,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
:type certr: `.CertificateResource`
:returns: Certificate chain, or `None` if no "up" Link was provided.
:rtype: `M2Crypto.X509.X509` wrapped in `.ComparableX509`
:rtype: `OpenSSL.crypto.X509` wrapped in `.ComparableX509`
"""
if certr.cert_chain_uri is not None:
@@ -414,7 +414,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
def revoke(self, cert):
"""Revoke certificate.
:param .ComparableX509 cert: `M2Crypto.X509.X509` wrapped in
:param .ComparableX509 cert: `OpenSSL.crypto.X509` wrapped in
`.ComparableX509`
:raises .ClientError: If revocation is unsuccessful.
+6 -4
View File
@@ -16,6 +16,8 @@ from acme import messages
from acme import messages_test
CERT_DER = pkg_resources.resource_string(
'acme.jose', os.path.join('testdata', 'cert.der'))
KEY = jose.JWKRSA.load(pkg_resources.resource_string(
'acme.jose', os.path.join('testdata', 'rsa512_key.pem')))
KEY2 = jose.JWKRSA.load(pkg_resources.resource_string(
@@ -204,7 +206,7 @@ class ClientTest(unittest.TestCase):
errors.UnexpectedUpdate, self.client.poll, self.authzr)
def test_request_issuance(self):
self.response.content = messages_test.CERT.as_der()
self.response.content = CERT_DER
self.response.headers['Location'] = self.certr.uri
self.response.links['up'] = {'url': self.certr.cert_chain_uri}
self.assertEqual(self.certr, self.client.request_issuance(
@@ -212,7 +214,7 @@ class ClientTest(unittest.TestCase):
# TODO: check POST args
def test_request_issuance_missing_up(self):
self.response.content = messages_test.CERT.as_der()
self.response.content = CERT_DER
self.response.headers['Location'] = self.certr.uri
self.assertEqual(
self.certr.update(cert_chain_uri=None),
@@ -306,7 +308,7 @@ class ClientTest(unittest.TestCase):
def test_check_cert(self):
self.response.headers['Location'] = self.certr.uri
self.response.content = messages_test.CERT.as_der()
self.response.content = CERT_DER
self.assertEqual(self.certr.update(body=messages_test.CERT),
self.client.check_cert(self.certr))
@@ -316,7 +318,7 @@ class ClientTest(unittest.TestCase):
errors.UnexpectedUpdate, self.client.check_cert, self.certr)
def test_check_cert_missing_location(self):
self.response.content = messages_test.CERT.as_der()
self.response.content = CERT_DER
self.assertRaises(
errors.ClientError, self.client.check_cert, self.certr)
+11 -9
View File
@@ -10,7 +10,7 @@ import abc
import binascii
import logging
import M2Crypto
import OpenSSL
from acme.jose import b64
from acme.jose import errors
@@ -321,26 +321,28 @@ def encode_cert(cert):
:type cert: :class:`acme.jose.util.ComparableX509`
"""
return b64.b64encode(cert.as_der())
return b64.b64encode(OpenSSL.crypto.dump_certificate(
OpenSSL.crypto.FILETYPE_ASN1, cert))
def decode_cert(b64der):
"""Decode JOSE Base-64 DER-encoded certificate."""
try:
return util.ComparableX509(M2Crypto.X509.load_cert_der_string(
decode_b64jose(b64der)))
except M2Crypto.X509.X509Error as error:
return util.ComparableX509(OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_ASN1, decode_b64jose(b64der)))
except OpenSSL.crypto.Error as error:
raise errors.DeserializationError(error)
def encode_csr(csr):
"""Encode CSR as JOSE Base-64 DER."""
return encode_cert(csr)
return b64.b64encode(OpenSSL.crypto.dump_certificate_request(
OpenSSL.crypto.FILETYPE_ASN1, csr))
def decode_csr(b64der):
"""Decode JOSE Base-64 DER-encoded CSR."""
try:
return util.ComparableX509(M2Crypto.X509.load_request_der_string(
decode_b64jose(b64der)))
except M2Crypto.X509.X509Error as error:
return util.ComparableX509(OpenSSL.crypto.load_certificate_request(
OpenSSL.crypto.FILETYPE_ASN1, decode_b64jose(b64der)))
except OpenSSL.crypto.Error as error:
raise errors.DeserializationError(error)
+8 -6
View File
@@ -4,18 +4,20 @@ import os
import pkg_resources
import unittest
import M2Crypto
import mock
import OpenSSL
from acme.jose import errors
from acme.jose import interfaces
from acme.jose import util
CERT = M2Crypto.X509.load_cert(pkg_resources.resource_filename(
'letsencrypt.tests', os.path.join('testdata', 'cert.pem')))
CSR = M2Crypto.X509.load_request(pkg_resources.resource_filename(
'letsencrypt.tests', os.path.join('testdata', 'csr.pem')))
CERT = OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string(
'letsencrypt.tests', os.path.join('testdata', 'cert.pem')))
CSR = OpenSSL.crypto.load_certificate_request(
OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string(
'letsencrypt.tests', os.path.join('testdata', 'csr.pem')))
class FieldTest(unittest.TestCase):
@@ -280,7 +282,7 @@ class DeEncodersTest(unittest.TestCase):
def test_encode_csr(self):
from acme.jose.json_util import encode_csr
self.assertEqual(self.b64_cert, encode_csr(CERT))
self.assertEqual(self.b64_csr, encode_csr(CSR))
def test_decode_csr(self):
from acme.jose.json_util import decode_csr
+6 -4
View File
@@ -3,7 +3,7 @@ import argparse
import base64
import sys
import M2Crypto
import OpenSSL
from acme.jose import b64
from acme.jose import errors
@@ -122,14 +122,16 @@ class Header(json_util.JSONObjectWithFields):
@x5c.encoder
def x5c(value): # pylint: disable=missing-docstring,no-self-argument
return [base64.b64encode(cert.as_der()) for cert in value]
return [base64.b64encode(OpenSSL.crypto.dump_certificate(
OpenSSL.crypto.FILETYPE_ASN1, cert)) for cert in value]
@x5c.decoder
def x5c(value): # pylint: disable=missing-docstring,no-self-argument
try:
return tuple(util.ComparableX509(M2Crypto.X509.load_cert_der_string(
return tuple(util.ComparableX509(OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_ASN1,
base64.b64decode(cert))) for cert in value)
except M2Crypto.X509.X509Error as error:
except OpenSSL.crypto.Error as error:
raise errors.DeserializationError(error)
+8 -5
View File
@@ -6,8 +6,8 @@ import unittest
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
import M2Crypto
import mock
import OpenSSL
from acme.jose import b64
from acme.jose import errors
@@ -16,8 +16,8 @@ from acme.jose import jwk
from acme.jose import util
CERT = util.ComparableX509(M2Crypto.X509.load_cert(
pkg_resources.resource_filename(
CERT = util.ComparableX509(OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string(
'letsencrypt.tests', 'testdata/cert.pem')))
RSA512_KEY = util.ComparableRSAKey(serialization.load_pem_private_key(
pkg_resources.resource_string(
@@ -76,10 +76,13 @@ class HeaderTest(unittest.TestCase):
from acme.jose.jws import Header
header = Header(x5c=(CERT, CERT))
jobj = header.to_partial_json()
cert_b64 = base64.b64encode(CERT.as_der())
cert_b64 = base64.b64encode(OpenSSL.crypto.dump_certificate(
OpenSSL.crypto.FILETYPE_ASN1, CERT))
self.assertEqual(jobj, {'x5c': [cert_b64, cert_b64]})
self.assertEqual(header, Header.from_json(jobj))
jobj['x5c'][0] = base64.b64encode('xxx' + CERT.as_der())
jobj['x5c'][0] = base64.b64encode(
'xxx' + OpenSSL.crypto.dump_certificate(
OpenSSL.crypto.FILETYPE_ASN1, CERT))
self.assertRaises(errors.DeserializationError, Header.from_json, jobj)
def test_find_key(self):
+21 -4
View File
@@ -2,6 +2,7 @@
import collections
from cryptography.hazmat.primitives.asymmetric import rsa
import OpenSSL
class abstractclassmethod(classmethod):
@@ -25,12 +26,12 @@ class abstractclassmethod(classmethod):
class ComparableX509(object): # pylint: disable=too-few-public-methods
"""Wrapper for M2Crypto.X509.* objects that supports __eq__.
"""Wrapper for OpenSSL.crypto.X509** objects that supports __eq__.
Wraps around:
- :class:`M2Crypto.X509.X509`
- :class:`M2Crypto.X509.Request`
- :class:`OpenSSL.crypto.X509`
- :class:`OpenSSL.crypto.X509Req`
"""
def __init__(self, wrapped):
@@ -40,7 +41,23 @@ class ComparableX509(object): # pylint: disable=too-few-public-methods
return getattr(self._wrapped, name)
def __eq__(self, other):
return self.as_der() == other.as_der()
filetype = OpenSSL.crypto.FILETYPE_ASN1
def as_der(obj):
# pylint: disable=missing-docstring,protected-access
if isinstance(obj, type(self)):
obj = obj._wrapped
if isinstance(obj, OpenSSL.crypto.X509):
func = OpenSSL.crypto.dump_certificate
elif isinstance(obj, OpenSSL.crypto.X509Req):
func = OpenSSL.crypto.dump_certificate_request
else:
raise TypeError(
"Equality for {0} not provided".format(obj.__class__))
return func(filetype, obj)
return as_der(self) == as_der(other)
def __repr__(self):
return '<{0}({1!r})>'.format(self.__class__.__name__, self._wrapped)
class ComparableRSAKey(object): # pylint: disable=too-few-public-methods
+32
View File
@@ -6,6 +6,38 @@ import unittest
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
import OpenSSL
class ComparableX509Test(unittest.TestCase):
"""Tests for acme.jose.util.ComparableX509."""
def setUp(self):
from acme.jose.util import ComparableX509
def load_cert(): # pylint: disable=missing-docstring
return ComparableX509(OpenSSL.crypto.load_certificate_request(
OpenSSL.crypto.FILETYPE_ASN1, pkg_resources.resource_string(
__name__, os.path.join('testdata', 'csr.der'))))
self.cert = load_cert()
self.cert_same = load_cert()
self.cert2 = ComparableX509(OpenSSL.crypto.load_certificate_request(
OpenSSL.crypto.FILETYPE_PEM, pkg_resources.resource_string(
'letsencrypt.tests', os.path.join('testdata', 'csr-san.pem'))))
def test_eq(self):
self.assertEqual(self.cert, self.cert_same)
def test_not_eq(self):
self.assertNotEqual(self.cert, self.cert2)
def test_eq_wrong_types(self):
from acme.jose.util import ComparableX509
self.assertRaises(
TypeError, ComparableX509(5).__eq__, ComparableX509(5))
def test_repr(self):
self.assertTrue(repr(self.cert).startswith(
'<ComparableX509(<OpenSSL.crypto.X509'))
class ComparableRSAKeyTest(unittest.TestCase):
+3 -3
View File
@@ -312,7 +312,7 @@ class CertificateRequest(jose.JSONObjectWithFields):
"""ACME new-cert request.
:ivar acme.jose.util.ComparableX509 csr:
`M2Crypto.X509.Request` wrapped in `.ComparableX509`
`OpenSSL.crypto.X509Req` wrapped in `.ComparableX509`
:ivar tuple authorizations: `tuple` of URIs (`str`)
"""
@@ -324,7 +324,7 @@ class CertificateResource(ResourceWithURI):
"""Certificate Resource.
:ivar acme.jose.util.ComparableX509 body:
`M2Crypto.X509.X509` wrapped in `.ComparableX509`
`OpenSSL.crypto.X509` wrapped in `.ComparableX509`
:ivar str cert_chain_uri: URI found in the 'up' ``Link`` header
:ivar tuple authzrs: `tuple` of `AuthorizationResource`.
@@ -336,7 +336,7 @@ class CertificateResource(ResourceWithURI):
class Revocation(jose.JSONObjectWithFields):
"""Revocation message.
:ivar .ComparableX509 certificate: `M2Crypto.X509.X509` wrapped in
:ivar .ComparableX509 certificate: `OpenSSL.crypto.X509` wrapped in
`.ComparableX509`
"""
+9 -11
View File
@@ -5,27 +5,25 @@ import unittest
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
import M2Crypto
import mock
import OpenSSL
from acme import challenges
from acme import jose
CERT = jose.ComparableX509(M2Crypto.X509.load_cert_string(
pkg_resources.resource_string(
'acme.jose', os.path.join('testdata', 'cert.der')),
M2Crypto.X509.FORMAT_DER))
CSR = jose.ComparableX509(M2Crypto.X509.load_request_string(
pkg_resources.resource_string(
'acme.jose', os.path.join('testdata', 'csr.der')),
M2Crypto.X509.FORMAT_DER))
CERT = jose.ComparableX509(OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_ASN1, pkg_resources.resource_string(
'acme.jose', os.path.join('testdata', 'cert.der'))))
CSR = jose.ComparableX509(OpenSSL.crypto.load_certificate_request(
OpenSSL.crypto.FILETYPE_ASN1, pkg_resources.resource_string(
'acme.jose', os.path.join('testdata', 'csr.der'))))
KEY = jose.util.ComparableRSAKey(serialization.load_pem_private_key(
pkg_resources.resource_string(
'acme.jose', os.path.join('testdata', 'rsa512_key.pem')),
password=None, backend=default_backend()))
CERT = jose.ComparableX509(M2Crypto.X509.load_cert(
format=M2Crypto.X509.FORMAT_DER, file=pkg_resources.resource_filename(
CERT = jose.ComparableX509(OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_ASN1, pkg_resources.resource_string(
'acme.jose', os.path.join('testdata', 'cert.der'))))