Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: third_party/requests/packages/urllib3/contrib/pyopenssl.py

Issue 24076010: Add 'requests' library to third_party. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/swarm_client
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 '''SSL with SNI-support for Python 2.
2
3 This needs the following packages installed:
4
5 * pyOpenSSL (tested with 0.13)
6 * ndg-httpsclient (tested with 0.3.2)
7 * pyasn1 (tested with 0.1.6)
8
9 To activate it call :func:`~urllib3.contrib.pyopenssl.inject_into_urllib3`.
10 This can be done in a ``sitecustomize`` module, or at any other time before
11 your application begins using ``urllib3``, like this::
12
13 try:
14 import urllib3.contrib.pyopenssl
15 urllib3.contrib.pyopenssl.inject_into_urllib3()
16 except ImportError:
17 pass
18
19 Now you can use :mod:`urllib3` as you normally would, and it will support SNI
20 when the required modules are installed.
21 '''
22
23 from ndg.httpsclient.ssl_peer_verification import (ServerSSLCertVerification,
24 SUBJ_ALT_NAME_SUPPORT)
25 from ndg.httpsclient.subj_alt_name import SubjectAltName
26 import OpenSSL.SSL
27 from pyasn1.codec.der import decoder as der_decoder
28 from socket import _fileobject
29 import ssl
30
31 from .. import connectionpool
32 from .. import util
33
34 __all__ = ['inject_into_urllib3', 'extract_from_urllib3']
35
36 # SNI only *really* works if we can read the subjectAltName of certificates.
37 HAS_SNI = SUBJ_ALT_NAME_SUPPORT
38
39 # Map from urllib3 to PyOpenSSL compatible parameter-values.
40 _openssl_versions = {
41 ssl.PROTOCOL_SSLv23: OpenSSL.SSL.SSLv23_METHOD,
42 ssl.PROTOCOL_SSLv3: OpenSSL.SSL.SSLv3_METHOD,
43 ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD,
44 }
45 _openssl_verify = {
46 ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE,
47 ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER,
48 ssl.CERT_REQUIRED: OpenSSL.SSL.VERIFY_PEER
49 + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
50 }
51
52
53 orig_util_HAS_SNI = util.HAS_SNI
54 orig_connectionpool_ssl_wrap_socket = connectionpool.ssl_wrap_socket
55
56
57 def inject_into_urllib3():
58 'Monkey-patch urllib3 with PyOpenSSL-backed SSL-support.'
59
60 connectionpool.ssl_wrap_socket = ssl_wrap_socket
61 util.HAS_SNI = HAS_SNI
62
63
64 def extract_from_urllib3():
65 'Undo monkey-patching by :func:`inject_into_urllib3`.'
66
67 connectionpool.ssl_wrap_socket = orig_connectionpool_ssl_wrap_socket
68 util.HAS_SNI = orig_util_HAS_SNI
69
70
71 ### Note: This is a slightly bug-fixed version of same from ndg-httpsclient.
72 def get_subj_alt_name(peer_cert):
73 # Search through extensions
74 dns_name = []
75 if not SUBJ_ALT_NAME_SUPPORT:
76 return dns_name
77
78 general_names = SubjectAltName()
79 for i in range(peer_cert.get_extension_count()):
80 ext = peer_cert.get_extension(i)
81 ext_name = ext.get_short_name()
82 if ext_name != 'subjectAltName':
83 continue
84
85 # PyOpenSSL returns extension data in ASN.1 encoded form
86 ext_dat = ext.get_data()
87 decoded_dat = der_decoder.decode(ext_dat,
88 asn1Spec=general_names)
89
90 for name in decoded_dat:
91 if not isinstance(name, SubjectAltName):
92 continue
93 for entry in range(len(name)):
94 component = name.getComponentByPosition(entry)
95 if component.getName() != 'dNSName':
96 continue
97 dns_name.append(str(component.getComponent()))
98
99 return dns_name
100
101
102 class WrappedSocket(object):
103 '''API-compatibility wrapper for Python OpenSSL's Connection-class.'''
104
105 def __init__(self, connection, socket):
106 self.connection = connection
107 self.socket = socket
108
109 def makefile(self, mode, bufsize=-1):
110 return _fileobject(self.connection, mode, bufsize)
111
112 def settimeout(self, timeout):
113 return self.socket.settimeout(timeout)
114
115 def sendall(self, data):
116 return self.connection.sendall(data)
117
118 def getpeercert(self, binary_form=False):
119 x509 = self.connection.get_peer_certificate()
120 if not x509:
121 raise ssl.SSLError('')
122
123 if binary_form:
124 return OpenSSL.crypto.dump_certificate(
125 OpenSSL.crypto.FILETYPE_ASN1,
126 x509)
127
128 return {
129 'subject': (
130 (('commonName', x509.get_subject().CN),),
131 ),
132 'subjectAltName': [
133 ('DNS', value)
134 for value in get_subj_alt_name(x509)
135 ]
136 }
137
138
139 def _verify_callback(cnx, x509, err_no, err_depth, return_code):
140 return err_no == 0
141
142
143 def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,
144 ca_certs=None, server_hostname=None,
145 ssl_version=None):
146 ctx = OpenSSL.SSL.Context(_openssl_versions[ssl_version])
147 if certfile:
148 ctx.use_certificate_file(certfile)
149 if keyfile:
150 ctx.use_privatekey_file(keyfile)
151 if cert_reqs != ssl.CERT_NONE:
152 ctx.set_verify(_openssl_verify[cert_reqs], _verify_callback)
153 if ca_certs:
154 try:
155 ctx.load_verify_locations(ca_certs, None)
156 except OpenSSL.SSL.Error as e:
157 raise ssl.SSLError('bad ca_certs: %r' % ca_certs, e)
158
159 cnx = OpenSSL.SSL.Connection(ctx, sock)
160 cnx.set_tlsext_host_name(server_hostname)
161 cnx.set_connect_state()
162 try:
163 cnx.do_handshake()
164 except OpenSSL.SSL.Error as e:
165 raise ssl.SSLError('bad handshake', e)
166
167 return WrappedSocket(cnx, sock)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698