summaryrefslogtreecommitdiff
path: root/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/urllib3/contrib/securetransport.py
diff options
context:
space:
mode:
authorShubham Saini <shubham6405@gmail.com>2018-12-11 10:01:23 +0000
committerShubham Saini <shubham6405@gmail.com>2018-12-11 10:01:23 +0000
commit68df54d6629ec019142eb149dd037774f2d11e7c (patch)
tree345bc22d46b4e01a4ba8303b94278952a4ed2b9e /venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/urllib3/contrib/securetransport.py
First commit
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.py810
1 files changed, 810 insertions, 0 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
new file mode 100644
index 0000000..77cf861
--- /dev/null
+++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/urllib3/contrib/securetransport.py
@@ -0,0 +1,810 @@
1"""
2SecureTranport support for urllib3 via ctypes.
3
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.
10
11We use ctypes here because this solution must not require a compiler. That's
12because pip is not allowed to require a compiler either.
13
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.
19
20To use this module, simply import and inject it::
21
22 import urllib3.contrib.securetransport
23 urllib3.contrib.securetransport.inject_into_urllib3()
24
25Happy TLSing!
26"""
27from __future__ import absolute_import
28
29import contextlib
30import ctypes
31import errno
32import os.path
33import shutil
34import socket
35import ssl
36import threading
37import weakref
38
39from .. import util
40from ._securetransport.bindings import (
41 Security, SecurityConst, CoreFoundation
42)
43from ._securetransport.low_level import (
44 _assert_no_error, _cert_array_from_pem, _temporary_keychain,
45 _load_client_cert_chain
46)
47
48try: # Platform-specific: Python 2
49 from socket import _fileobject
50except ImportError: # Platform-specific: Python 3
51 _fileobject = None
52 from ..packages.backports.makefile import backport_makefile
53
54try:
55 memoryview(b'')
56except 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
62HAS_SNI = True
63
64orig_util_HAS_SNI = util.HAS_SNI
65orig_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.
88SSL_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.
93CIPHER_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
135if hasattr(ssl, "PROTOCOL_SSLv2"):
136 _protocol_to_min_max[ssl.PROTOCOL_SSLv2] = (
137 SecurityConst.kSSLProtocol2, SecurityConst.kSSLProtocol2
138 )
139if hasattr(ssl, "PROTOCOL_SSLv3"):
140 _protocol_to_min_max[ssl.PROTOCOL_SSLv3] = (
141 SecurityConst.kSSLProtocol3, SecurityConst.kSSLProtocol3
142 )
143if hasattr(ssl, "PROTOCOL_TLSv1"):
144 _protocol_to_min_max[ssl.PROTOCOL_TLSv1] = (
145 SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol1
146 )
147if hasattr(ssl, "PROTOCOL_TLSv1_1"):
148 _protocol_to_min_max[ssl.PROTOCOL_TLSv1_1] = (
149 SecurityConst.kTLSProtocol11, SecurityConst.kTLSProtocol11
150 )
151if hasattr(ssl, "PROTOCOL_TLSv1_2"):
152 _protocol_to_min_max[ssl.PROTOCOL_TLSv1_2] = (
153 SecurityConst.kTLSProtocol12, SecurityConst.kTLSProtocol12
154 )
155if hasattr(ssl, "PROTOCOL_TLS"):
156 _protocol_to_min_max[ssl.PROTOCOL_TLS] = _protocol_to_min_max[ssl.PROTOCOL_SSLv23]
157
158
159def 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
170def 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
181def _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
238def _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
295class 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
686if _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)
690else: # 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
697WrappedSocket.makefile = makefile
698
699
700class 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