File CVE-2018-1000807-8_use_after_free_X509.patch of Package python-pyOpenSSL.9666

From e73818600065821d588af475b024f4eb518c3509 Mon Sep 17 00:00:00 2001
From: Paul Kehrer <paul.l.kehrer@gmail.com>
Date: Thu, 30 Nov 2017 20:55:25 +0800
Subject: [PATCH] fix a memory leak and a potential UAF and also #722 (#723)

* fix a memory leak and a potential UAF and also #722

* sanity check

* bump cryptography minimum version, add changelog
---
 CHANGELOG.rst         |  6 +++---
 setup.py              |  2 +-
 src/OpenSSL/SSL.py    |  5 +++--
 src/OpenSSL/crypto.py |  7 +++----
 tests/test_ssl.py     | 25 +++++++++++++++++++++++++
 tox.ini               |  2 +-
 6 files changed, 36 insertions(+), 11 deletions(-)

Index: pyOpenSSL-16.0.0/src/OpenSSL/SSL.py
===================================================================
--- pyOpenSSL-16.0.0.orig/src/OpenSSL/SSL.py
+++ pyOpenSSL-16.0.0/src/OpenSSL/SSL.py
@@ -210,8 +210,9 @@ class _VerifyHelper(_CallbackExceptionHe
 
         @wraps(callback)
         def wrapper(ok, store_ctx):
-            cert = X509.__new__(X509)
-            cert._x509 = _lib.X509_STORE_CTX_get_current_cert(store_ctx)
+            x509 = _lib.X509_STORE_CTX_get_current_cert(store_ctx)
+            _lib.X509_up_ref(x509)
+            cert = X509._from_raw_x509_ptr(x509)
             error_number = _lib.X509_STORE_CTX_get_error(store_ctx)
             error_depth = _lib.X509_STORE_CTX_get_error_depth(store_ctx)
 
Index: pyOpenSSL-16.0.0/src/OpenSSL/crypto.py
===================================================================
--- pyOpenSSL-16.0.0.orig/src/OpenSSL/crypto.py
+++ pyOpenSSL-16.0.0/src/OpenSSL/crypto.py
@@ -2770,8 +2770,7 @@ def load_pkcs12(buffer, passphrase=None)
         pycert = None
         friendlyname = None
     else:
-        pycert = X509.__new__(X509)
-        pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
+        pycert = X509._from_raw_x509_ptr(cert[0])
 
         friendlyname_length = _ffi.new("int*")
         friendlyname_buffer = _lib.X509_alias_get0(
@@ -2785,8 +2784,8 @@ def load_pkcs12(buffer, passphrase=None)
 
     pycacerts = []
     for i in range(_lib.sk_X509_num(cacerts)):
-        pycacert = X509.__new__(X509)
-        pycacert._x509 = _lib.sk_X509_value(cacerts, i)
+        x509 = _lib.sk_X509_value(cacerts, i)
+        pycacert = X509._from_raw_x509_ptr(x509)
         pycacerts.append(pycacert)
     if not pycacerts:
         pycacerts = None
Index: pyOpenSSL-16.0.0/tests/test_ssl.py
===================================================================
--- pyOpenSSL-16.0.0.orig/tests/test_ssl.py
+++ pyOpenSSL-16.0.0/tests/test_ssl.py
@@ -179,6 +179,68 @@ def handshake(client, server):
                 conns.remove(conn)
 
 
+def interact_in_memory(client_conn, server_conn):
+    """
+    Try to read application bytes from each of the two `Connection` objects.
+    Copy bytes back and forth between their send/receive buffers for as long
+    as there is anything to copy.  When there is nothing more to copy,
+    return `None`.  If one of them actually manages to deliver some application
+    bytes, return a two-tuple of the connection from which the bytes were read
+    and the bytes themselves.
+    """
+    wrote = True
+    while wrote:
+        # Loop until neither side has anything to say
+        wrote = False
+
+        # Copy stuff from each side's send buffer to the other side's
+        # receive buffer.
+        for (read, write) in [(client_conn, server_conn),
+                              (server_conn, client_conn)]:
+
+            # Give the side a chance to generate some more bytes, or succeed.
+            try:
+                data = read.recv(2 ** 16)
+            except WantReadError:
+                # It didn't succeed, so we'll hope it generated some output.
+                pass
+            else:
+                # It did succeed, so we'll stop now and let the caller deal
+                # with it.
+                return (read, data)
+
+            while True:
+                # Keep copying as long as there's more stuff there.
+                try:
+                    dirty = read.bio_read(4096)
+                except WantReadError:
+                    # Okay, nothing more waiting to be sent.  Stop
+                    # processing this send buffer.
+                    break
+                else:
+                    # Keep track of the fact that someone generated some
+                    # output.
+                    wrote = True
+                    write.bio_write(dirty)
+
+
+def handshake_in_memory(client_conn, server_conn):
+    """
+    Perform the TLS handshake between two `Connection` instances connected to
+    each other via memory BIOs.
+    """
+    client_conn.set_connect_state()
+    server_conn.set_accept_state()
+
+    for conn in [client_conn, server_conn]:
+        try:
+            conn.do_handshake()
+        except WantReadError:
+            pass
+
+    interact_in_memory(client_conn, server_conn)
+
+
 def _create_certificate_chain():
     """
     Construct and return a chain of certificates.
@@ -1300,6 +1362,31 @@ class ContextTests(TestCase, _LoopbackMi
 
         self.assertIdentical(verify.connection, clientConnection)
 
+    def test_x509_in_verify_works(self):
+        """
+        We had a bug where the X509 cert instantiated in the callback wrapper
+        didn't __init__ so it was missing objects needed when calling
+        get_subject. This test sets up a handshake where we call get_subject
+        on the cert provided to the verify callback.
+        """
+        serverContext = Context(TLSv1_METHOD)
+        serverContext.use_privatekey(
+            load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM))
+        serverContext.use_certificate(
+            load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
+        serverConnection = Connection(serverContext, None)
+
+        def verify_cb_get_subject(conn, cert, errnum, depth, ok):
+            assert cert.get_subject()
+            return 1
+
+        clientContext = Context(TLSv1_METHOD)
+        clientContext.set_verify(VERIFY_PEER, verify_cb_get_subject)
+        clientConnection = Connection(clientContext, None)
+        clientConnection.set_connect_state()
+
+        handshake_in_memory(clientConnection, serverConnection)
+
     def test_set_verify_callback_exception(self):
         """
         If the verify callback passed to :py:obj:`Context.set_verify` raises an
openSUSE Build Service is sponsored by