2SecureTranport support for urllib3 via ctypes.
4This makes platform-native TLS available to urllib3 users on macOS without the
5use of a compiler. This is an important feature because the Python Package
6Index is moving to become a TLSv1.2-or-higher server, and the default OpenSSL
7that ships with macOS is not capable of doing TLSv1.2. The only way to resolve
8this is to give macOS users an alternative solution to the problem, and that
9solution is to use SecureTransport.
11We use ctypes here because this solution must not require a compiler. That's
12because pip is not allowed to require a compiler either.
14This is not intended to be a seriously long-term solution to this problem.
15The hope is that PEP 543 will eventually solve this issue for us, at which
16point we can retire this contrib module. But in the short term, we need to
17solve the impending tire fire that is Python on Mac without this kind of
18contrib module. So...here we are.
20To use this module, simply import and inject it::
22 import pip._vendor.urllib3.contrib.securetransport as securetransport
23 securetransport.inject_into_urllib3()
27This code is a bastardised version of the code found in Will Bond's oscrypto
28library. An enormous debt is owed to him for blazing this trail for us. For
29that reason, this code should be considered to be covered both by urllib3's
30license and by oscrypto's:
34 Copyright (c) 2015-2016 Will Bond <will@wbond.net>
36 Permission is hereby granted, free of charge, to any person obtaining a
37 copy of this software and associated documentation files (the "Software"),
38 to deal in the Software without restriction, including without limitation
39 the rights to use, copy, modify, merge, publish, distribute, sublicense,
40 and/or sell copies of the Software, and to permit persons to whom the
41 Software is furnished to do so, subject to the following conditions:
43 The above copyright notice and this permission notice shall be included in
44 all copies or substantial portions of the Software.
46 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
51 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
52 DEALINGS IN THE SOFTWARE.
54from __future__
import absolute_import
70from ..
util.ssl_ import PROTOCOL_TLS_CLIENT
74 _build_tls_unknown_ca_alert,
76 _create_cfstring_array,
77 _load_client_cert_chain,
82 from socket
import _fileobject
87__all__ = [
"inject_into_urllib3",
"extract_from_urllib3"]
116SSL_WRITE_BLOCKSIZE = 16384
157_protocol_to_min_max = {
162if hasattr(ssl,
"PROTOCOL_SSLv2"):
167if hasattr(ssl,
"PROTOCOL_SSLv3"):
172if hasattr(ssl,
"PROTOCOL_TLSv1"):
177if hasattr(ssl,
"PROTOCOL_TLSv1_1"):
182if hasattr(ssl,
"PROTOCOL_TLSv1_2"):
191 Monkey-patch urllib3 with SecureTransport-backed SSL-support.
203 Undo monkey-patching by :func:`inject_into_urllib3`.
215 SecureTransport read callback. This is called by ST to request that data
216 be returned from the socket.
218 wrapped_socket =
None
221 if wrapped_socket
is None:
225 requested_length = data_length_pointer[0]
232 while read_count < requested_length:
233 if timeout
is None or timeout >= 0:
237 remaining = requested_length - read_count
239 data_buffer + read_count
242 read_count += chunk_size
251 data_length_pointer[0] = read_count
256 data_length_pointer[0] = read_count
258 if read_count != requested_length:
262 except Exception
as e:
263 if wrapped_socket
is not None:
270 SecureTransport write callback. This is called by ST to request that data
271 actually be sent on the network.
273 wrapped_socket =
None
276 if wrapped_socket
is None:
280 bytes_to_write = data_length_pointer[0]
288 while sent < bytes_to_write:
289 if timeout
is None or timeout >= 0:
297 data = data[chunk_sent:]
302 data_length_pointer[0] = sent
307 data_length_pointer[0] = sent
309 if sent != bytes_to_write:
313 except Exception
as e:
314 if wrapped_socket
is not None:
328 API-compatibility wrapper for Python's OpenSSL wrapped socket object.
330 Note: _makefile_refs, _drop(), and _reuse() are needed for the garbage
352 @contextlib.contextmanager
355 A context manager that can be used to wrap calls that do I/O from
356 SecureTransport. If any of the I/O callbacks hit an exception, this
357 context manager will correctly propagate the exception after the fact.
358 This avoids silently swallowing those exceptions.
360 It also correctly forces the socket closed.
375 Sets up the allowed ciphers. By default this matches the set in
376 util.ssl_.DEFAULT_CIPHERS, at least as supported by macOS. This is done
377 custom and doesn't allow changing at this time, mostly because parsing
378 OpenSSL cipher strings is going to be a freaking nightmare.
384 _assert_no_error(result)
388 Sets up the ALPN protocols on the context.
392 protocols_arr = _create_cfstring_array(protocols)
395 _assert_no_error(result)
401 Called when we have set custom validation. We do this in two cases:
402 first, when cert validation is entirely disabled; and second, when
403 using a custom trust DB.
404 Raises an SSLError if the connection is not trusted.
416 if trust_result
in successes:
418 reason =
"error code: %d" % (trust_result,)
419 except Exception
as e:
421 reason =
"exception: %r" % (e,)
424 rec = _build_tls_unknown_ca_alert(self.
version())
432 raise ssl.SSLError(
"certificate verify failed, %s" % reason)
437 with open(trust_bundle,
"rb")
as f:
445 cert_array = _cert_array_from_pem(trust_bundle)
452 _assert_no_error(result)
457 _assert_no_error(result)
460 _assert_no_error(result)
464 _assert_no_error(result)
469 if cert_array
is not None:
483 client_key_passphrase,
487 Actually performs the TLS handshake. This is run automatically by
488 wrapped socket, and shouldn't be needed in user code.
496 self.
context, _read_callback_pointer, _write_callback_pointer
498 _assert_no_error(result)
503 with _connection_ref_lock:
504 handle = id(self) % 2147483647
505 while handle
in _connection_refs:
506 handle = (handle + 1) % 2147483647
507 _connection_refs[handle] = self
510 _assert_no_error(result)
518 self.
context, server_hostname,
len(server_hostname)
520 _assert_no_error(result)
530 _assert_no_error(result)
533 _assert_no_error(result)
539 if not verify
or trust_bundle
is not None:
543 _assert_no_error(result)
552 _assert_no_error(result)
564 _assert_no_error(result)
579 bytes_read = self.
recv_into(buffer, bufsiz)
580 data = buffer[:bytes_read]
620 _assert_no_error(result)
644 _assert_no_error(result)
651 while total_sent <
len(data):
652 sent = self.
send(data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE])
699 raise ValueError(
"SecureTransport only supports dumping binary certs")
707 _assert_no_error(result)
741 _assert_no_error(result)
743 raise ssl.SSLError(
"SecureTransport does not support TLS 1.3")
755 raise ssl.SSLError(
"Unknown TLS version: %r" % protocol)
770 self._makefile_refs += 1
771 return _fileobject(self, mode, bufsize, close=
True)
775 def makefile(self, mode="r", buffering=None, *args, **kwargs):
779 return backport_makefile(self, mode, buffering, *args, **kwargs)
787 I am a wrapper class for the SecureTransport library, to translate the
788 interface of the standard library ``SSLContext`` object to calls into
805 SecureTransport cannot have its hostname checking disabled. For more,
806 see the comment on getpeercert() in this file.
810 @check_hostname.setter
813 SecureTransport cannot have its hostname checking disabled. For more,
814 see the comment on getpeercert() in this file.
829 def options(self, value):
854 return self.set_default_verify_paths()
859 raise ValueError(
"SecureTransport doesn't support custom cipher strings")
863 if capath
is not None:
864 raise ValueError(
"SecureTransport does not support cert directories")
867 if cafile
is not None:
880 Sets the ALPN protocols that will later be set on the context.
882 Raises a NotImplementedError if ALPN is not supported.
884 if not hasattr(Security,
"SSLSetALPNProtocols"):
886 "SecureTransport supports ALPN only in macOS 10.12+"
894 do_handshake_on_connect=True,
895 suppress_ragged_eofs=True,
896 server_hostname=None,
901 assert not server_side
902 assert do_handshake_on_connect
903 assert suppress_ragged_eofs
921 return wrapped_socket
set_ciphers(self, ciphers)
set_default_verify_paths(self)
load_cert_chain(self, certfile, keyfile=None, password=None)
load_verify_locations(self, cafile=None, capath=None, cadata=None)
set_alpn_protocols(self, protocols)
_evaluate_trust(self, trust_bundle)
handshake(self, server_hostname, verify, trust_bundle, min_version, max_version, client_cert, client_key, client_key_passphrase, alpn_protocols)
recv_into(self, buffer, nbytes=None)
getpeercert(self, binary_form=False)
_custom_validate(self, verify, trust_bundle)
_set_alpn_protocols(self, protocols)
settimeout(self, timeout)
_read_callback(connection_id, data_buffer, data_length_pointer)
_write_callback(connection_id, data_buffer, data_length_pointer)