2 SecureTranport support for urllib3 via ctypes.
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.
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.
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.
20 To use this module, simply import and inject it::
22 import pip._vendor.urllib3.contrib.securetransport as securetransport
23 securetransport.inject_into_urllib3()
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:
34 Copyright (c) 2015-2016 Will Bond <will@wbond.net>
36 Permission is hereby granted, free of charge, to any person obtaining a
37 copy of this software and associated documentation files (the "Software"),
38 to deal in the Software without restriction, including without limitation
39 the rights to use, copy, modify, merge, publish, distribute, sublicense,
40 and/or sell copies of the Software, and to permit persons to whom the
41 Software is furnished to do so, subject to the following conditions:
43 The above copyright notice and this permission notice shall be included in
44 all copies or substantial portions of the Software.
46 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
51 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
52 DEALINGS IN THE SOFTWARE.
54 from __future__
import absolute_import
67 from pip
._vendor
import six
70 from ..util
.ssl_
import PROTOCOL_TLS_CLIENT
71 from ._securetransport
.bindings
import CoreFoundation
, Security
, SecurityConst
72 from ._securetransport
.low_level
import (
74 _build_tls_unknown_ca_alert
,
76 _create_cfstring_array
,
77 _load_client_cert_chain
,
81 try: # Platform-specific: Python 2
82 from socket
import _fileobject
83 except ImportError: # Platform-specific: Python 3
85 from ..packages
.backports
.makefile
import backport_makefile
87 __all__
= ["inject_into_urllib3", "extract_from_urllib3"]
92 orig_util_HAS_SNI
= util
.HAS_SNI
93 orig_util_SSLContext
= util
.ssl_
.SSLContext
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
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:
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.
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()
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
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.
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
,
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
),
162 if hasattr(ssl
, "PROTOCOL_SSLv2"):
163 _protocol_to_min_max
[ssl
.PROTOCOL_SSLv2
] = (
164 SecurityConst
.kSSLProtocol2
,
165 SecurityConst
.kSSLProtocol2
,
167 if hasattr(ssl
, "PROTOCOL_SSLv3"):
168 _protocol_to_min_max
[ssl
.PROTOCOL_SSLv3
] = (
169 SecurityConst
.kSSLProtocol3
,
170 SecurityConst
.kSSLProtocol3
,
172 if hasattr(ssl
, "PROTOCOL_TLSv1"):
173 _protocol_to_min_max
[ssl
.PROTOCOL_TLSv1
] = (
174 SecurityConst
.kTLSProtocol1
,
175 SecurityConst
.kTLSProtocol1
,
177 if hasattr(ssl
, "PROTOCOL_TLSv1_1"):
178 _protocol_to_min_max
[ssl
.PROTOCOL_TLSv1_1
] = (
179 SecurityConst
.kTLSProtocol11
,
180 SecurityConst
.kTLSProtocol11
,
182 if hasattr(ssl
, "PROTOCOL_TLSv1_2"):
183 _protocol_to_min_max
[ssl
.PROTOCOL_TLSv1_2
] = (
184 SecurityConst
.kTLSProtocol12
,
185 SecurityConst
.kTLSProtocol12
,
189 def inject_into_urllib3():
191 Monkey-patch urllib3 with SecureTransport-backed SSL-support.
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
201 def extract_from_urllib3():
203 Undo monkey-patching by :func:`inject_into_urllib3`.
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
213 def _read_callback(connection_id
, data_buffer
, data_length_pointer
):
215 SecureTransport read callback. This is called by ST to request that data
216 be returned from the socket.
218 wrapped_socket
= None
220 wrapped_socket
= _connection_refs
.get(connection_id
)
221 if wrapped_socket
is None:
222 return SecurityConst
.errSSLInternal
223 base_socket
= wrapped_socket
.socket
225 requested_length
= data_length_pointer
[0]
227 timeout
= wrapped_socket
.gettimeout()
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")
237 remaining
= requested_length
- read_count
238 buffer = (ctypes
.c_char
* remaining
).from_address(
239 data_buffer
+ read_count
241 chunk_size
= base_socket
.recv_into(buffer, remaining
)
242 read_count
+= chunk_size
245 return SecurityConst
.errSSLClosedGraceful
247 except (socket
.error
) as e
:
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
256 data_length_pointer
[0] = read_count
258 if read_count
!= requested_length
:
259 return SecurityConst
.errSSLWouldBlock
262 except Exception as e
:
263 if wrapped_socket
is not None:
264 wrapped_socket
._exception
= e
265 return SecurityConst
.errSSLInternal
268 def _write_callback(connection_id
, data_buffer
, data_length_pointer
):
270 SecureTransport write callback. This is called by ST to request that data
271 actually be sent on the network.
273 wrapped_socket
= None
275 wrapped_socket
= _connection_refs
.get(connection_id
)
276 if wrapped_socket
is None:
277 return SecurityConst
.errSSLInternal
278 base_socket
= wrapped_socket
.socket
280 bytes_to_write
= data_length_pointer
[0]
281 data
= ctypes
.string_at(data_buffer
, bytes_to_write
)
283 timeout
= wrapped_socket
.gettimeout()
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
)
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
:
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
307 data_length_pointer
[0] = sent
309 if sent
!= bytes_to_write
:
310 return SecurityConst
.errSSLWouldBlock
313 except Exception as e
:
314 if wrapped_socket
is not None:
315 wrapped_socket
._exception
= e
316 return SecurityConst
.errSSLInternal
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
)
326 class WrappedSocket(object):
328 API-compatibility wrapper for Python's OpenSSL wrapped socket object.
330 Note: _makefile_refs, _drop(), and _reuse() are needed for the garbage
334 def __init__(self
, socket
):
337 self
._makefile
_refs
= 0
339 self
._exception
= None
340 self
._keychain
= None
341 self
._keychain
_dir
= None
342 self
._client
_cert
_chain
= None
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)
352 @contextlib.contextmanager
353 def _raise_on_error(self
):
355 A context manager that can be used to wrap calls that do I/O from
356 SecureTransport. If any of the I/O callbacks hit an exception, this
357 context manager will correctly propagate the exception after the fact.
358 This avoids silently swallowing those exceptions.
360 It also correctly forces the socket closed.
362 self
._exception
= None
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
368 if self
._exception
is not None:
369 exception
, self
._exception
= self
._exception
, None
373 def _set_ciphers(self
):
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.
380 ciphers
= (Security
.SSLCipherSuite
* len(CIPHER_SUITES
))(*CIPHER_SUITES
)
381 result
= Security
.SSLSetEnabledCiphers(
382 self
.context
, ciphers
, len(CIPHER_SUITES
)
384 _assert_no_error(result
)
386 def _set_alpn_protocols(self
, protocols
):
388 Sets up the ALPN protocols on the context.
392 protocols_arr
= _create_cfstring_array(protocols
)
394 result
= Security
.SSLSetALPNProtocols(self
.context
, protocols_arr
)
395 _assert_no_error(result
)
397 CoreFoundation
.CFRelease(protocols_arr
)
399 def _custom_validate(self
, verify
, trust_bundle
):
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.
406 # If we disabled cert validation, just say: cool.
411 SecurityConst
.kSecTrustResultUnspecified
,
412 SecurityConst
.kSecTrustResultProceed
,
415 trust_result
= self
._evaluate
_trust
(trust_bundle
)
416 if trust_result
in successes
:
418 reason
= "error code: %d" % (trust_result
,)
419 except Exception as e
:
420 # Do not trust on error
421 reason
= "exception: %r" % (e
,)
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
)
432 raise ssl
.SSLError("certificate verify failed, %s" % reason
)
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()
441 trust
= Security
.SecTrustRef()
444 # Get a CFArray that contains the certs we want.
445 cert_array
= _cert_array_from_pem(trust_bundle
)
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
)
454 raise ssl
.SSLError("Failed to copy trust reference")
456 result
= Security
.SecTrustSetAnchorCertificates(trust
, cert_array
)
457 _assert_no_error(result
)
459 result
= Security
.SecTrustSetAnchorCertificatesOnly(trust
, True)
460 _assert_no_error(result
)
462 trust_result
= Security
.SecTrustResultType()
463 result
= Security
.SecTrustEvaluate(trust
, ctypes
.byref(trust_result
))
464 _assert_no_error(result
)
467 CoreFoundation
.CFRelease(trust
)
469 if cert_array
is not None:
470 CoreFoundation
.CFRelease(cert_array
)
472 return trust_result
.value
483 client_key_passphrase
,
487 Actually performs the TLS handshake. This is run automatically by
488 wrapped socket, and shouldn't be needed in user code.
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
495 result
= Security
.SSLSetIOFuncs(
496 self
.context
, _read_callback_pointer
, _write_callback_pointer
498 _assert_no_error(result
)
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
509 result
= Security
.SSLSetConnection(self
.context
, handle
)
510 _assert_no_error(result
)
512 # If we have a server hostname, we should set that too.
514 if not isinstance(server_hostname
, bytes):
515 server_hostname
= server_hostname
.encode("utf-8")
517 result
= Security
.SSLSetPeerDomainName(
518 self
.context
, server_hostname
, len(server_hostname
)
520 _assert_no_error(result
)
525 # Setup the ALPN protocols.
526 self
._set
_alpn
_protocols
(alpn_protocols
)
528 # Set the minimum and maximum TLS versions.
529 result
= Security
.SSLSetProtocolVersionMin(self
.context
, min_version
)
530 _assert_no_error(result
)
532 result
= Security
.SSLSetProtocolVersionMax(self
.context
, max_version
)
533 _assert_no_error(result
)
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
543 _assert_no_error(result
)
545 # If there's a client cert, we need to use it.
547 self
._keychain
, self
._keychain
_dir
= _temporary_keychain()
548 self
._client
_cert
_chain
= _load_client_cert_chain(
549 self
._keychain
, client_cert
, client_key
551 result
= Security
.SSLSetCertificate(self
.context
, self
._client
_cert
_chain
)
552 _assert_no_error(result
)
555 with self
._raise
_on
_error
():
556 result
= Security
.SSLHandshake(self
.context
)
558 if result
== SecurityConst
.errSSLWouldBlock
:
559 raise socket
.timeout("handshake timed out")
560 elif result
== SecurityConst
.errSSLServerAuthCompleted
:
561 self
._custom
_validate
(verify
, trust_bundle
)
564 _assert_no_error(result
)
568 return self
.socket
.fileno()
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
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
]
583 def recv_into(self
, buffer, nbytes
=None):
591 buffer = (ctypes
.c_char
* nbytes
).from_buffer(buffer)
592 processed_bytes
= ctypes
.c_size_t(0)
594 with self
._raise
_on
_error
():
595 result
= Security
.SSLRead(
596 self
.context
, buffer, nbytes
, ctypes
.byref(processed_bytes
)
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"
607 if processed_bytes
.value
== 0:
608 # Timed out, no data read.
609 raise socket
.timeout("recv timed out")
611 SecurityConst
.errSSLClosedGraceful
,
612 SecurityConst
.errSSLClosedNoNotify
,
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.
620 _assert_no_error(result
)
622 # Ok, we read and probably succeeded. We should return whatever data
624 return processed_bytes
.value
626 def settimeout(self
, timeout
):
627 self
._timeout
= timeout
629 def gettimeout(self
):
632 def send(self
, data
):
633 processed_bytes
= ctypes
.c_size_t(0)
635 with self
._raise
_on
_error
():
636 result
= Security
.SSLWrite(
637 self
.context
, data
, len(data
), ctypes
.byref(processed_bytes
)
640 if result
== SecurityConst
.errSSLWouldBlock
and processed_bytes
.value
== 0:
642 raise socket
.timeout("send timed out")
644 _assert_no_error(result
)
646 # We sent, and probably succeeded. Tell them how much we sent.
647 return processed_bytes
.value
649 def sendall(self
, data
):
651 while total_sent
< len(data
):
652 sent
= self
.send(data
[total_sent
: total_sent
+ SSL_WRITE_BLOCKSIZE
])
656 with self
._raise
_on
_error
():
657 Security
.SSLClose(self
.context
)
660 # TODO: should I do clean shutdown here? Do I have to?
661 if self
._makefile
_refs
< 1:
664 CoreFoundation
.CFRelease(self
.context
)
666 if self
._client
_cert
_chain
:
667 CoreFoundation
.CFRelease(self
._client
_cert
_chain
)
668 self
._client
_cert
_chain
= None
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()
676 self
._makefile
_refs
-= 1
678 def getpeercert(self
, binary_form
=False):
681 # Here's how we do this:
683 # 1. Call SSLCopyPeerTrust to get hold of the trust object for this
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.
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.
699 raise ValueError("SecureTransport only supports dumping binary certs")
700 trust
= Security
.SecTrustRef()
705 # Grab the trust store.
706 result
= Security
.SSLCopyPeerTrust(self
.context
, ctypes
.byref(trust
))
707 _assert_no_error(result
)
709 # Probably we haven't done the handshake yet. No biggie.
712 cert_count
= Security
.SecTrustGetCertificateCount(trust
)
714 # Also a case that might happen if we haven't handshaked.
715 # Handshook? Handshaken?
718 leaf
= Security
.SecTrustGetCertificateAtIndex(trust
, 0)
721 # Ok, now we want the DER bytes.
722 certdata
= Security
.SecCertificateCopyData(leaf
)
725 data_length
= CoreFoundation
.CFDataGetLength(certdata
)
726 data_buffer
= CoreFoundation
.CFDataGetBytePtr(certdata
)
727 der_bytes
= ctypes
.string_at(data_buffer
, data_length
)
730 CoreFoundation
.CFRelease(certdata
)
732 CoreFoundation
.CFRelease(trust
)
737 protocol
= Security
.SSLProtocol()
738 result
= Security
.SSLGetNegotiatedProtocolVersion(
739 self
.context
, ctypes
.byref(protocol
)
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
:
746 elif protocol
.value
== SecurityConst
.kTLSProtocol11
:
748 elif protocol
.value
== SecurityConst
.kTLSProtocol1
:
750 elif protocol
.value
== SecurityConst
.kSSLProtocol3
:
752 elif protocol
.value
== SecurityConst
.kSSLProtocol2
:
755 raise ssl
.SSLError("Unknown TLS version: %r" % protocol
)
758 self
._makefile
_refs
+= 1
761 if self
._makefile
_refs
< 1:
764 self
._makefile
_refs
-= 1
767 if _fileobject
: # Platform-specific: Python 2
769 def makefile(self
, mode
, bufsize
=-1):
770 self
._makefile
_refs
+= 1
771 return _fileobject(self
, mode
, bufsize
, close
=True)
773 else: # Platform-specific: Python 3
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).
779 return backport_makefile(self
, mode
, buffering
, *args
, **kwargs
)
782 WrappedSocket
.makefile
= makefile
785 class SecureTransportContext(object):
787 I am a wrapper class for the SecureTransport library, to translate the
788 interface of the standard library ``SSLContext`` object to calls into
792 def __init__(self
, protocol
):
793 self
._min
_version
, self
._max
_version
= _protocol_to_min_max
[protocol
]
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
803 def check_hostname(self
):
805 SecureTransport cannot have its hostname checking disabled. For more,
806 see the comment on getpeercert() in this file.
810 @check_hostname.setter
811 def check_hostname(self
, value
):
813 SecureTransport cannot have its hostname checking disabled. For more,
814 see the comment on getpeercert() in this file.
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.
829 def options(self
, value
):
830 # TODO: Update in line with above.
831 self
._options
= value
834 def verify_mode(self
):
835 return ssl
.CERT_REQUIRED
if self
._verify
else ssl
.CERT_NONE
838 def verify_mode(self
, value
):
839 self
._verify
= True if value
== ssl
.CERT_REQUIRED
else False
841 def set_default_verify_paths(self
):
842 # So, this has to do something a bit weird. Specifically, what it does
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
853 def load_default_certs(self
):
854 return self
.set_default_verify_paths()
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")
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")
866 # Raise if cafile does not exist.
867 if cafile
is not None:
871 self
._trust
_bundle
= cafile
or cadata
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
878 def set_alpn_protocols(self
, protocols
):
880 Sets the ALPN protocols that will later be set on the context.
882 Raises a NotImplementedError if ALPN is not supported.
884 if not hasattr(Security
, "SSLSetALPNProtocols"):
885 raise NotImplementedError(
886 "SecureTransport supports ALPN only in macOS 10.12+"
888 self
._alpn
_protocols
= [six
.ensure_binary(p
) for p
in protocols
]
894 do_handshake_on_connect
=True,
895 suppress_ragged_eofs
=True,
896 server_hostname
=None,
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
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
)
909 # Now we can handshake
910 wrapped_socket
.handshake(
918 self
._client
_key
_passphrase
,
919 self
._alpn
_protocols
,
921 return wrapped_socket