diff options
Diffstat (limited to 'venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/urllib3/contrib/securetransport.py')
-rw-r--r-- | venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/urllib3/contrib/securetransport.py | 810 |
1 files changed, 0 insertions, 810 deletions
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/urllib3/contrib/securetransport.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/urllib3/contrib/securetransport.py deleted file mode 100644 index 77cf861..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/urllib3/contrib/securetransport.py +++ /dev/null | |||
@@ -1,810 +0,0 @@ | |||
1 | """ | ||
2 | SecureTranport support for urllib3 via ctypes. | ||
3 | |||
4 | This makes platform-native TLS available to urllib3 users on macOS without the | ||
5 | use of a compiler. This is an important feature because the Python Package | ||
6 | Index is moving to become a TLSv1.2-or-higher server, and the default OpenSSL | ||
7 | that ships with macOS is not capable of doing TLSv1.2. The only way to resolve | ||
8 | this is to give macOS users an alternative solution to the problem, and that | ||
9 | solution is to use SecureTransport. | ||
10 | |||
11 | We use ctypes here because this solution must not require a compiler. That's | ||
12 | because pip is not allowed to require a compiler either. | ||
13 | |||
14 | This is not intended to be a seriously long-term solution to this problem. | ||
15 | The hope is that PEP 543 will eventually solve this issue for us, at which | ||
16 | point we can retire this contrib module. But in the short term, we need to | ||
17 | solve the impending tire fire that is Python on Mac without this kind of | ||
18 | contrib module. So...here we are. | ||
19 | |||
20 | To use this module, simply import and inject it:: | ||
21 | |||
22 | import urllib3.contrib.securetransport | ||
23 | urllib3.contrib.securetransport.inject_into_urllib3() | ||
24 | |||
25 | Happy TLSing! | ||
26 | """ | ||
27 | from __future__ import absolute_import | ||
28 | |||
29 | import contextlib | ||
30 | import ctypes | ||
31 | import errno | ||
32 | import os.path | ||
33 | import shutil | ||
34 | import socket | ||
35 | import ssl | ||
36 | import threading | ||
37 | import weakref | ||
38 | |||
39 | from .. import util | ||
40 | from ._securetransport.bindings import ( | ||
41 | Security, SecurityConst, CoreFoundation | ||
42 | ) | ||
43 | from ._securetransport.low_level import ( | ||
44 | _assert_no_error, _cert_array_from_pem, _temporary_keychain, | ||
45 | _load_client_cert_chain | ||
46 | ) | ||
47 | |||
48 | try: # Platform-specific: Python 2 | ||
49 | from socket import _fileobject | ||
50 | except ImportError: # Platform-specific: Python 3 | ||
51 | _fileobject = None | ||
52 | from ..packages.backports.makefile import backport_makefile | ||
53 | |||
54 | try: | ||
55 | memoryview(b'') | ||
56 | except NameError: | ||
57 | raise ImportError("SecureTransport only works on Pythons with memoryview") | ||
58 | |||
59 | __all__ = ['inject_into_urllib3', 'extract_from_urllib3'] | ||
60 | |||
61 | # SNI always works | ||
62 | HAS_SNI = True | ||
63 | |||
64 | orig_util_HAS_SNI = util.HAS_SNI | ||
65 | orig_util_SSLContext = util.ssl_.SSLContext | ||
66 | |||
67 | # This dictionary is used by the read callback to obtain a handle to the | ||
68 | # calling wrapped socket. This is a pretty silly approach, but for now it'll | ||
69 | # do. I feel like I should be able to smuggle a handle to the wrapped socket | ||
70 | # directly in the SSLConnectionRef, but for now this approach will work I | ||
71 | # guess. | ||
72 | # | ||
73 | # We need to lock around this structure for inserts, but we don't do it for | ||
74 | # reads/writes in the callbacks. The reasoning here goes as follows: | ||
75 | # | ||
76 | # 1. It is not possible to call into the callbacks before the dictionary is | ||
77 | # populated, so once in the callback the id must be in the dictionary. | ||
78 | # 2. The callbacks don't mutate the dictionary, they only read from it, and | ||
79 | # so cannot conflict with any of the insertions. | ||
80 | # | ||
81 | # This is good: if we had to lock in the callbacks we'd drastically slow down | ||
82 | # the performance of this code. | ||
83 | _connection_refs = weakref.WeakValueDictionary() | ||
84 | _connection_ref_lock = threading.Lock() | ||
85 | |||
86 | # Limit writes to 16kB. This is OpenSSL's limit, but we'll cargo-cult it over | ||
87 | # for no better reason than we need *a* limit, and this one is right there. | ||
88 | SSL_WRITE_BLOCKSIZE = 16384 | ||
89 | |||
90 | # This is our equivalent of util.ssl_.DEFAULT_CIPHERS, but expanded out to | ||
91 | # individual cipher suites. We need to do this becuase this is how | ||
92 | # SecureTransport wants them. | ||
93 | CIPHER_SUITES = [ | ||
94 | SecurityConst.TLS_AES_256_GCM_SHA384, | ||
95 | SecurityConst.TLS_CHACHA20_POLY1305_SHA256, | ||
96 | SecurityConst.TLS_AES_128_GCM_SHA256, | ||
97 | SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | ||
98 | SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
99 | SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | ||
100 | SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
101 | SecurityConst.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, | ||
102 | SecurityConst.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, | ||
103 | SecurityConst.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, | ||
104 | SecurityConst.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, | ||
105 | SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, | ||
106 | SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, | ||
107 | SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, | ||
108 | SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, | ||
109 | SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, | ||
110 | SecurityConst.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, | ||
111 | SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, | ||
112 | SecurityConst.TLS_DHE_DSS_WITH_AES_256_CBC_SHA, | ||
113 | SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, | ||
114 | SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, | ||
115 | SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, | ||
116 | SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, | ||
117 | SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, | ||
118 | SecurityConst.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, | ||
119 | SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, | ||
120 | SecurityConst.TLS_DHE_DSS_WITH_AES_128_CBC_SHA, | ||
121 | SecurityConst.TLS_RSA_WITH_AES_256_GCM_SHA384, | ||
122 | SecurityConst.TLS_RSA_WITH_AES_128_GCM_SHA256, | ||
123 | SecurityConst.TLS_RSA_WITH_AES_256_CBC_SHA256, | ||
124 | SecurityConst.TLS_RSA_WITH_AES_128_CBC_SHA256, | ||
125 | SecurityConst.TLS_RSA_WITH_AES_256_CBC_SHA, | ||
126 | SecurityConst.TLS_RSA_WITH_AES_128_CBC_SHA, | ||
127 | ] | ||
128 | |||
129 | # Basically this is simple: for PROTOCOL_SSLv23 we turn it into a low of | ||
130 | # TLSv1 and a high of TLSv1.2. For everything else, we pin to that version. | ||
131 | _protocol_to_min_max = { | ||
132 | ssl.PROTOCOL_SSLv23: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol12), | ||
133 | } | ||
134 | |||
135 | if hasattr(ssl, "PROTOCOL_SSLv2"): | ||
136 | _protocol_to_min_max[ssl.PROTOCOL_SSLv2] = ( | ||
137 | SecurityConst.kSSLProtocol2, SecurityConst.kSSLProtocol2 | ||
138 | ) | ||
139 | if hasattr(ssl, "PROTOCOL_SSLv3"): | ||
140 | _protocol_to_min_max[ssl.PROTOCOL_SSLv3] = ( | ||
141 | SecurityConst.kSSLProtocol3, SecurityConst.kSSLProtocol3 | ||
142 | ) | ||
143 | if hasattr(ssl, "PROTOCOL_TLSv1"): | ||
144 | _protocol_to_min_max[ssl.PROTOCOL_TLSv1] = ( | ||
145 | SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol1 | ||
146 | ) | ||
147 | if hasattr(ssl, "PROTOCOL_TLSv1_1"): | ||
148 | _protocol_to_min_max[ssl.PROTOCOL_TLSv1_1] = ( | ||
149 | SecurityConst.kTLSProtocol11, SecurityConst.kTLSProtocol11 | ||
150 | ) | ||
151 | if hasattr(ssl, "PROTOCOL_TLSv1_2"): | ||
152 | _protocol_to_min_max[ssl.PROTOCOL_TLSv1_2] = ( | ||
153 | SecurityConst.kTLSProtocol12, SecurityConst.kTLSProtocol12 | ||
154 | ) | ||
155 | if hasattr(ssl, "PROTOCOL_TLS"): | ||
156 | _protocol_to_min_max[ssl.PROTOCOL_TLS] = _protocol_to_min_max[ssl.PROTOCOL_SSLv23] | ||
157 | |||
158 | |||
159 | def inject_into_urllib3(): | ||
160 | """ | ||
161 | Monkey-patch urllib3 with SecureTransport-backed SSL-support. | ||
162 | """ | ||
163 | util.ssl_.SSLContext = SecureTransportContext | ||
164 | util.HAS_SNI = HAS_SNI | ||
165 | util.ssl_.HAS_SNI = HAS_SNI | ||
166 | util.IS_SECURETRANSPORT = True | ||
167 | util.ssl_.IS_SECURETRANSPORT = True | ||
168 | |||
169 | |||
170 | def extract_from_urllib3(): | ||
171 | """ | ||
172 | Undo monkey-patching by :func:`inject_into_urllib3`. | ||
173 | """ | ||
174 | util.ssl_.SSLContext = orig_util_SSLContext | ||
175 | util.HAS_SNI = orig_util_HAS_SNI | ||
176 | util.ssl_.HAS_SNI = orig_util_HAS_SNI | ||
177 | util.IS_SECURETRANSPORT = False | ||
178 | util.ssl_.IS_SECURETRANSPORT = False | ||
179 | |||
180 | |||
181 | def _read_callback(connection_id, data_buffer, data_length_pointer): | ||
182 | """ | ||
183 | SecureTransport read callback. This is called by ST to request that data | ||
184 | be returned from the socket. | ||
185 | """ | ||
186 | wrapped_socket = None | ||
187 | try: | ||
188 | wrapped_socket = _connection_refs.get(connection_id) | ||
189 | if wrapped_socket is None: | ||
190 | return SecurityConst.errSSLInternal | ||
191 | base_socket = wrapped_socket.socket | ||
192 | |||
193 | requested_length = data_length_pointer[0] | ||
194 | |||
195 | timeout = wrapped_socket.gettimeout() | ||
196 | error = None | ||
197 | read_count = 0 | ||
198 | buffer = (ctypes.c_char * requested_length).from_address(data_buffer) | ||
199 | buffer_view = memoryview(buffer) | ||
200 | |||
201 | try: | ||
202 | while read_count < requested_length: | ||
203 | if timeout is None or timeout >= 0: | ||
204 | readables = util.wait_for_read([base_socket], timeout) | ||
205 | if not readables: | ||
206 | raise socket.error(errno.EAGAIN, 'timed out') | ||
207 | |||
208 | # We need to tell ctypes that we have a buffer that can be | ||
209 | # written to. Upsettingly, we do that like this: | ||
210 | chunk_size = base_socket.recv_into( | ||
211 | buffer_view[read_count:requested_length] | ||
212 | ) | ||
213 | read_count += chunk_size | ||
214 | if not chunk_size: | ||
215 | if not read_count: | ||
216 | return SecurityConst.errSSLClosedGraceful | ||
217 | break | ||
218 | except (socket.error) as e: | ||
219 | error = e.errno | ||
220 | |||
221 | if error is not None and error != errno.EAGAIN: | ||
222 | if error == errno.ECONNRESET: | ||
223 | return SecurityConst.errSSLClosedAbort | ||
224 | raise | ||
225 | |||
226 | data_length_pointer[0] = read_count | ||
227 | |||
228 | if read_count != requested_length: | ||
229 | return SecurityConst.errSSLWouldBlock | ||
230 | |||
231 | return 0 | ||
232 | except Exception as e: | ||
233 | if wrapped_socket is not None: | ||
234 | wrapped_socket._exception = e | ||
235 | return SecurityConst.errSSLInternal | ||
236 | |||
237 | |||
238 | def _write_callback(connection_id, data_buffer, data_length_pointer): | ||
239 | """ | ||
240 | SecureTransport write callback. This is called by ST to request that data | ||
241 | actually be sent on the network. | ||
242 | """ | ||
243 | wrapped_socket = None | ||
244 | try: | ||
245 | wrapped_socket = _connection_refs.get(connection_id) | ||
246 | if wrapped_socket is None: | ||
247 | return SecurityConst.errSSLInternal | ||
248 | base_socket = wrapped_socket.socket | ||
249 | |||
250 | bytes_to_write = data_length_pointer[0] | ||
251 | data = ctypes.string_at(data_buffer, bytes_to_write) | ||
252 | |||
253 | timeout = wrapped_socket.gettimeout() | ||
254 | error = None | ||
255 | sent = 0 | ||
256 | |||
257 | try: | ||
258 | while sent < bytes_to_write: | ||
259 | if timeout is None or timeout >= 0: | ||
260 | writables = util.wait_for_write([base_socket], timeout) | ||
261 | if not writables: | ||
262 | raise socket.error(errno.EAGAIN, 'timed out') | ||
263 | chunk_sent = base_socket.send(data) | ||
264 | sent += chunk_sent | ||
265 | |||
266 | # This has some needless copying here, but I'm not sure there's | ||
267 | # much value in optimising this data path. | ||
268 | data = data[chunk_sent:] | ||
269 | except (socket.error) as e: | ||
270 | error = e.errno | ||
271 | |||
272 | if error is not None and error != errno.EAGAIN: | ||
273 | if error == errno.ECONNRESET: | ||
274 | return SecurityConst.errSSLClosedAbort | ||
275 | raise | ||
276 | |||
277 | data_length_pointer[0] = sent | ||
278 | if sent != bytes_to_write: | ||
279 | return SecurityConst.errSSLWouldBlock | ||
280 | |||
281 | return 0 | ||
282 | except Exception as e: | ||
283 | if wrapped_socket is not None: | ||
284 | wrapped_socket._exception = e | ||
285 | return SecurityConst.errSSLInternal | ||
286 | |||
287 | |||
288 | # We need to keep these two objects references alive: if they get GC'd while | ||
289 | # in use then SecureTransport could attempt to call a function that is in freed | ||
290 | # memory. That would be...uh...bad. Yeah, that's the word. Bad. | ||
291 | _read_callback_pointer = Security.SSLReadFunc(_read_callback) | ||
292 | _write_callback_pointer = Security.SSLWriteFunc(_write_callback) | ||
293 | |||
294 | |||
295 | class WrappedSocket(object): | ||
296 | """ | ||
297 | API-compatibility wrapper for Python's OpenSSL wrapped socket object. | ||
298 | |||
299 | Note: _makefile_refs, _drop(), and _reuse() are needed for the garbage | ||
300 | collector of PyPy. | ||
301 | """ | ||
302 | def __init__(self, socket): | ||
303 | self.socket = socket | ||
304 | self.context = None | ||
305 | self._makefile_refs = 0 | ||
306 | self._closed = False | ||
307 | self._exception = None | ||
308 | self._keychain = None | ||
309 | self._keychain_dir = None | ||
310 | self._client_cert_chain = None | ||
311 | |||
312 | # We save off the previously-configured timeout and then set it to | ||
313 | # zero. This is done because we use select and friends to handle the | ||
314 | # timeouts, but if we leave the timeout set on the lower socket then | ||
315 | # Python will "kindly" call select on that socket again for us. Avoid | ||
316 | # that by forcing the timeout to zero. | ||
317 | self._timeout = self.socket.gettimeout() | ||
318 | self.socket.settimeout(0) | ||
319 | |||
320 | @contextlib.contextmanager | ||
321 | def _raise_on_error(self): | ||
322 | """ | ||
323 | A context manager that can be used to wrap calls that do I/O from | ||
324 | SecureTransport. If any of the I/O callbacks hit an exception, this | ||
325 | context manager will correctly propagate the exception after the fact. | ||
326 | This avoids silently swallowing those exceptions. | ||
327 | |||
328 | It also correctly forces the socket closed. | ||
329 | """ | ||
330 | self._exception = None | ||
331 | |||
332 | # We explicitly don't catch around this yield because in the unlikely | ||
333 | # event that an exception was hit in the block we don't want to swallow | ||
334 | # it. | ||
335 | yield | ||
336 | if self._exception is not None: | ||
337 | exception, self._exception = self._exception, None | ||
338 | self.close() | ||
339 | raise exception | ||
340 | |||
341 | def _set_ciphers(self): | ||
342 | """ | ||
343 | Sets up the allowed ciphers. By default this matches the set in | ||
344 | util.ssl_.DEFAULT_CIPHERS, at least as supported by macOS. This is done | ||
345 | custom and doesn't allow changing at this time, mostly because parsing | ||
346 | OpenSSL cipher strings is going to be a freaking nightmare. | ||
347 | """ | ||
348 | ciphers = (Security.SSLCipherSuite * len(CIPHER_SUITES))(*CIPHER_SUITES) | ||
349 | result = Security.SSLSetEnabledCiphers( | ||
350 | self.context, ciphers, len(CIPHER_SUITES) | ||
351 | ) | ||
352 | _assert_no_error(result) | ||
353 | |||
354 | def _custom_validate(self, verify, trust_bundle): | ||
355 | """ | ||
356 | Called when we have set custom validation. We do this in two cases: | ||
357 | first, when cert validation is entirely disabled; and second, when | ||
358 | using a custom trust DB. | ||
359 | """ | ||
360 | # If we disabled cert validation, just say: cool. | ||
361 | if not verify: | ||
362 | return | ||
363 | |||
364 | # We want data in memory, so load it up. | ||
365 | if os.path.isfile(trust_bundle): | ||
366 | with open(trust_bundle, 'rb') as f: | ||
367 | trust_bundle = f.read() | ||
368 | |||
369 | cert_array = None | ||
370 | trust = Security.SecTrustRef() | ||
371 | |||
372 | try: | ||
373 | # Get a CFArray that contains the certs we want. | ||
374 | cert_array = _cert_array_from_pem(trust_bundle) | ||
375 | |||
376 | # Ok, now the hard part. We want to get the SecTrustRef that ST has | ||
377 | # created for this connection, shove our CAs into it, tell ST to | ||
378 | # ignore everything else it knows, and then ask if it can build a | ||
379 | # chain. This is a buuuunch of code. | ||
380 | result = Security.SSLCopyPeerTrust( | ||
381 | self.context, ctypes.byref(trust) | ||
382 | ) | ||
383 | _assert_no_error(result) | ||
384 | if not trust: | ||
385 | raise ssl.SSLError("Failed to copy trust reference") | ||
386 | |||
387 | result = Security.SecTrustSetAnchorCertificates(trust, cert_array) | ||
388 | _assert_no_error(result) | ||
389 | |||
390 | result = Security.SecTrustSetAnchorCertificatesOnly(trust, True) | ||
391 | _assert_no_error(result) | ||
392 | |||
393 | trust_result = Security.SecTrustResultType() | ||
394 | result = Security.SecTrustEvaluate( | ||
395 | trust, ctypes.byref(trust_result) | ||
396 | ) | ||
397 | _assert_no_error(result) | ||
398 | finally: | ||
399 | if trust: | ||
400 | CoreFoundation.CFRelease(trust) | ||
401 | |||
402 | if cert_array is None: | ||
403 | CoreFoundation.CFRelease(cert_array) | ||
404 | |||
405 | # Ok, now we can look at what the result was. | ||
406 | successes = ( | ||
407 | SecurityConst.kSecTrustResultUnspecified, | ||
408 | SecurityConst.kSecTrustResultProceed | ||
409 | ) | ||
410 | if trust_result.value not in successes: | ||
411 | raise ssl.SSLError( | ||
412 | "certificate verify failed, error code: %d" % | ||
413 | trust_result.value | ||
414 | ) | ||
415 | |||
416 | def handshake(self, | ||
417 | server_hostname, | ||
418 | verify, | ||
419 | trust_bundle, | ||
420 | min_version, | ||
421 | max_version, | ||
422 | client_cert, | ||
423 | client_key, | ||
424 | client_key_passphrase): | ||
425 | """ | ||
426 | Actually performs the TLS handshake. This is run automatically by | ||
427 | wrapped socket, and shouldn't be needed in user code. | ||
428 | """ | ||
429 | # First, we do the initial bits of connection setup. We need to create | ||
430 | # a context, set its I/O funcs, and set the connection reference. | ||
431 | self.context = Security.SSLCreateContext( | ||
432 | None, SecurityConst.kSSLClientSide, SecurityConst.kSSLStreamType | ||
433 | ) | ||
434 | result = Security.SSLSetIOFuncs( | ||
435 | self.context, _read_callback_pointer, _write_callback_pointer | ||
436 | ) | ||
437 | _assert_no_error(result) | ||
438 | |||
439 | # Here we need to compute the handle to use. We do this by taking the | ||
440 | # id of self modulo 2**31 - 1. If this is already in the dictionary, we | ||
441 | # just keep incrementing by one until we find a free space. | ||
442 | with _connection_ref_lock: | ||
443 | handle = id(self) % 2147483647 | ||
444 | while handle in _connection_refs: | ||
445 | handle = (handle + 1) % 2147483647 | ||
446 | _connection_refs[handle] = self | ||
447 | |||
448 | result = Security.SSLSetConnection(self.context, handle) | ||
449 | _assert_no_error(result) | ||
450 | |||
451 | # If we have a server hostname, we should set that too. | ||
452 | if server_hostname: | ||
453 | if not isinstance(server_hostname, bytes): | ||
454 | server_hostname = server_hostname.encode('utf-8') | ||
455 | |||
456 | result = Security.SSLSetPeerDomainName( | ||
457 | self.context, server_hostname, len(server_hostname) | ||
458 | ) | ||
459 | _assert_no_error(result) | ||
460 | |||
461 | # Setup the ciphers. | ||
462 | self._set_ciphers() | ||
463 | |||
464 | # Set the minimum and maximum TLS versions. | ||
465 | result = Security.SSLSetProtocolVersionMin(self.context, min_version) | ||
466 | _assert_no_error(result) | ||
467 | result = Security.SSLSetProtocolVersionMax(self.context, max_version) | ||
468 | _assert_no_error(result) | ||
469 | |||
470 | # If there's a trust DB, we need to use it. We do that by telling | ||
471 | # SecureTransport to break on server auth. We also do that if we don't | ||
472 | # want to validate the certs at all: we just won't actually do any | ||
473 | # authing in that case. | ||
474 | if not verify or trust_bundle is not None: | ||
475 | result = Security.SSLSetSessionOption( | ||
476 | self.context, | ||
477 | SecurityConst.kSSLSessionOptionBreakOnServerAuth, | ||
478 | True | ||
479 | ) | ||
480 | _assert_no_error(result) | ||
481 | |||
482 | # If there's a client cert, we need to use it. | ||
483 | if client_cert: | ||
484 | self._keychain, self._keychain_dir = _temporary_keychain() | ||
485 | self._client_cert_chain = _load_client_cert_chain( | ||
486 | self._keychain, client_cert, client_key | ||
487 | ) | ||
488 | result = Security.SSLSetCertificate( | ||
489 | self.context, self._client_cert_chain | ||
490 | ) | ||
491 | _assert_no_error(result) | ||
492 | |||
493 | while True: | ||
494 | with self._raise_on_error(): | ||
495 | result = Security.SSLHandshake(self.context) | ||
496 | |||
497 | if result == SecurityConst.errSSLWouldBlock: | ||
498 | raise socket.timeout("handshake timed out") | ||
499 | elif result == SecurityConst.errSSLServerAuthCompleted: | ||
500 | self._custom_validate(verify, trust_bundle) | ||
501 | continue | ||
502 | else: | ||
503 | _assert_no_error(result) | ||
504 | break | ||
505 | |||
506 | def fileno(self): | ||
507 | return self.socket.fileno() | ||
508 | |||
509 | # Copy-pasted from Python 3.5 source code | ||
510 | def _decref_socketios(self): | ||
511 | if self._makefile_refs > 0: | ||
512 | self._makefile_refs -= 1 | ||
513 | if self._closed: | ||
514 | self.close() | ||
515 | |||
516 | def recv(self, bufsiz): | ||
517 | buffer = ctypes.create_string_buffer(bufsiz) | ||
518 | bytes_read = self.recv_into(buffer, bufsiz) | ||
519 | data = buffer[:bytes_read] | ||
520 | return data | ||
521 | |||
522 | def recv_into(self, buffer, nbytes=None): | ||
523 | # Read short on EOF. | ||
524 | if self._closed: | ||
525 | return 0 | ||
526 | |||
527 | if nbytes is None: | ||
528 | nbytes = len(buffer) | ||
529 | |||
530 | buffer = (ctypes.c_char * nbytes).from_buffer(buffer) | ||
531 | processed_bytes = ctypes.c_size_t(0) | ||
532 | |||
533 | with self._raise_on_error(): | ||
534 | result = Security.SSLRead( | ||
535 | self.context, buffer, nbytes, ctypes.byref(processed_bytes) | ||
536 | ) | ||
537 | |||
538 | # There are some result codes that we want to treat as "not always | ||
539 | # errors". Specifically, those are errSSLWouldBlock, | ||
540 | # errSSLClosedGraceful, and errSSLClosedNoNotify. | ||
541 | if (result == SecurityConst.errSSLWouldBlock): | ||
542 | # If we didn't process any bytes, then this was just a time out. | ||
543 | # However, we can get errSSLWouldBlock in situations when we *did* | ||
544 | # read some data, and in those cases we should just read "short" | ||
545 | # and return. | ||
546 | if processed_bytes.value == 0: | ||
547 | # Timed out, no data read. | ||
548 | raise socket.timeout("recv timed out") | ||
549 | elif result in (SecurityConst.errSSLClosedGraceful, SecurityConst.errSSLClosedNoNotify): | ||
550 | # The remote peer has closed this connection. We should do so as | ||
551 | # well. Note that we don't actually return here because in | ||
552 | # principle this could actually be fired along with return data. | ||
553 | # It's unlikely though. | ||
554 | self.close() | ||
555 | else: | ||
556 | _assert_no_error(result) | ||
557 | |||
558 | # Ok, we read and probably succeeded. We should return whatever data | ||
559 | # was actually read. | ||
560 | return processed_bytes.value | ||
561 | |||
562 | def settimeout(self, timeout): | ||
563 | self._timeout = timeout | ||
564 | |||
565 | def gettimeout(self): | ||
566 | return self._timeout | ||
567 | |||
568 | def send(self, data): | ||
569 | processed_bytes = ctypes.c_size_t(0) | ||
570 | |||
571 | with self._raise_on_error(): | ||
572 | result = Security.SSLWrite( | ||
573 | self.context, data, len(data), ctypes.byref(processed_bytes) | ||
574 | ) | ||
575 | |||
576 | if result == SecurityConst.errSSLWouldBlock and processed_bytes.value == 0: | ||
577 | # Timed out | ||
578 | raise socket.timeout("send timed out") | ||
579 | else: | ||
580 | _assert_no_error(result) | ||
581 | |||
582 | # We sent, and probably succeeded. Tell them how much we sent. | ||
583 | return processed_bytes.value | ||
584 | |||
585 | def sendall(self, data): | ||
586 | total_sent = 0 | ||
587 | while total_sent < len(data): | ||
588 | sent = self.send(data[total_sent:total_sent + SSL_WRITE_BLOCKSIZE]) | ||
589 | total_sent += sent | ||
590 | |||
591 | def shutdown(self): | ||
592 | with self._raise_on_error(): | ||
593 | Security.SSLClose(self.context) | ||
594 | |||
595 | def close(self): | ||
596 | # TODO: should I do clean shutdown here? Do I have to? | ||
597 | if self._makefile_refs < 1: | ||
598 | self._closed = True | ||
599 | if self.context: | ||
600 | CoreFoundation.CFRelease(self.context) | ||
601 | self.context = None | ||
602 | if self._client_cert_chain: | ||
603 | CoreFoundation.CFRelease(self._client_cert_chain) | ||
604 | self._client_cert_chain = None | ||
605 | if self._keychain: | ||
606 | Security.SecKeychainDelete(self._keychain) | ||
607 | CoreFoundation.CFRelease(self._keychain) | ||
608 | shutil.rmtree(self._keychain_dir) | ||
609 | self._keychain = self._keychain_dir = None | ||
610 | return self.socket.close() | ||
611 | else: | ||
612 | self._makefile_refs -= 1 | ||
613 | |||
614 | def getpeercert(self, binary_form=False): | ||
615 | # Urgh, annoying. | ||
616 | # | ||
617 | # Here's how we do this: | ||
618 | # | ||
619 | # 1. Call SSLCopyPeerTrust to get hold of the trust object for this | ||
620 | # connection. | ||
621 | # 2. Call SecTrustGetCertificateAtIndex for index 0 to get the leaf. | ||
622 | # 3. To get the CN, call SecCertificateCopyCommonName and process that | ||
623 | # string so that it's of the appropriate type. | ||
624 | # 4. To get the SAN, we need to do something a bit more complex: | ||
625 | # a. Call SecCertificateCopyValues to get the data, requesting | ||
626 | # kSecOIDSubjectAltName. | ||
627 | # b. Mess about with this dictionary to try to get the SANs out. | ||
628 | # | ||
629 | # This is gross. Really gross. It's going to be a few hundred LoC extra | ||
630 | # just to repeat something that SecureTransport can *already do*. So my | ||
631 | # operating assumption at this time is that what we want to do is | ||
632 | # instead to just flag to urllib3 that it shouldn't do its own hostname | ||
633 | # validation when using SecureTransport. | ||
634 | if not binary_form: | ||
635 | raise ValueError( | ||
636 | "SecureTransport only supports dumping binary certs" | ||
637 | ) | ||
638 | trust = Security.SecTrustRef() | ||
639 | certdata = None | ||
640 | der_bytes = None | ||
641 | |||
642 | try: | ||
643 | # Grab the trust store. | ||
644 | result = Security.SSLCopyPeerTrust( | ||
645 | self.context, ctypes.byref(trust) | ||
646 | ) | ||
647 | _assert_no_error(result) | ||
648 | if not trust: | ||
649 | # Probably we haven't done the handshake yet. No biggie. | ||
650 | return None | ||
651 | |||
652 | cert_count = Security.SecTrustGetCertificateCount(trust) | ||
653 | if not cert_count: | ||
654 | # Also a case that might happen if we haven't handshaked. | ||
655 | # Handshook? Handshaken? | ||
656 | return None | ||
657 | |||
658 | leaf = Security.SecTrustGetCertificateAtIndex(trust, 0) | ||
659 | assert leaf | ||
660 | |||
661 | # Ok, now we want the DER bytes. | ||
662 | certdata = Security.SecCertificateCopyData(leaf) | ||
663 | assert certdata | ||
664 | |||
665 | data_length = CoreFoundation.CFDataGetLength(certdata) | ||
666 | data_buffer = CoreFoundation.CFDataGetBytePtr(certdata) | ||
667 | der_bytes = ctypes.string_at(data_buffer, data_length) | ||
668 | finally: | ||
669 | if certdata: | ||
670 | CoreFoundation.CFRelease(certdata) | ||
671 | if trust: | ||
672 | CoreFoundation.CFRelease(trust) | ||
673 | |||
674 | return der_bytes | ||
675 | |||
676 | def _reuse(self): | ||
677 | self._makefile_refs += 1 | ||
678 | |||
679 | def _drop(self): | ||
680 | if self._makefile_refs < 1: | ||
681 | self.close() | ||
682 | else: | ||
683 | self._makefile_refs -= 1 | ||
684 | |||
685 | |||
686 | if _fileobject: # Platform-specific: Python 2 | ||
687 | def makefile(self, mode, bufsize=-1): | ||
688 | self._makefile_refs += 1 | ||
689 | return _fileobject(self, mode, bufsize, close=True) | ||
690 | else: # Platform-specific: Python 3 | ||
691 | def makefile(self, mode="r", buffering=None, *args, **kwargs): | ||
692 | # We disable buffering with SecureTransport because it conflicts with | ||
693 | # the buffering that ST does internally (see issue #1153 for more). | ||
694 | buffering = 0 | ||
695 | return backport_makefile(self, mode, buffering, *args, **kwargs) | ||
696 | |||
697 | WrappedSocket.makefile = makefile | ||
698 | |||
699 | |||
700 | class SecureTransportContext(object): | ||
701 | """ | ||
702 | I am a wrapper class for the SecureTransport library, to translate the | ||
703 | interface of the standard library ``SSLContext`` object to calls into | ||
704 | SecureTransport. | ||
705 | """ | ||
706 | def __init__(self, protocol): | ||
707 | self._min_version, self._max_version = _protocol_to_min_max[protocol] | ||
708 | self._options = 0 | ||
709 | self._verify = False | ||
710 | self._trust_bundle = None | ||
711 | self._client_cert = None | ||
712 | self._client_key = None | ||
713 | self._client_key_passphrase = None | ||
714 | |||
715 | @property | ||
716 | def check_hostname(self): | ||
717 | """ | ||
718 | SecureTransport cannot have its hostname checking disabled. For more, | ||
719 | see the comment on getpeercert() in this file. | ||
720 | """ | ||
721 | return True | ||
722 | |||
723 | @check_hostname.setter | ||
724 | def check_hostname(self, value): | ||
725 | """ | ||
726 | SecureTransport cannot have its hostname checking disabled. For more, | ||
727 | see the comment on getpeercert() in this file. | ||
728 | """ | ||
729 | pass | ||
730 | |||
731 | @property | ||
732 | def options(self): | ||
733 | # TODO: Well, crap. | ||
734 | # | ||
735 | # So this is the bit of the code that is the most likely to cause us | ||
736 | # trouble. Essentially we need to enumerate all of the SSL options that | ||
737 | # users might want to use and try to see if we can sensibly translate | ||
738 | # them, or whether we should just ignore them. | ||
739 | return self._options | ||
740 | |||
741 | @options.setter | ||
742 | def options(self, value): | ||
743 | # TODO: Update in line with above. | ||
744 | self._options = value | ||
745 | |||
746 | @property | ||
747 | def verify_mode(self): | ||
748 | return ssl.CERT_REQUIRED if self._verify else ssl.CERT_NONE | ||
749 | |||
750 | @verify_mode.setter | ||
751 | def verify_mode(self, value): | ||
752 | self._verify = True if value == ssl.CERT_REQUIRED else False | ||
753 | |||
754 | def set_default_verify_paths(self): | ||
755 | # So, this has to do something a bit weird. Specifically, what it does | ||
756 | # is nothing. | ||
757 | # | ||
758 | # This means that, if we had previously had load_verify_locations | ||
759 | # called, this does not undo that. We need to do that because it turns | ||
760 | # out that the rest of the urllib3 code will attempt to load the | ||
761 | # default verify paths if it hasn't been told about any paths, even if | ||
762 | # the context itself was sometime earlier. We resolve that by just | ||
763 | # ignoring it. | ||
764 | pass | ||
765 | |||
766 | def load_default_certs(self): | ||
767 | return self.set_default_verify_paths() | ||
768 | |||
769 | def set_ciphers(self, ciphers): | ||
770 | # For now, we just require the default cipher string. | ||
771 | if ciphers != util.ssl_.DEFAULT_CIPHERS: | ||
772 | raise ValueError( | ||
773 | "SecureTransport doesn't support custom cipher strings" | ||
774 | ) | ||
775 | |||
776 | def load_verify_locations(self, cafile=None, capath=None, cadata=None): | ||
777 | # OK, we only really support cadata and cafile. | ||
778 | if capath is not None: | ||
779 | raise ValueError( | ||
780 | "SecureTransport does not support cert directories" | ||
781 | ) | ||
782 | |||
783 | self._trust_bundle = cafile or cadata | ||
784 | |||
785 | def load_cert_chain(self, certfile, keyfile=None, password=None): | ||
786 | self._client_cert = certfile | ||
787 | self._client_key = keyfile | ||
788 | self._client_cert_passphrase = password | ||
789 | |||
790 | def wrap_socket(self, sock, server_side=False, | ||
791 | do_handshake_on_connect=True, suppress_ragged_eofs=True, | ||
792 | server_hostname=None): | ||
793 | # So, what do we do here? Firstly, we assert some properties. This is a | ||
794 | # stripped down shim, so there is some functionality we don't support. | ||
795 | # See PEP 543 for the real deal. | ||
796 | assert not server_side | ||
797 | assert do_handshake_on_connect | ||
798 | assert suppress_ragged_eofs | ||
799 | |||
800 | # Ok, we're good to go. Now we want to create the wrapped socket object | ||
801 | # and store it in the appropriate place. | ||
802 | wrapped_socket = WrappedSocket(sock) | ||
803 | |||
804 | # Now we can handshake | ||
805 | wrapped_socket.handshake( | ||
806 | server_hostname, self._verify, self._trust_bundle, | ||
807 | self._min_version, self._max_version, self._client_cert, | ||
808 | self._client_key, self._client_key_passphrase | ||
809 | ) | ||
810 | return wrapped_socket | ||