diff options
| -rw-r--r-- | CHANGELOG.rst | 2 | ||||
| -rw-r--r-- | docs/x509.rst | 9 | ||||
| -rw-r--r-- | src/cryptography/hazmat/backends/openssl/x509.py | 12 | ||||
| -rw-r--r-- | src/cryptography/x509.py | 6 | ||||
| -rw-r--r-- | tests/test_x509.py | 84 | 
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"),          [ | 
