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