We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
assert_fingerprint SHA256 support is missing
assert_fingerprint only seems to support MD5 and SHA1.  Would it be possible to add SHA256 support to it?


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `urllib3/util/ssl_.py`
Content:
```
1 from binascii import hexlify, unhexlify
2 from hashlib import md5, sha1
3 
4 from ..exceptions import SSLError
5 
6 
7 SSLContext = None
8 HAS_SNI = False
9 create_default_context = None
10 
11 import errno
12 import ssl
13 
14 try:  # Test for SSL features
15     from ssl import wrap_socket, CERT_NONE, PROTOCOL_SSLv23
16     from ssl import HAS_SNI  # Has SNI?
17 except ImportError:
18     pass
19 
20 
21 try:
22     from ssl import OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION
23 except ImportError:
24     OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000
25     OP_NO_COMPRESSION = 0x20000
26 
27 try:
28     from ssl import _DEFAULT_CIPHERS
29 except ImportError:
30     _DEFAULT_CIPHERS = (
31         'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
32         'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:'
33         'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5'
34     )
35 
36 try:
37     from ssl import SSLContext  # Modern SSL?
38 except ImportError:
39     import sys
40 
41     class SSLContext(object):  # Platform-specific: Python 2 & 3.1
42         supports_set_ciphers = sys.version_info >= (2, 7)
43 
44         def __init__(self, protocol_version):
45             self.protocol = protocol_version
46             # Use default values from a real SSLContext
47             self.check_hostname = False
48             self.verify_mode = ssl.CERT_NONE
49             self.ca_certs = None
50             self.options = 0
51             self.certfile = None
52             self.keyfile = None
53             self.ciphers = None
54 
55         def load_cert_chain(self, certfile, keyfile):
56             self.certfile = certfile
57             self.keyfile = keyfile
58 
59         def load_verify_locations(self, location):
60             self.ca_certs = location
61 
62         def set_ciphers(self, cipher_suite):
63             if not self.supports_set_ciphers:
64                 raise TypeError(
65                     'Your version of Python does not support setting '
66                     'a custom cipher suite. Please upgrade to Python '
67                     '2.7, 3.2, or later if you need this functionality.'
68                 )
69             self.ciphers = cipher_suite
70 
71         def wrap_socket(self, socket, server_hostname=None):
72             kwargs = {
73                 'keyfile': self.keyfile,
74                 'certfile': self.certfile,
75                 'ca_certs': self.ca_certs,
76                 'cert_reqs': self.verify_mode,
77                 'ssl_version': self.protocol,
78             }
79             if self.supports_set_ciphers:  # Platform-specific: Python 2.7+
80                 return wrap_socket(socket, ciphers=self.ciphers, **kwargs)
81             else:  # Platform-specific: Python 2.6
82                 return wrap_socket(socket, **kwargs)
83 
84 
85 def assert_fingerprint(cert, fingerprint):
86     """
87     Checks if given fingerprint matches the supplied certificate.
88 
89     :param cert:
90         Certificate as bytes object.
91     :param fingerprint:
92         Fingerprint as string of hexdigits, can be interspersed by colons.
93     """
94 
95     # Maps the length of a digest to a possible hash function producing
96     # this digest.
97     hashfunc_map = {
98         16: md5,
99         20: sha1
100     }
101 
102     fingerprint = fingerprint.replace(':', '').lower()
103     digest_length, odd = divmod(len(fingerprint), 2)
104 
105     if odd or digest_length not in hashfunc_map:
106         raise SSLError('Fingerprint is of invalid length.')
107 
108     # We need encode() here for py32; works on py2 and p33.
109     fingerprint_bytes = unhexlify(fingerprint.encode())
110 
111     hashfunc = hashfunc_map[digest_length]
112 
113     cert_digest = hashfunc(cert).digest()
114 
115     if not cert_digest == fingerprint_bytes:
116         raise SSLError('Fingerprints did not match. Expected "{0}", got "{1}".'
117                        .format(hexlify(fingerprint_bytes),
118                                hexlify(cert_digest)))
119 
120 
121 def resolve_cert_reqs(candidate):
122     """
123     Resolves the argument to a numeric constant, which can be passed to
124     the wrap_socket function/method from the ssl module.
125     Defaults to :data:`ssl.CERT_NONE`.
126     If given a string it is assumed to be the name of the constant in the
127     :mod:`ssl` module or its abbrevation.
128     (So you can specify `REQUIRED` instead of `CERT_REQUIRED`.
129     If it's neither `None` nor a string we assume it is already the numeric
130     constant which can directly be passed to wrap_socket.
131     """
132     if candidate is None:
133         return CERT_NONE
134 
135     if isinstance(candidate, str):
136         res = getattr(ssl, candidate, None)
137         if res is None:
138             res = getattr(ssl, 'CERT_' + candidate)
139         return res
140 
141     return candidate
142 
143 
144 def resolve_ssl_version(candidate):
145     """
146     like resolve_cert_reqs
147     """
148     if candidate is None:
149         return PROTOCOL_SSLv23
150 
151     if isinstance(candidate, str):
152         res = getattr(ssl, candidate, None)
153         if res is None:
154             res = getattr(ssl, 'PROTOCOL_' + candidate)
155         return res
156 
157     return candidate
158 
159 
160 def create_urllib3_context(ssl_version=None, cert_reqs=ssl.CERT_REQUIRED,
161                            options=None, ciphers=None):
162     """All arguments have the same meaning as ``ssl_wrap_socket``.
163 
164     By default, this function does a lot of the same work that
165     ``ssl.create_default_context`` does on Python 3.4+. It:
166 
167     - Disables SSLv2, SSLv3, and compression
168     - Sets a restricted set of server ciphers
169 
170     If you wish to enable SSLv3, you can do::
171 
172         from urllib3.util import ssl_
173         context = ssl_.create_urllib3_context()
174         context.options &= ~ssl_.OP_NO_SSLv3
175 
176     You can do the same to enable compression (substituting ``COMPRESSION``
177     for ``SSLv3`` in the last line above).
178 
179     :param ssl_version:
180         The desired protocol version to use. This will default to
181         PROTOCOL_SSLv23 which will negotiate the highest protocol that both
182         the server and your installation of OpenSSL support.
183     :param cert_reqs:
184         Whether to require the certificate verification. This defaults to
185         ``ssl.CERT_REQUIRED``.
186     :param options:
187         Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``,
188         ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``.
189     :param ciphers:
190         Which cipher suites to allow the server to select.
191     :returns:
192         Constructed SSLContext object with specified options
193     :rtype: SSLContext
194     """
195     context = SSLContext(ssl_version or ssl.PROTOCOL_SSLv23)
196 
197     if options is None:
198         options = 0
199         # SSLv2 is easily broken and is considered harmful and dangerous
200         options |= OP_NO_SSLv2
201         # SSLv3 has several problems and is now dangerous
202         options |= OP_NO_SSLv3
203         # Disable compression to prevent CRIME attacks for OpenSSL 1.0+
204         # (issue #309)
205         options |= OP_NO_COMPRESSION
206 
207     context.options |= options
208 
209     if getattr(context, 'supports_set_ciphers', True):  # Platform-specific: Python 2.6
210         context.set_ciphers(ciphers or _DEFAULT_CIPHERS)
211 
212     context.verify_mode = cert_reqs
213     if getattr(context, 'check_hostname', None) is not None:  # Platform-specific: Python 3.2
214         context.check_hostname = (context.verify_mode == ssl.CERT_REQUIRED)
215     return context
216 
217 
218 def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,
219                     ca_certs=None, server_hostname=None,
220                     ssl_version=None, ciphers=None, ssl_context=None):
221     """
222     All arguments except for server_hostname and ssl_context have the same
223     meaning as they do when using :func:`ssl.wrap_socket`.
224 
225     :param server_hostname:
226         When SNI is supported, the expected hostname of the certificate
227     :param ssl_context:
228         A pre-made :class:`SSLContext` object. If none is provided, one will
229         be created using :func:`create_urllib3_context`.
230     :param ciphers:
231         A string of ciphers we wish the client to support. This is not
232         supported on Python 2.6 as the ssl module does not support it.
233     """
234     context = ssl_context
235     if context is None:
236         context = create_urllib3_context(ssl_version, cert_reqs,
237                                          ciphers=ciphers)
238 
239     if ca_certs:
240         try:
241             context.load_verify_locations(ca_certs)
242         except IOError as e:  # Platform-specific: Python 2.6, 2.7, 3.2
243             raise SSLError(e)
244         # Py33 raises FileNotFoundError which subclasses OSError
245         # These are not equivalent unless we check the errno attribute
246         except OSError as e:  # Platform-specific: Python 3.3 and beyond
247             if e.errno == errno.ENOENT:
248                 raise SSLError(e)
249             raise
250     if certfile:
251         context.load_cert_chain(certfile, keyfile)
252     if HAS_SNI:  # Platform-specific: OpenSSL with enabled SNI
253         return context.wrap_socket(sock, server_hostname=server_hostname)
254     return context.wrap_socket(sock)
255
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/urllib3/util/ssl_.py b/urllib3/util/ssl_.py
--- a/urllib3/util/ssl_.py
+++ b/urllib3/util/ssl_.py
@@ -1,5 +1,5 @@
 from binascii import hexlify, unhexlify
-from hashlib import md5, sha1
+from hashlib import md5, sha1, sha256
 
 from ..exceptions import SSLError
 
@@ -96,7 +96,8 @@
     # this digest.
     hashfunc_map = {
         16: md5,
-        20: sha1
+        20: sha1,
+        32: sha256,
     }
 
     fingerprint = fingerprint.replace(':', '').lower()

{"golden_diff": "diff --git a/urllib3/util/ssl_.py b/urllib3/util/ssl_.py\n--- a/urllib3/util/ssl_.py\n+++ b/urllib3/util/ssl_.py\n@@ -1,5 +1,5 @@\n from binascii import hexlify, unhexlify\n-from hashlib import md5, sha1\n+from hashlib import md5, sha1, sha256\n \n from ..exceptions import SSLError\n \n@@ -96,7 +96,8 @@\n     # this digest.\n     hashfunc_map = {\n         16: md5,\n-        20: sha1\n+        20: sha1,\n+        32: sha256,\n     }\n \n     fingerprint = fingerprint.replace(':', '').lower()\n", "issue": "assert_fingerprint SHA256 support is missing\nassert_fingerprint only seems to support MD5 and SHA1.  Would it be possible to add SHA256 support to it?\n\n", "before_files": [{"content": "from binascii import hexlify, unhexlify\nfrom hashlib import md5, sha1\n\nfrom ..exceptions import SSLError\n\n\nSSLContext = None\nHAS_SNI = False\ncreate_default_context = None\n\nimport errno\nimport ssl\n\ntry:  # Test for SSL features\n    from ssl import wrap_socket, CERT_NONE, PROTOCOL_SSLv23\n    from ssl import HAS_SNI  # Has SNI?\nexcept ImportError:\n    pass\n\n\ntry:\n    from ssl import OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION\nexcept ImportError:\n    OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000\n    OP_NO_COMPRESSION = 0x20000\n\ntry:\n    from ssl import _DEFAULT_CIPHERS\nexcept ImportError:\n    _DEFAULT_CIPHERS = (\n        'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'\n        'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:'\n        'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5'\n    )\n\ntry:\n    from ssl import SSLContext  # Modern SSL?\nexcept ImportError:\n    import sys\n\n    class SSLContext(object):  # Platform-specific: Python 2 & 3.1\n        supports_set_ciphers = sys.version_info >= (2, 7)\n\n        def __init__(self, protocol_version):\n            self.protocol = protocol_version\n            # Use default values from a real SSLContext\n            self.check_hostname = False\n            self.verify_mode = ssl.CERT_NONE\n            self.ca_certs = None\n            self.options = 0\n            self.certfile = None\n            self.keyfile = None\n            self.ciphers = None\n\n        def load_cert_chain(self, certfile, keyfile):\n            self.certfile = certfile\n            self.keyfile = keyfile\n\n        def load_verify_locations(self, location):\n            self.ca_certs = location\n\n        def set_ciphers(self, cipher_suite):\n            if not self.supports_set_ciphers:\n                raise TypeError(\n                    'Your version of Python does not support setting '\n                    'a custom cipher suite. Please upgrade to Python '\n                    '2.7, 3.2, or later if you need this functionality.'\n                )\n            self.ciphers = cipher_suite\n\n        def wrap_socket(self, socket, server_hostname=None):\n            kwargs = {\n                'keyfile': self.keyfile,\n                'certfile': self.certfile,\n                'ca_certs': self.ca_certs,\n                'cert_reqs': self.verify_mode,\n                'ssl_version': self.protocol,\n            }\n            if self.supports_set_ciphers:  # Platform-specific: Python 2.7+\n                return wrap_socket(socket, ciphers=self.ciphers, **kwargs)\n            else:  # Platform-specific: Python 2.6\n                return wrap_socket(socket, **kwargs)\n\n\ndef assert_fingerprint(cert, fingerprint):\n    \"\"\"\n    Checks if given fingerprint matches the supplied certificate.\n\n    :param cert:\n        Certificate as bytes object.\n    :param fingerprint:\n        Fingerprint as string of hexdigits, can be interspersed by colons.\n    \"\"\"\n\n    # Maps the length of a digest to a possible hash function producing\n    # this digest.\n    hashfunc_map = {\n        16: md5,\n        20: sha1\n    }\n\n    fingerprint = fingerprint.replace(':', '').lower()\n    digest_length, odd = divmod(len(fingerprint), 2)\n\n    if odd or digest_length not in hashfunc_map:\n        raise SSLError('Fingerprint is of invalid length.')\n\n    # We need encode() here for py32; works on py2 and p33.\n    fingerprint_bytes = unhexlify(fingerprint.encode())\n\n    hashfunc = hashfunc_map[digest_length]\n\n    cert_digest = hashfunc(cert).digest()\n\n    if not cert_digest == fingerprint_bytes:\n        raise SSLError('Fingerprints did not match. Expected \"{0}\", got \"{1}\".'\n                       .format(hexlify(fingerprint_bytes),\n                               hexlify(cert_digest)))\n\n\ndef resolve_cert_reqs(candidate):\n    \"\"\"\n    Resolves the argument to a numeric constant, which can be passed to\n    the wrap_socket function/method from the ssl module.\n    Defaults to :data:`ssl.CERT_NONE`.\n    If given a string it is assumed to be the name of the constant in the\n    :mod:`ssl` module or its abbrevation.\n    (So you can specify `REQUIRED` instead of `CERT_REQUIRED`.\n    If it's neither `None` nor a string we assume it is already the numeric\n    constant which can directly be passed to wrap_socket.\n    \"\"\"\n    if candidate is None:\n        return CERT_NONE\n\n    if isinstance(candidate, str):\n        res = getattr(ssl, candidate, None)\n        if res is None:\n            res = getattr(ssl, 'CERT_' + candidate)\n        return res\n\n    return candidate\n\n\ndef resolve_ssl_version(candidate):\n    \"\"\"\n    like resolve_cert_reqs\n    \"\"\"\n    if candidate is None:\n        return PROTOCOL_SSLv23\n\n    if isinstance(candidate, str):\n        res = getattr(ssl, candidate, None)\n        if res is None:\n            res = getattr(ssl, 'PROTOCOL_' + candidate)\n        return res\n\n    return candidate\n\n\ndef create_urllib3_context(ssl_version=None, cert_reqs=ssl.CERT_REQUIRED,\n                           options=None, ciphers=None):\n    \"\"\"All arguments have the same meaning as ``ssl_wrap_socket``.\n\n    By default, this function does a lot of the same work that\n    ``ssl.create_default_context`` does on Python 3.4+. It:\n\n    - Disables SSLv2, SSLv3, and compression\n    - Sets a restricted set of server ciphers\n\n    If you wish to enable SSLv3, you can do::\n\n        from urllib3.util import ssl_\n        context = ssl_.create_urllib3_context()\n        context.options &= ~ssl_.OP_NO_SSLv3\n\n    You can do the same to enable compression (substituting ``COMPRESSION``\n    for ``SSLv3`` in the last line above).\n\n    :param ssl_version:\n        The desired protocol version to use. This will default to\n        PROTOCOL_SSLv23 which will negotiate the highest protocol that both\n        the server and your installation of OpenSSL support.\n    :param cert_reqs:\n        Whether to require the certificate verification. This defaults to\n        ``ssl.CERT_REQUIRED``.\n    :param options:\n        Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``,\n        ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``.\n    :param ciphers:\n        Which cipher suites to allow the server to select.\n    :returns:\n        Constructed SSLContext object with specified options\n    :rtype: SSLContext\n    \"\"\"\n    context = SSLContext(ssl_version or ssl.PROTOCOL_SSLv23)\n\n    if options is None:\n        options = 0\n        # SSLv2 is easily broken and is considered harmful and dangerous\n        options |= OP_NO_SSLv2\n        # SSLv3 has several problems and is now dangerous\n        options |= OP_NO_SSLv3\n        # Disable compression to prevent CRIME attacks for OpenSSL 1.0+\n        # (issue #309)\n        options |= OP_NO_COMPRESSION\n\n    context.options |= options\n\n    if getattr(context, 'supports_set_ciphers', True):  # Platform-specific: Python 2.6\n        context.set_ciphers(ciphers or _DEFAULT_CIPHERS)\n\n    context.verify_mode = cert_reqs\n    if getattr(context, 'check_hostname', None) is not None:  # Platform-specific: Python 3.2\n        context.check_hostname = (context.verify_mode == ssl.CERT_REQUIRED)\n    return context\n\n\ndef ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,\n                    ca_certs=None, server_hostname=None,\n                    ssl_version=None, ciphers=None, ssl_context=None):\n    \"\"\"\n    All arguments except for server_hostname and ssl_context have the same\n    meaning as they do when using :func:`ssl.wrap_socket`.\n\n    :param server_hostname:\n        When SNI is supported, the expected hostname of the certificate\n    :param ssl_context:\n        A pre-made :class:`SSLContext` object. If none is provided, one will\n        be created using :func:`create_urllib3_context`.\n    :param ciphers:\n        A string of ciphers we wish the client to support. This is not\n        supported on Python 2.6 as the ssl module does not support it.\n    \"\"\"\n    context = ssl_context\n    if context is None:\n        context = create_urllib3_context(ssl_version, cert_reqs,\n                                         ciphers=ciphers)\n\n    if ca_certs:\n        try:\n            context.load_verify_locations(ca_certs)\n        except IOError as e:  # Platform-specific: Python 2.6, 2.7, 3.2\n            raise SSLError(e)\n        # Py33 raises FileNotFoundError which subclasses OSError\n        # These are not equivalent unless we check the errno attribute\n        except OSError as e:  # Platform-specific: Python 3.3 and beyond\n            if e.errno == errno.ENOENT:\n                raise SSLError(e)\n            raise\n    if certfile:\n        context.load_cert_chain(certfile, keyfile)\n    if HAS_SNI:  # Platform-specific: OpenSSL with enabled SNI\n        return context.wrap_socket(sock, server_hostname=server_hostname)\n    return context.wrap_socket(sock)\n", "path": "urllib3/util/ssl_.py"}], "after_files": [{"content": "from binascii import hexlify, unhexlify\nfrom hashlib import md5, sha1, sha256\n\nfrom ..exceptions import SSLError\n\n\nSSLContext = None\nHAS_SNI = False\ncreate_default_context = None\n\nimport errno\nimport ssl\n\ntry:  # Test for SSL features\n    from ssl import wrap_socket, CERT_NONE, PROTOCOL_SSLv23\n    from ssl import HAS_SNI  # Has SNI?\nexcept ImportError:\n    pass\n\n\ntry:\n    from ssl import OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION\nexcept ImportError:\n    OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000\n    OP_NO_COMPRESSION = 0x20000\n\ntry:\n    from ssl import _DEFAULT_CIPHERS\nexcept ImportError:\n    _DEFAULT_CIPHERS = (\n        'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'\n        'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:'\n        'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5'\n    )\n\ntry:\n    from ssl import SSLContext  # Modern SSL?\nexcept ImportError:\n    import sys\n\n    class SSLContext(object):  # Platform-specific: Python 2 & 3.1\n        supports_set_ciphers = sys.version_info >= (2, 7)\n\n        def __init__(self, protocol_version):\n            self.protocol = protocol_version\n            # Use default values from a real SSLContext\n            self.check_hostname = False\n            self.verify_mode = ssl.CERT_NONE\n            self.ca_certs = None\n            self.options = 0\n            self.certfile = None\n            self.keyfile = None\n            self.ciphers = None\n\n        def load_cert_chain(self, certfile, keyfile):\n            self.certfile = certfile\n            self.keyfile = keyfile\n\n        def load_verify_locations(self, location):\n            self.ca_certs = location\n\n        def set_ciphers(self, cipher_suite):\n            if not self.supports_set_ciphers:\n                raise TypeError(\n                    'Your version of Python does not support setting '\n                    'a custom cipher suite. Please upgrade to Python '\n                    '2.7, 3.2, or later if you need this functionality.'\n                )\n            self.ciphers = cipher_suite\n\n        def wrap_socket(self, socket, server_hostname=None):\n            kwargs = {\n                'keyfile': self.keyfile,\n                'certfile': self.certfile,\n                'ca_certs': self.ca_certs,\n                'cert_reqs': self.verify_mode,\n                'ssl_version': self.protocol,\n            }\n            if self.supports_set_ciphers:  # Platform-specific: Python 2.7+\n                return wrap_socket(socket, ciphers=self.ciphers, **kwargs)\n            else:  # Platform-specific: Python 2.6\n                return wrap_socket(socket, **kwargs)\n\n\ndef assert_fingerprint(cert, fingerprint):\n    \"\"\"\n    Checks if given fingerprint matches the supplied certificate.\n\n    :param cert:\n        Certificate as bytes object.\n    :param fingerprint:\n        Fingerprint as string of hexdigits, can be interspersed by colons.\n    \"\"\"\n\n    # Maps the length of a digest to a possible hash function producing\n    # this digest.\n    hashfunc_map = {\n        16: md5,\n        20: sha1,\n        32: sha256,\n    }\n\n    fingerprint = fingerprint.replace(':', '').lower()\n    digest_length, odd = divmod(len(fingerprint), 2)\n\n    if odd or digest_length not in hashfunc_map:\n        raise SSLError('Fingerprint is of invalid length.')\n\n    # We need encode() here for py32; works on py2 and p33.\n    fingerprint_bytes = unhexlify(fingerprint.encode())\n\n    hashfunc = hashfunc_map[digest_length]\n\n    cert_digest = hashfunc(cert).digest()\n\n    if not cert_digest == fingerprint_bytes:\n        raise SSLError('Fingerprints did not match. Expected \"{0}\", got \"{1}\".'\n                       .format(hexlify(fingerprint_bytes),\n                               hexlify(cert_digest)))\n\n\ndef resolve_cert_reqs(candidate):\n    \"\"\"\n    Resolves the argument to a numeric constant, which can be passed to\n    the wrap_socket function/method from the ssl module.\n    Defaults to :data:`ssl.CERT_NONE`.\n    If given a string it is assumed to be the name of the constant in the\n    :mod:`ssl` module or its abbrevation.\n    (So you can specify `REQUIRED` instead of `CERT_REQUIRED`.\n    If it's neither `None` nor a string we assume it is already the numeric\n    constant which can directly be passed to wrap_socket.\n    \"\"\"\n    if candidate is None:\n        return CERT_NONE\n\n    if isinstance(candidate, str):\n        res = getattr(ssl, candidate, None)\n        if res is None:\n            res = getattr(ssl, 'CERT_' + candidate)\n        return res\n\n    return candidate\n\n\ndef resolve_ssl_version(candidate):\n    \"\"\"\n    like resolve_cert_reqs\n    \"\"\"\n    if candidate is None:\n        return PROTOCOL_SSLv23\n\n    if isinstance(candidate, str):\n        res = getattr(ssl, candidate, None)\n        if res is None:\n            res = getattr(ssl, 'PROTOCOL_' + candidate)\n        return res\n\n    return candidate\n\n\ndef create_urllib3_context(ssl_version=None, cert_reqs=ssl.CERT_REQUIRED,\n                           options=None, ciphers=None):\n    \"\"\"All arguments have the same meaning as ``ssl_wrap_socket``.\n\n    By default, this function does a lot of the same work that\n    ``ssl.create_default_context`` does on Python 3.4+. It:\n\n    - Disables SSLv2, SSLv3, and compression\n    - Sets a restricted set of server ciphers\n\n    If you wish to enable SSLv3, you can do::\n\n        from urllib3.util import ssl_\n        context = ssl_.create_urllib3_context()\n        context.options &= ~ssl_.OP_NO_SSLv3\n\n    You can do the same to enable compression (substituting ``COMPRESSION``\n    for ``SSLv3`` in the last line above).\n\n    :param ssl_version:\n        The desired protocol version to use. This will default to\n        PROTOCOL_SSLv23 which will negotiate the highest protocol that both\n        the server and your installation of OpenSSL support.\n    :param cert_reqs:\n        Whether to require the certificate verification. This defaults to\n        ``ssl.CERT_REQUIRED``.\n    :param options:\n        Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``,\n        ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``.\n    :param ciphers:\n        Which cipher suites to allow the server to select.\n    :returns:\n        Constructed SSLContext object with specified options\n    :rtype: SSLContext\n    \"\"\"\n    context = SSLContext(ssl_version or ssl.PROTOCOL_SSLv23)\n\n    if options is None:\n        options = 0\n        # SSLv2 is easily broken and is considered harmful and dangerous\n        options |= OP_NO_SSLv2\n        # SSLv3 has several problems and is now dangerous\n        options |= OP_NO_SSLv3\n        # Disable compression to prevent CRIME attacks for OpenSSL 1.0+\n        # (issue #309)\n        options |= OP_NO_COMPRESSION\n\n    context.options |= options\n\n    if getattr(context, 'supports_set_ciphers', True):  # Platform-specific: Python 2.6\n        context.set_ciphers(ciphers or _DEFAULT_CIPHERS)\n\n    context.verify_mode = cert_reqs\n    if getattr(context, 'check_hostname', None) is not None:  # Platform-specific: Python 3.2\n        context.check_hostname = (context.verify_mode == ssl.CERT_REQUIRED)\n    return context\n\n\ndef ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,\n                    ca_certs=None, server_hostname=None,\n                    ssl_version=None, ciphers=None, ssl_context=None):\n    \"\"\"\n    All arguments except for server_hostname and ssl_context have the same\n    meaning as they do when using :func:`ssl.wrap_socket`.\n\n    :param server_hostname:\n        When SNI is supported, the expected hostname of the certificate\n    :param ssl_context:\n        A pre-made :class:`SSLContext` object. If none is provided, one will\n        be created using :func:`create_urllib3_context`.\n    :param ciphers:\n        A string of ciphers we wish the client to support. This is not\n        supported on Python 2.6 as the ssl module does not support it.\n    \"\"\"\n    context = ssl_context\n    if context is None:\n        context = create_urllib3_context(ssl_version, cert_reqs,\n                                         ciphers=ciphers)\n\n    if ca_certs:\n        try:\n            context.load_verify_locations(ca_certs)\n        except IOError as e:  # Platform-specific: Python 2.6, 2.7, 3.2\n            raise SSLError(e)\n        # Py33 raises FileNotFoundError which subclasses OSError\n        # These are not equivalent unless we check the errno attribute\n        except OSError as e:  # Platform-specific: Python 3.3 and beyond\n            if e.errno == errno.ENOENT:\n                raise SSLError(e)\n            raise\n    if certfile:\n        context.load_cert_chain(certfile, keyfile)\n    if HAS_SNI:  # Platform-specific: OpenSSL with enabled SNI\n        return context.wrap_socket(sock, server_hostname=server_hostname)\n    return context.wrap_socket(sock)\n", "path": "urllib3/util/ssl_.py"}]}