Hi Timothy,

I can't claim to be a subject matter expert, but the changes make sense on the surface. I can also confirm the OVN testsuite passes with this change.

Acked-by: Mark Michelson <[email protected]>

On 9/10/21 10:34 AM, Timothy Redaelli wrote:
Currently, pyOpenSSL is half-deprecated upstream and so it's removed on
some distributions (for example on CentOS Stream 9,
https://issues.redhat.com/browse/CS-336), but since OVS only
supports Python 3 it's possible to replace pyOpenSSL with "import ssl"
included in base Python 3.

Stream recv and send had to be splitted as _recv and _send, since SSLError
is a subclass of socket.error and so it was not possible to except for
SSLWantReadError and SSLWantWriteError in recv and send of SSLStream.

Reported-by: Timothy Redaelli <[email protected]>
Reported-at: https://bugzilla.redhat.com/1988429
Signed-off-by: Timothy Redaelli <[email protected]>
---
  .ci/linux-prepare.sh |  2 +-
  .cirrus.yml          |  2 +-
  .travis.yml          |  1 -
  python/ovs/poller.py |  6 ++--
  python/ovs/stream.py | 75 +++++++++++++++++++++++---------------------
  tests/ovsdb-idl.at   |  2 +-
  6 files changed, 46 insertions(+), 42 deletions(-)

diff --git a/.ci/linux-prepare.sh b/.ci/linux-prepare.sh
index c55125cf7..b9b499bad 100755
--- a/.ci/linux-prepare.sh
+++ b/.ci/linux-prepare.sh
@@ -21,7 +21,7 @@ make -j4 HAVE_LLVM= HAVE_SQLITE= install
  cd ..
pip3 install --disable-pip-version-check --user \
-    flake8 hacking sphinx pyOpenSSL wheel setuptools
+    flake8 hacking sphinx wheel setuptools
  pip3 install --user --upgrade docutils
  pip3 install --user  'meson==0.47.1'
diff --git a/.cirrus.yml b/.cirrus.yml
index 358f2ba25..bb206f35f 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -9,7 +9,7 @@ freebsd_build_task:
env:
      DEPENDENCIES: automake libtool gmake gcc wget openssl python3
-    PY_DEPS:      sphinx|openssl
+    PY_DEPS:      sphinx
      matrix:
        COMPILER: gcc
        COMPILER: clang
diff --git a/.travis.yml b/.travis.yml
index 51d051108..c7aeede06 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,7 +17,6 @@ addons:
        - libjemalloc-dev
        - libnuma-dev
        - libpcap-dev
-      - python3-openssl
        - python3-pip
        - python3-sphinx
        - libelf-dev
diff --git a/python/ovs/poller.py b/python/ovs/poller.py
index 3624ec865..157719c3a 100644
--- a/python/ovs/poller.py
+++ b/python/ovs/poller.py
@@ -26,9 +26,9 @@ if sys.platform == "win32":
      import ovs.winutils as winutils
try:
-    from OpenSSL import SSL
+    import ssl
  except ImportError:
-    SSL = None
+    ssl = None
try:
      from eventlet import patcher as eventlet_patcher
@@ -73,7 +73,7 @@ class _SelectSelect(object):
      def register(self, fd, events):
          if isinstance(fd, socket.socket):
              fd = fd.fileno()
-        if SSL and isinstance(fd, SSL.Connection):
+        if ssl and isinstance(fd, ssl.SSLSocket):
              fd = fd.fileno()
if sys.platform != 'win32':
diff --git a/python/ovs/stream.py b/python/ovs/stream.py
index f5a520862..cd74b46be 100644
--- a/python/ovs/stream.py
+++ b/python/ovs/stream.py
@@ -22,9 +22,9 @@ import ovs.socket_util
  import ovs.vlog
try:
-    from OpenSSL import SSL
+    import ssl
  except ImportError:
-    SSL = None
+    ssl = None
if sys.platform == 'win32':
      import ovs.winutils as winutils
@@ -322,6 +322,12 @@ class Stream(object):
          The recv function will not block waiting for data to arrive.  If no
          data have been received, it returns (errno.EAGAIN, "") immediately."""
+ try:
+            return self._recv(n)
+        except socket.error as e:
+            return (ovs.socket_util.get_exception_errno(e), "")
+
+    def _recv(self, n):
          retval = self.connect()
          if retval != 0:
              return (retval, "")
@@ -331,10 +337,7 @@ class Stream(object):
          if sys.platform == 'win32' and self.socket is None:
              return self.__recv_windows(n)
- try:
-            return (0, self.socket.recv(n))
-        except socket.error as e:
-            return (ovs.socket_util.get_exception_errno(e), "")
+        return (0, self.socket.recv(n))
def __recv_windows(self, n):
          if self._read_pending:
@@ -396,6 +399,12 @@ class Stream(object):
          Will not block.  If no bytes can be immediately accepted for
          transmission, returns -errno.EAGAIN immediately."""
+ try:
+            return self._send(buf)
+        except socket.error as e:
+            return -ovs.socket_util.get_exception_errno(e)
+
+    def _send(self, buf):
          retval = self.connect()
          if retval != 0:
              return -retval
@@ -409,10 +418,7 @@ class Stream(object):
          if sys.platform == 'win32' and self.socket is None:
              return self.__send_windows(buf)
- try:
-            return self.socket.send(buf)
-        except socket.error as e:
-            return -ovs.socket_util.get_exception_errno(e)
+        return self.socket.send(buf)
def __send_windows(self, buf):
          if self._write_pending:
@@ -769,17 +775,13 @@ class SSLStream(Stream):
      def check_connection_completion(sock):
          try:
              return Stream.check_connection_completion(sock)
-        except SSL.SysCallError as e:
+        except ssl.SSLSyscallError as e:
              return ovs.socket_util.get_exception_errno(e)
@staticmethod
      def needs_probes():
          return True
- @staticmethod
-    def verify_cb(conn, cert, errnum, depth, ok):
-        return ok
-
      @staticmethod
      def _open(suffix, dscp):
          error, sock = TCPStream._open(suffix, dscp)
@@ -787,17 +789,16 @@ class SSLStream(Stream):
              return error, None
# Create an SSL context
-        ctx = SSL.Context(SSL.SSLv23_METHOD)
-        ctx.set_verify(SSL.VERIFY_PEER, SSLStream.verify_cb)
-        ctx.set_options(SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3)
+        ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+        ctx.verify_mode = ssl.CERT_REQUIRED
+        ctx.options |= ssl.OP_NO_SSLv2
+        ctx.options |= ssl.OP_NO_SSLv3
          # If the client has not set the SSL configuration files
          # exception would be raised.
-        ctx.use_privatekey_file(Stream._SSL_private_key_file)
-        ctx.use_certificate_file(Stream._SSL_certificate_file)
          ctx.load_verify_locations(Stream._SSL_ca_cert_file)
-
-        ssl_sock = SSL.Connection(ctx, sock)
-        ssl_sock.set_connect_state()
+        ctx.load_cert_chain(Stream._SSL_certificate_file,
+                            Stream._SSL_private_key_file)
+        ssl_sock = ctx.wrap_socket(sock, do_handshake_on_connect=False)
          return error, ssl_sock
def connect(self):
@@ -809,40 +810,44 @@ class SSLStream(Stream):
          # TCP Connection is successful. Now do the SSL handshake
          try:
              self.socket.do_handshake()
-        except SSL.WantReadError:
+        except ssl.SSLWantReadError:
              return errno.EAGAIN
-        except SSL.SysCallError as e:
+        except ssl.SSLSyscallError as e:
              return ovs.socket_util.get_exception_errno(e)
return 0 def recv(self, n):
          try:
-            return super(SSLStream, self).recv(n)
-        except SSL.WantReadError:
+            return super(SSLStream, self)._recv(n)
+        except ssl.SSLWantReadError:
              return (errno.EAGAIN, "")
-        except SSL.SysCallError as e:
+        except ssl.SSLSyscallError as e:
              return (ovs.socket_util.get_exception_errno(e), "")
-        except SSL.ZeroReturnError:
+        except ssl.SSLZeroReturnError:
              return (0, "")
+        except socket.error as e:
+            return (ovs.socket_util.get_exception_errno(e), "")
def send(self, buf):
          try:
-            return super(SSLStream, self).send(buf)
-        except SSL.WantWriteError:
+            return super(SSLStream, self)._send(buf)
+        except ssl.SSLWantWriteError:
              return -errno.EAGAIN
-        except SSL.SysCallError as e:
+        except ssl.SSLSyscallError as e:
+            return -ovs.socket_util.get_exception_errno(e)
+        except socket.error as e:
              return -ovs.socket_util.get_exception_errno(e)
def close(self):
          if self.socket:
              try:
-                self.socket.shutdown()
-            except SSL.Error:
+                self.socket.shutdown(socket.SHUT_RDWR)
+            except (socket.error, OSError, ValueError):
                  pass
          return super(SSLStream, self).close()
-if SSL:
+if ssl:
      # Register SSL only if the OpenSSL module is available
      Stream.register_method("ssl", SSLStream)
diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at
index 501c13b81..0f229b2f9 100644
--- a/tests/ovsdb-idl.at
+++ b/tests/ovsdb-idl.at
@@ -225,7 +225,7 @@ m4_define([OVSDB_CHECK_IDL_TCP6_MULTIPLE_REMOTES_PY],
  m4_define([OVSDB_CHECK_IDL_SSL_PY],
    [AT_SETUP([$1 - Python3 - SSL])
     AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
-   $PYTHON3 -c "import OpenSSL.SSL"
+   $PYTHON3 -c "import ssl"
     SSL_PRESENT=$?
     AT_SKIP_IF([test $SSL_PRESENT != 0])
     AT_KEYWORDS([ovsdb server idl positive Python with ssl socket $5])


_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to