Repository: pyca/pyopenssl
Pull request #640 (2017-06-25 20:00:10)

Added an API for converting X509 to/from cryptography

codecov[bot]: # [Codecov](https://codecov.io/gh/pyca/pyopenssl/pull/640?src=pr&el=h1) Report
> Merging [#640](https://codecov.io/gh/pyca/pyopenssl/pull/640?src=pr&el=desc) into [master](https://codecov.io/gh/pyca/pyopenssl/commit/ce98ee6075399343ee4580dc334e6bc38bfbc221?src=pr&el=desc) will **increase** coverage by `0.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/pyca/pyopenssl/pull/640/graphs/tree.svg?token=KKfpMZOTgK&width=650&src=pr&height=150)](https://codecov.io/gh/pyca/pyopenssl/pull/640?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #640      +/-   ##
==========================================
+ Coverage   96.81%   96.82%   +0.01%     
==========================================
  Files          18       18              
  Lines        5621     5646      +25     
  Branches      389      390       +1     
==========================================
+ Hits         5442     5467      +25     
  Misses        120      120              
  Partials       59       59
```


| [Impacted Files](https://codecov.io/gh/pyca/pyopenssl/pull/640?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [tests/test\_crypto.py](https://codecov.io/gh/pyca/pyopenssl/pull/640?src=pr&el=tree#diff-dGVzdHMvdGVzdF9jcnlwdG8ucHk=) | `98.58% <100%> (+0.01%)` | :arrow_up: |
| [src/OpenSSL/crypto.py](https://codecov.io/gh/pyca/pyopenssl/pull/640?src=pr&el=tree#diff-c3JjL09wZW5TU0wvY3J5cHRvLnB5) | `96.59% <100%> (+0.03%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pyca/pyopenssl/pull/640?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pyca/pyopenssl/pull/640?src=pr&el=footer). Last update [ce98ee6...80cfd5c](https://codecov.io/gh/pyca/pyopenssl/pull/640?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 5bd844c..ee372c3 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -31,6 +31,7 @@ Deprecations:
 Changes:
 ^^^^^^^^
 
+- Added ``OpenSSL.crypto.X509.from_cryptography`` and ``OpenSSL.crypto.X509.to_cryptography`` for converting X.509 certificate to and from pyca/cryptography objects. `#640 <https://github.com/pyca/pyopenssl/pull/640>`_
 - Added ``OpenSSL.debug`` that allows to get an overview of used library versions (including linked OpenSSL) and other useful runtime information using ``python -m OpenSSL.debug``.
   `#620 <https://github.com/pyca/pyopenssl/pull/620>`_
 
diff --git a/src/OpenSSL/crypto.py b/src/OpenSSL/crypto.py
index ae05ede..cdbcc22 100644
--- a/src/OpenSSL/crypto.py
+++ b/src/OpenSSL/crypto.py
@@ -10,6 +10,7 @@ from six import (
     text_type as _text_type,
     PY3 as _PY3)
 
+from cryptography import x509
 from cryptography.hazmat.primitives.asymmetric import dsa, rsa
 
 from OpenSSL._util import (
@@ -996,6 +997,37 @@ class X509(object):
         _openssl_assert(x509 != _ffi.NULL)
         self._x509 = _ffi.gc(x509, _lib.X509_free)
 
+    def to_cryptography(self):
+        """
+        Export as a ``cryptography`` certificate.
+
+        :rtype: ``cryptography.x509.Certificate``
+
+        .. versionadded:: 17.1.0
+        """
+        from cryptography.hazmat.backends.openssl.x509 import _Certificate
+        backend = _get_backend()
+        return _Certificate(backend, self._x509)
+
+    @classmethod
+    def from_cryptography(cls, crypto_cert):
+        """
+        Construct based on a ``cryptography`` *crypto_cert*.
+
+        :param crypto_key: A ``cryptography`` X.509 certificate.
+        :type crypto_key: ``cryptography.x509.Certificate``
+
+        :rtype: PKey
+
+        .. versionadded:: 17.1.0
+        """
+        if not isinstance(crypto_cert, x509.Certificate):
+            raise TypeError("Must be a certificate")
+
+        cert = cls()
+        cert._x509 = crypto_cert._x509
+        return cert
+
     def set_version(self, version):
         """
         Set the version number of the certificate.
diff --git a/src/OpenSSL/rand.py b/src/OpenSSL/rand.py
index 09cf988..cf2053f 100644
--- a/src/OpenSSL/rand.py
+++ b/src/OpenSSL/rand.py
@@ -157,22 +157,6 @@ def write_file(filename):
     return _lib.RAND_write_file(filename)
 
 
-# TODO There are no tests for screen at all
-def screen():
-    """
-    Add the current contents of the screen to the PRNG state.
-
-    Availability: Windows.
-
-    :return: None
-    """
-    _lib.RAND_screen()
-
-
-if getattr(_lib, 'RAND_screen', None) is None:
-    del screen
-
-
 # TODO There are no tests for the RAND strings being loaded, whatever that
 # means.
 _lib.ERR_load_RAND_strings()


Test patch:
diff --git a/tests/test_crypto.py b/tests/test_crypto.py
index 5efb904..2bcc933 100644
--- a/tests/test_crypto.py
+++ b/tests/test_crypto.py
@@ -17,6 +17,7 @@ import pytest
 
 from six import binary_type
 
+from cryptography import x509
 from cryptography.hazmat.backends.openssl.backend import backend
 from cryptography.hazmat.primitives import serialization
 from cryptography.hazmat.primitives.asymmetric import rsa
@@ -1922,6 +1923,26 @@ tgI5
         with pytest.raises(TypeError):
             cert.sign(object(), b"sha256")
 
+    def test_convert_from_cryptography(self):
+        crypto_cert = x509.load_pem_x509_certificate(
+            intermediate_cert_pem, backend
+        )
+        cert = X509.from_cryptography(crypto_cert)
+
+        assert isinstance(cert, X509)
+        assert cert.get_version() == crypto_cert.version.value
+
+    def test_convert_from_cryptography_unsupported_type(self):
+        with pytest.raises(TypeError):
+            X509.from_cryptography(object())
+
+    def test_convert_to_cryptography_key(self):
+        cert = load_certificate(FILETYPE_PEM, intermediate_cert_pem)
+        crypto_cert = cert.to_cryptography()
+
+        assert isinstance(crypto_cert, x509.Certificate)
+        assert crypto_cert.version.value == cert.get_version()
+
 
 class TestX509Store(object):
     """