|
| 1 | +diff --git a/pywbem/_cim_http.py b/pywbem/_cim_http.py |
| 2 | +index b6080058..2779d7aa 100644 |
| 3 | +--- a/pywbem/_cim_http.py |
| 4 | ++++ b/pywbem/_cim_http.py |
| 5 | +@@ -57,22 +57,12 @@ from ._utils import _ensure_unicode, _ensure_bytes, _format |
| 6 | + |
| 7 | + _ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' |
| 8 | + |
| 9 | +-if six.PY2 and not _ON_RTD: # RTD has no swig to install M2Crypto |
| 10 | +- # pylint: disable=wrong-import-order,wrong-import-position |
| 11 | +- from M2Crypto import SSL |
| 12 | +- from M2Crypto.Err import SSLError |
| 13 | +- from M2Crypto.m2 import OPENSSL_VERSION_TEXT as OPENSSL_VERSION |
| 14 | +- _HAVE_M2CRYPTO = True |
| 15 | +- # pylint: disable=invalid-name |
| 16 | +- SocketErrors = (socket.error, socket.sslerror) |
| 17 | +-else: |
| 18 | +- # pylint: disable=wrong-import-order,wrong-import-position |
| 19 | +- import ssl as SSL |
| 20 | +- from ssl import SSLError, CertificateError |
| 21 | +- from ssl import OPENSSL_VERSION |
| 22 | +- _HAVE_M2CRYPTO = False |
| 23 | +- # pylint: disable=invalid-name |
| 24 | +- SocketErrors = (socket.error,) |
| 25 | ++# pylint: disable=wrong-import-order |
| 26 | ++import ssl as SSL |
| 27 | ++from ssl import SSLError, CertificateError |
| 28 | ++from ssl import OPENSSL_VERSION |
| 29 | ++# pylint: disable=invalid-name |
| 30 | ++SocketErrors = (socket.error,) |
| 31 | + |
| 32 | + __all__ = ['DEFAULT_CA_CERT_PATHS'] |
| 33 | + |
| 34 | +@@ -519,12 +509,25 @@ def wbem_request(url, data, creds, cimxml_headers=None, debug=False, x509=None, |
| 35 | + # Note: We do not use strict=True in the following call, because it |
| 36 | + # is not clear what side effects that would have, and if no status |
| 37 | + # line comes back we'll certainly find out about that. |
| 38 | ++ ssl_context = SSL.create_default_context(purpose=SSL.Purpose.SERVER_AUTH) |
| 39 | ++ ssl_context.check_hostname = False |
| 40 | ++ |
| 41 | ++ if no_verification: |
| 42 | ++ ssl_context.verify_mode = SSL.CERT_NONE |
| 43 | ++ |
| 44 | ++ if cert_file and key_file: |
| 45 | ++ ssl_context.load_cert_chain(cert_file, key_file) |
| 46 | ++ |
| 47 | ++ if ca_certs: |
| 48 | ++ ssl_context.load_verify_locations(ca_certs) |
| 49 | ++ |
| 50 | ++ # 3.12 removed key_file, cert_file, etc. |
| 51 | + httplib.HTTPSConnection.__init__(self, host=host, port=port, |
| 52 | +- key_file=key_file, |
| 53 | +- cert_file=cert_file, |
| 54 | ++ context=ssl_context, |
| 55 | + timeout=timeout) |
| 56 | + self.ca_certs = ca_certs |
| 57 | + self.verify_callback = verify_callback |
| 58 | ++ self.ctx = ssl_context |
| 59 | + # issue 297: Verify_callback is not used in py 3 |
| 60 | + if verify_callback is not None and six.PY3: |
| 61 | + warnings.warn("The 'verify_callback' parameter was specified " |
| 62 | +@@ -534,137 +537,25 @@ def wbem_request(url, data, creds, cimxml_headers=None, debug=False, x509=None, |
| 63 | + def connect(self): |
| 64 | + # pylint: disable=too-many-branches |
| 65 | + """Connect to a host on a given (SSL) port.""" |
| 66 | ++ # set up the socket |
| 67 | ++ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| 68 | ++ sock.settimeout(self.timeout) |
| 69 | + |
| 70 | +- # Connect for M2Crypto ssl package |
| 71 | +- if _HAVE_M2CRYPTO: |
| 72 | +- # Calling httplib.HTTPSConnection.connect(self) does not work |
| 73 | +- # because of its ssl.wrap_socket() call. So we copy the code of |
| 74 | +- # that connect() method modulo the ssl.wrap_socket() call. |
| 75 | +- |
| 76 | +- # Another change is that we do not pass the timeout value |
| 77 | +- # on to the socket call, because that does not work with |
| 78 | +- # M2Crypto. |
| 79 | +- |
| 80 | +- if sys.version_info[0:2] >= (2, 7): |
| 81 | +- # the source_address parameter was added in Python 2.7 |
| 82 | +- self.sock = socket.create_connection( |
| 83 | +- (self.host, self.port), None, self.source_address) |
| 84 | +- else: |
| 85 | +- self.sock = socket.create_connection( |
| 86 | +- (self.host, self.port), None) |
| 87 | +- |
| 88 | +- # Removed code for tunneling support. |
| 89 | +- |
| 90 | +- # End of code from httplib.HTTPSConnection.connect(self). |
| 91 | +- |
| 92 | +- ctx = SSL.Context('sslv23') |
| 93 | +- |
| 94 | +- if self.cert_file: |
| 95 | +- ctx.load_cert(self.cert_file, keyfile=self.key_file) |
| 96 | +- if self.ca_certs: |
| 97 | +- ctx.set_verify( |
| 98 | +- SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, |
| 99 | +- depth=9, callback=verify_callback) |
| 100 | +- # M2Crypto requires binary strings as path names and |
| 101 | +- # otherwise raises TypeError. |
| 102 | +- ca_certs = _ensure_bytes(self.ca_certs) |
| 103 | +- if os.path.isdir(self.ca_certs): |
| 104 | +- ctx.load_verify_locations(capath=ca_certs) |
| 105 | +- else: |
| 106 | +- ctx.load_verify_locations(cafile=ca_certs) |
| 107 | +- try: |
| 108 | +- self.sock = SSL.Connection(ctx, self.sock) |
| 109 | +- |
| 110 | +- # Below is a body of SSL.Connection.connect() method |
| 111 | +- # except for the first line (socket connection). |
| 112 | +- |
| 113 | +- # Removed code for tunneling support. |
| 114 | +- |
| 115 | +- # Setting the timeout on the input socket does not work |
| 116 | +- # with M2Crypto, with such a timeout set it calls a |
| 117 | +- # different low level function (nbio instead of bio) |
| 118 | +- # that does not work. The symptom is that reading the |
| 119 | +- # response returns None. |
| 120 | +- # Therefore, we set the timeout at the level of the outer |
| 121 | +- # M2Crypto socket object. |
| 122 | +- # pylint: disable=using-constant-test |
| 123 | +- |
| 124 | +- if self.timeout is not None: |
| 125 | +- self.sock.set_socket_read_timeout( |
| 126 | +- SSL.timeout(self.timeout)) |
| 127 | +- self.sock.set_socket_write_timeout( |
| 128 | +- SSL.timeout(self.timeout)) |
| 129 | +- |
| 130 | +- self.sock.addr = (self.host, self.port) |
| 131 | +- self.sock.setup_ssl() |
| 132 | +- self.sock.set_connect_state() |
| 133 | +- ret = self.sock.connect_ssl() |
| 134 | +- if self.ca_certs: |
| 135 | +- check = getattr(self.sock, 'postConnectionCheck', |
| 136 | +- self.sock.clientPostConnectionCheck) |
| 137 | +- if check is not None: |
| 138 | +- if not check(self.sock.get_peer_cert(), self.host): |
| 139 | +- raise ConnectionError( |
| 140 | +- 'SSL error: post connection check failed', |
| 141 | +- conn_id=conn_id) |
| 142 | +- return ret |
| 143 | +- |
| 144 | +- except (SSLError, SSL.SSLError, |
| 145 | +- SSL.Checker.SSLVerificationError) as arg: |
| 146 | +- raise ConnectionError( |
| 147 | +- _format("SSL error {0}: {1}; OpenSSL version: {2}", |
| 148 | +- arg.__class__, arg, OPENSSL_VERSION), |
| 149 | +- conn_id=conn_id) |
| 150 | +- |
| 151 | +- # Connect using Python SSL module |
| 152 | +- else: |
| 153 | +- # Setup the socket context |
| 154 | +- |
| 155 | +- # Note: PROTOCOL_SSLv23 allows talking to servers with TLS but |
| 156 | +- # not with SSL. For details, see the table in |
| 157 | +- # https://docs.python.org/3/library/ssl.html#ssl.wrap_socket |
| 158 | +- # Within the defined set of protocol versions, SSLv23 selects |
| 159 | +- # the highest protocol version that both client and server |
| 160 | +- # support. |
| 161 | +- # Issue #893: Consider the use of default_context() |
| 162 | +- ctx = SSL.SSLContext(SSL.PROTOCOL_SSLv23) |
| 163 | +- |
| 164 | +- if self.cert_file: |
| 165 | +- ctx.load_cert_chain(self.cert_file, keyfile=self.key_file) |
| 166 | +- if self.ca_certs: |
| 167 | +- # We need to use CERT_REQUIRED to require that the server |
| 168 | +- # certificate is being validated by the client (against the |
| 169 | +- # certificates in ca_certs). |
| 170 | +- ctx.verify_mode = SSL.CERT_REQUIRED |
| 171 | +- if os.path.isdir(self.ca_certs): |
| 172 | +- ctx.load_verify_locations(capath=self.ca_certs) |
| 173 | +- else: |
| 174 | +- ctx.load_verify_locations(cafile=self.ca_certs) |
| 175 | +- ctx.check_hostname = True |
| 176 | +- else: |
| 177 | +- ctx.check_hostname = False |
| 178 | +- ctx.verify_mode = SSL.CERT_NONE |
| 179 | +- |
| 180 | +- # setup the socket |
| 181 | +- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| 182 | +- sock.settimeout(self.timeout) |
| 183 | +- |
| 184 | +- try: |
| 185 | +- self.sock = ctx.wrap_socket(sock, |
| 186 | +- server_hostname=self.host) |
| 187 | +- return self.sock.connect((self.host, self.port)) |
| 188 | ++ try: |
| 189 | ++ self.sock = self.ctx.wrap_socket(sock) |
| 190 | ++ return self.sock.connect((self.host, self.port)) |
| 191 | + |
| 192 | +- except SSLError as arg: |
| 193 | +- raise ConnectionError( |
| 194 | +- _format("SSL error {0}: {1}; OpenSSL version: {2}", |
| 195 | +- arg.__class__, arg, OPENSSL_VERSION), |
| 196 | +- conn_id=conn_id) |
| 197 | +- except CertificateError as arg: |
| 198 | +- raise ConnectionError( |
| 199 | +- _format("SSL certificate error {0}: {1}; " |
| 200 | +- "OpenSSL version: {2}", |
| 201 | +- arg.__class__, arg, OPENSSL_VERSION), |
| 202 | +- conn_id=conn_id) |
| 203 | ++ except SSLError as arg: |
| 204 | ++ raise ConnectionError( |
| 205 | ++ _format("SSL error {0}: {1}; OpenSSL version: {2}", |
| 206 | ++ arg.__class__, arg, OPENSSL_VERSION), |
| 207 | ++ conn_id=conn_id) |
| 208 | ++ except CertificateError as arg: |
| 209 | ++ raise ConnectionError( |
| 210 | ++ _format("SSL certificate error {0}: {1}; " |
| 211 | ++ "OpenSSL version: {2}", |
| 212 | ++ arg.__class__, arg, OPENSSL_VERSION), |
| 213 | ++ conn_id=conn_id) |
| 214 | + |
| 215 | + class FileHTTPConnection(HTTPBaseConnection, httplib.HTTPConnection): |
| 216 | + """Execute client connection based on a unix domain socket. """ |
0 commit comments