aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2015-05-19 21:21:32 -0700
committerPaul Kehrer <paul.l.kehrer@gmail.com>2015-05-19 21:21:32 -0700
commitf2646557cbe6ee7dc8c338ad60b188a8ab1978ab (patch)
treef527720eb68b827b79b9a354058edce33eb576b2
parentc5db584e727c180b7d426bd13675a8e0d0980dd3 (diff)
parent9dd2ab94131c57af7aceac6785ee3607e02b1353 (diff)
downloadcryptography-f2646557cbe6ee7dc8c338ad60b188a8ab1978ab.tar.gz
cryptography-f2646557cbe6ee7dc8c338ad60b188a8ab1978ab.tar.bz2
cryptography-f2646557cbe6ee7dc8c338ad60b188a8ab1978ab.zip
Merge pull request #1984 from AndreLouisCaron/cert-encoding
Adds certificate encoding to PEM and DER.
-rw-r--r--CHANGELOG.rst2
-rw-r--r--docs/x509.rst9
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py12
-rw-r--r--src/cryptography/x509.py6
-rw-r--r--tests/test_x509.py84
5 files changed, 113 insertions, 0 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 4d7a9a82..07d903c1 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -9,6 +9,8 @@ Changelog
* Support serialization of certificate signing requests using the
``public_bytes`` method of
:class:`~cryptography.x509.CertificateSigningRequest`.
+* Support serialization of certificates using the ``public_bytes`` method of
+ :class:`~cryptography.x509.Certificate`.
0.9 - 2015-05-13
~~~~~~~~~~~~~~~~
diff --git a/docs/x509.rst b/docs/x509.rst
index c570f196..5e4d9bfa 100644
--- a/docs/x509.rst
+++ b/docs/x509.rst
@@ -326,6 +326,15 @@ X.509 Certificate Object
<Extension(oid=<ObjectIdentifier(oid=2.5.29.32, name=certificatePolicies)>, critical=False, value=<CertificatePolicies([<PolicyInformation(policy_identifier=<ObjectIdentifier(oid=2.16.840.1.101.3.2.1.48.1, name=Unknown OID)>, policy_qualifiers=None)>])>)>
<Extension(oid=<ObjectIdentifier(oid=2.5.29.19, name=basicConstraints)>, critical=True, value=<BasicConstraints(ca=True, path_length=None)>)>
+ .. method:: public_bytes(encoding)
+
+ :param encoding: The
+ :class:`~cryptography.hazmat.primitives.serialization.Encoding`
+ that will be used to serialize the certificate.
+
+ :return bytes: The data that can be written to a file or sent
+ over the network to be verified by clients.
+
X.509 CSR (Certificate Signing Request) Object
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index 72041366..c7d2d154 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -311,6 +311,18 @@ class _Certificate(object):
return x509.Extensions(extensions)
+ def public_bytes(self, encoding):
+ if not isinstance(encoding, serialization.Encoding):
+ raise TypeError("encoding must be an item from the Encoding enum")
+
+ bio = self._backend._create_mem_bio()
+ if encoding is serialization.Encoding.PEM:
+ res = self._backend._lib.PEM_write_bio_X509(bio, self._x509)
+ elif encoding is serialization.Encoding.DER:
+ res = self._backend._lib.i2d_X509_bio(bio, self._x509)
+ assert res == 1
+ return self._backend._read_mem_bio(bio)
+
def _decode_certificate_policies(backend, ext):
cp = backend._ffi.cast(
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
index 9a3295ce..e6d19ae7 100644
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -1167,6 +1167,12 @@ class Certificate(object):
Checks not equal.
"""
+ @abc.abstractmethod
+ def public_bytes(self, encoding):
+ """
+ Serializes the certificate to PEM or DER format.
+ """
+
@six.add_metaclass(abc.ABCMeta)
class CertificateSigningRequest(object):
diff --git a/tests/test_x509.py b/tests/test_x509.py
index 72fc9d40..a3bed85f 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -368,6 +368,90 @@ class TestRSACertificate(object):
with pytest.raises(UnsupportedAlgorithm):
cert.signature_hash_algorithm
+ def test_public_bytes_pem(self, backend):
+ # Load an existing certificate.
+ cert = _load_cert(
+ os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"),
+ x509.load_der_x509_certificate,
+ backend
+ )
+
+ # Encode it to PEM and load it back.
+ cert = x509.load_pem_x509_certificate(cert.public_bytes(
+ encoding=serialization.Encoding.PEM,
+ ), backend)
+
+ # We should recover what we had to start with.
+ assert cert.not_valid_before == datetime.datetime(2010, 1, 1, 8, 30)
+ assert cert.not_valid_after == datetime.datetime(2030, 12, 31, 8, 30)
+ assert cert.serial == 2
+ public_key = cert.public_key()
+ assert isinstance(public_key, rsa.RSAPublicKey)
+ assert cert.version is x509.Version.v3
+ fingerprint = binascii.hexlify(cert.fingerprint(hashes.SHA1()))
+ assert fingerprint == b"6f49779533d565e8b7c1062503eab41492c38e4d"
+
+ def test_public_bytes_der(self, backend):
+ # Load an existing certificate.
+ cert = _load_cert(
+ os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"),
+ x509.load_der_x509_certificate,
+ backend
+ )
+
+ # Encode it to DER and load it back.
+ cert = x509.load_der_x509_certificate(cert.public_bytes(
+ encoding=serialization.Encoding.DER,
+ ), backend)
+
+ # We should recover what we had to start with.
+ assert cert.not_valid_before == datetime.datetime(2010, 1, 1, 8, 30)
+ assert cert.not_valid_after == datetime.datetime(2030, 12, 31, 8, 30)
+ assert cert.serial == 2
+ public_key = cert.public_key()
+ assert isinstance(public_key, rsa.RSAPublicKey)
+ assert cert.version is x509.Version.v3
+ fingerprint = binascii.hexlify(cert.fingerprint(hashes.SHA1()))
+ assert fingerprint == b"6f49779533d565e8b7c1062503eab41492c38e4d"
+
+ def test_public_bytes_invalid_encoding(self, backend):
+ cert = _load_cert(
+ os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"),
+ x509.load_der_x509_certificate,
+ backend
+ )
+
+ with pytest.raises(TypeError):
+ cert.public_bytes('NotAnEncoding')
+
+ @pytest.mark.parametrize(
+ ("cert_path", "loader_func", "encoding"),
+ [
+ (
+ os.path.join("x509", "v1_cert.pem"),
+ x509.load_pem_x509_certificate,
+ serialization.Encoding.PEM,
+ ),
+ (
+ os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"),
+ x509.load_der_x509_certificate,
+ serialization.Encoding.DER,
+ ),
+ ]
+ )
+ def test_public_bytes_match(self, cert_path, loader_func, encoding,
+ backend):
+ cert_bytes = load_vectors_from_file(
+ cert_path, lambda pemfile: pemfile.read(), mode="rb"
+ )
+ cert = loader_func(cert_bytes, backend)
+ serialized = cert.public_bytes(encoding)
+ assert serialized == cert_bytes
+
+
+@pytest.mark.requires_backend_interface(interface=RSABackend)
+@pytest.mark.requires_backend_interface(interface=X509Backend)
+class TestRSACertificateRequest(object):
@pytest.mark.parametrize(
("path", "loader_func"),
[