diff options
author | Timothy Redaelli <tredaelli@redhat.com> | 2021-10-30 01:12:14 +0200 |
---|---|---|
committer | Ilya Maximets <i.maximets@ovn.org> | 2021-11-03 16:00:04 +0100 |
commit | 68543dd523bd00f53fa7b91777b962ccb22ce679 (patch) | |
tree | 8aff5caebf7a7f203fae24a6b96b56e21b8830d6 /python | |
parent | 3f550fa53824be9ba65e8095d3e97d713be388c9 (diff) | |
download | openvswitch-68543dd523bd00f53fa7b91777b962ccb22ce679.tar.gz |
python: Replace pyOpenSSL with ssl.
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.
TCPstream._open cannot be used in SSLStream, since Python ssl module
requires the SSL socket to be created before connecting it, so
SSLStream._open needs to create the socket, create SSL socket and then
connect the SSL socket.
Reported-by: Timothy Redaelli <tredaelli@redhat.com>
Reported-at: https://bugzilla.redhat.com/1988429
Signed-off-by: Timothy Redaelli <tredaelli@redhat.com>
Acked-by: Terry Wilson <twilson@redhat.com>
Tested-by: Terry Wilson <twilson@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Diffstat (limited to 'python')
-rw-r--r-- | python/ovs/poller.py | 6 | ||||
-rw-r--r-- | python/ovs/stream.py | 91 |
2 files changed, 57 insertions, 40 deletions
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..ac5b0fd0c 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,7 +775,7 @@ 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 @@ -777,27 +783,34 @@ class SSLStream(Stream): return True @staticmethod - def verify_cb(conn, cert, errnum, depth, ok): - return ok - - @staticmethod def _open(suffix, dscp): - error, sock = TCPStream._open(suffix, dscp) - if error: - return error, None + address = ovs.socket_util.inet_parse_active(suffix, 0) + family, sock = ovs.socket_util.inet_create_socket_active( + socket.SOCK_STREAM, address) + if sock is None: + return family, sock # 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) + ctx.load_cert_chain(Stream._SSL_certificate_file, + Stream._SSL_private_key_file) + ssl_sock = ctx.wrap_socket(sock, do_handshake_on_connect=False) - ssl_sock = SSL.Connection(ctx, sock) - ssl_sock.set_connect_state() + # Connect + error = ovs.socket_util.inet_connect_active(ssl_sock, address, family, + dscp) + if not error: + try: + ssl_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + except socket.error as e: + ssl_sock.close() + return ovs.socket_util.get_exception_errno(e), None return error, ssl_sock def connect(self): @@ -809,40 +822,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: pass return super(SSLStream, self).close() -if SSL: +if ssl: # Register SSL only if the OpenSSL module is available Stream.register_method("ssl", SSLStream) |