We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Raise an error on openssl 0.9.8
With an env var (probably `CRYPTOGRAPHY_ALLOW_OPENSSL_098`) to allow disabling it for this one release.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/cryptography/hazmat/bindings/openssl/binding.py`
Content:
```
1 # This file is dual licensed under the terms of the Apache License, Version
2 # 2.0, and the BSD License. See the LICENSE file in the root of this repository
3 # for complete details.
4 
5 from __future__ import absolute_import, division, print_function
6 
7 import collections
8 import os
9 import threading
10 import types
11 import warnings
12 
13 from cryptography import utils
14 from cryptography.exceptions import InternalError
15 from cryptography.hazmat.bindings._openssl import ffi, lib
16 from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES
17 
18 _OpenSSLError = collections.namedtuple("_OpenSSLError",
19                                        ["code", "lib", "func", "reason"])
20 _OpenSSLErrorWithText = collections.namedtuple(
21     "_OpenSSLErrorWithText", ["code", "lib", "func", "reason", "reason_text"]
22 )
23 
24 
25 def _consume_errors(lib):
26     errors = []
27     while True:
28         code = lib.ERR_get_error()
29         if code == 0:
30             break
31 
32         err_lib = lib.ERR_GET_LIB(code)
33         err_func = lib.ERR_GET_FUNC(code)
34         err_reason = lib.ERR_GET_REASON(code)
35 
36         errors.append(_OpenSSLError(code, err_lib, err_func, err_reason))
37 
38     return errors
39 
40 
41 def _openssl_assert(lib, ok):
42     if not ok:
43         errors = _consume_errors(lib)
44         errors_with_text = []
45         for err in errors:
46             err_text_reason = ffi.string(
47                 lib.ERR_error_string(err.code, ffi.NULL)
48             )
49             errors_with_text.append(
50                 _OpenSSLErrorWithText(
51                     err.code, err.lib, err.func, err.reason, err_text_reason
52                 )
53             )
54 
55         raise InternalError(
56             "Unknown OpenSSL error. This error is commonly encountered when "
57             "another library is not cleaning up the OpenSSL error stack. If "
58             "you are using cryptography with another library that uses "
59             "OpenSSL try disabling it before reporting a bug. Otherwise "
60             "please file an issue at https://github.com/pyca/cryptography/"
61             "issues with information on how to reproduce "
62             "this. ({0!r})".format(errors_with_text),
63             errors_with_text
64         )
65 
66 
67 def ffi_callback(signature, name, **kwargs):
68     """Callback dispatcher
69 
70     The ffi_callback() dispatcher keeps callbacks compatible between dynamic
71     and static callbacks.
72     """
73     def wrapper(func):
74         if lib.Cryptography_STATIC_CALLBACKS:
75             # def_extern() returns a decorator that sets the internal
76             # function pointer and returns the original function unmodified.
77             ffi.def_extern(name=name, **kwargs)(func)
78             callback = getattr(lib, name)
79         else:
80             # callback() wraps the function in a cdata function.
81             callback = ffi.callback(signature, **kwargs)(func)
82         return callback
83     return wrapper
84 
85 
86 @ffi_callback("int (*)(unsigned char *, int)",
87               name="Cryptography_rand_bytes",
88               error=-1)
89 def _osrandom_rand_bytes(buf, size):
90     signed = ffi.cast("char *", buf)
91     result = os.urandom(size)
92     signed[0:size] = result
93     return 1
94 
95 
96 @ffi_callback("int (*)(void)", name="Cryptography_rand_status")
97 def _osrandom_rand_status():
98     return 1
99 
100 
101 def build_conditional_library(lib, conditional_names):
102     conditional_lib = types.ModuleType("lib")
103     excluded_names = set()
104     for condition, names in conditional_names.items():
105         if not getattr(lib, condition):
106             excluded_names |= set(names)
107 
108     for attr in dir(lib):
109         if attr not in excluded_names:
110             setattr(conditional_lib, attr, getattr(lib, attr))
111 
112     return conditional_lib
113 
114 
115 class Binding(object):
116     """
117     OpenSSL API wrapper.
118     """
119     lib = None
120     ffi = ffi
121     _lib_loaded = False
122     _locks = None
123     _lock_cb_handle = None
124     _init_lock = threading.Lock()
125     _lock_init_lock = threading.Lock()
126 
127     _osrandom_engine_id = ffi.new("const char[]", b"osrandom")
128     _osrandom_engine_name = ffi.new("const char[]", b"osrandom_engine")
129     _osrandom_method = ffi.new(
130         "RAND_METHOD *",
131         dict(bytes=_osrandom_rand_bytes,
132              pseudorand=_osrandom_rand_bytes,
133              status=_osrandom_rand_status)
134     )
135 
136     def __init__(self):
137         self._ensure_ffi_initialized()
138 
139     @classmethod
140     def _register_osrandom_engine(cls):
141         _openssl_assert(cls.lib, cls.lib.ERR_peek_error() == 0)
142 
143         engine = cls.lib.ENGINE_new()
144         _openssl_assert(cls.lib, engine != cls.ffi.NULL)
145         try:
146             result = cls.lib.ENGINE_set_id(engine, cls._osrandom_engine_id)
147             _openssl_assert(cls.lib, result == 1)
148             result = cls.lib.ENGINE_set_name(engine, cls._osrandom_engine_name)
149             _openssl_assert(cls.lib, result == 1)
150             result = cls.lib.ENGINE_set_RAND(engine, cls._osrandom_method)
151             _openssl_assert(cls.lib, result == 1)
152             result = cls.lib.ENGINE_add(engine)
153             if result != 1:
154                 errors = _consume_errors(cls.lib)
155                 _openssl_assert(
156                     cls.lib,
157                     errors[0].reason == cls.lib.ENGINE_R_CONFLICTING_ENGINE_ID
158                 )
159 
160         finally:
161             result = cls.lib.ENGINE_free(engine)
162             _openssl_assert(cls.lib, result == 1)
163 
164     @classmethod
165     def _ensure_ffi_initialized(cls):
166         with cls._init_lock:
167             if not cls._lib_loaded:
168                 cls.lib = build_conditional_library(lib, CONDITIONAL_NAMES)
169                 cls._lib_loaded = True
170                 # initialize the SSL library
171                 cls.lib.SSL_library_init()
172                 # adds all ciphers/digests for EVP
173                 cls.lib.OpenSSL_add_all_algorithms()
174                 # loads error strings for libcrypto and libssl functions
175                 cls.lib.SSL_load_error_strings()
176                 cls._register_osrandom_engine()
177 
178     @classmethod
179     def init_static_locks(cls):
180         with cls._lock_init_lock:
181             cls._ensure_ffi_initialized()
182 
183             if not cls._lock_cb_handle:
184                 wrapper = ffi_callback(
185                     "void(int, int, const char *, int)",
186                     name="Cryptography_locking_cb",
187                 )
188                 cls._lock_cb_handle = wrapper(cls._lock_cb)
189 
190             # Use Python's implementation if available, importing _ssl triggers
191             # the setup for this.
192             __import__("_ssl")
193 
194             if cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL:
195                 return
196 
197             # If nothing else has setup a locking callback already, we set up
198             # our own
199             num_locks = cls.lib.CRYPTO_num_locks()
200             cls._locks = [threading.Lock() for n in range(num_locks)]
201 
202             cls.lib.CRYPTO_set_locking_callback(cls._lock_cb_handle)
203 
204     @classmethod
205     def _lock_cb(cls, mode, n, file, line):
206         lock = cls._locks[n]
207 
208         if mode & cls.lib.CRYPTO_LOCK:
209             lock.acquire()
210         elif mode & cls.lib.CRYPTO_UNLOCK:
211             lock.release()
212         else:
213             raise RuntimeError(
214                 "Unknown lock mode {0}: lock={1}, file={2}, line={3}.".format(
215                     mode, n, file, line
216                 )
217             )
218 
219 
220 # OpenSSL is not thread safe until the locks are initialized. We call this
221 # method in module scope so that it executes with the import lock. On
222 # Pythons < 3.4 this import lock is a global lock, which can prevent a race
223 # condition registering the OpenSSL locks. On Python 3.4+ the import lock
224 # is per module so this approach will not work.
225 Binding.init_static_locks()
226 
227 if Binding.lib.SSLeay() < 0x10000000:
228     warnings.warn(
229         "OpenSSL version 0.9.8 is no longer supported by the OpenSSL project, "
230         "please upgrade. The next version of cryptography will drop support "
231         "for it.",
232         utils.DeprecatedIn12
233     )
234 elif Binding.lib.SSLeay() < 0x10001000:
235     warnings.warn(
236         "OpenSSL versions less than 1.0.1 are no longer supported by the "
237         "OpenSSL project, please upgrade. A future version of cryptography "
238         "will drop support for these versions.",
239         DeprecationWarning
240     )
241
```
--- 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/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py
--- a/src/cryptography/hazmat/bindings/openssl/binding.py
+++ b/src/cryptography/hazmat/bindings/openssl/binding.py
@@ -10,7 +10,6 @@
 import types
 import warnings
 
-from cryptography import utils
 from cryptography.exceptions import InternalError
 from cryptography.hazmat.bindings._openssl import ffi, lib
 from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES
@@ -217,6 +216,30 @@
             )
 
 
+def _verify_openssl_version(version):
+    if version < 0x10000000:
+        if os.environ.get("CRYPTOGRAPHY_ALLOW_OPENSSL_098"):
+            warnings.warn(
+                "OpenSSL version 0.9.8 is no longer supported by the OpenSSL "
+                "project, please upgrade. The next version of cryptography "
+                "will completely remove support for it.",
+                DeprecationWarning
+            )
+        else:
+            raise RuntimeError(
+                "You are linking against OpenSSL 0.9.8, which is no longer "
+                "support by the OpenSSL project. You need to upgrade to a "
+                "newer version of OpenSSL."
+            )
+    elif version < 0x10001000:
+        warnings.warn(
+            "OpenSSL versions less than 1.0.1 are no longer supported by the "
+            "OpenSSL project, please upgrade. A future version of "
+            "cryptography will drop support for these versions of OpenSSL.",
+            DeprecationWarning
+        )
+
+
 # OpenSSL is not thread safe until the locks are initialized. We call this
 # method in module scope so that it executes with the import lock. On
 # Pythons < 3.4 this import lock is a global lock, which can prevent a race
@@ -224,17 +247,4 @@
 # is per module so this approach will not work.
 Binding.init_static_locks()
 
-if Binding.lib.SSLeay() < 0x10000000:
-    warnings.warn(
-        "OpenSSL version 0.9.8 is no longer supported by the OpenSSL project, "
-        "please upgrade. The next version of cryptography will drop support "
-        "for it.",
-        utils.DeprecatedIn12
-    )
-elif Binding.lib.SSLeay() < 0x10001000:
-    warnings.warn(
-        "OpenSSL versions less than 1.0.1 are no longer supported by the "
-        "OpenSSL project, please upgrade. A future version of cryptography "
-        "will drop support for these versions.",
-        DeprecationWarning
-    )
+_verify_openssl_version(Binding.lib.SSLeay())

{"golden_diff": "diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py\n--- a/src/cryptography/hazmat/bindings/openssl/binding.py\n+++ b/src/cryptography/hazmat/bindings/openssl/binding.py\n@@ -10,7 +10,6 @@\n import types\n import warnings\n \n-from cryptography import utils\n from cryptography.exceptions import InternalError\n from cryptography.hazmat.bindings._openssl import ffi, lib\n from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES\n@@ -217,6 +216,30 @@\n             )\n \n \n+def _verify_openssl_version(version):\n+    if version < 0x10000000:\n+        if os.environ.get(\"CRYPTOGRAPHY_ALLOW_OPENSSL_098\"):\n+            warnings.warn(\n+                \"OpenSSL version 0.9.8 is no longer supported by the OpenSSL \"\n+                \"project, please upgrade. The next version of cryptography \"\n+                \"will completely remove support for it.\",\n+                DeprecationWarning\n+            )\n+        else:\n+            raise RuntimeError(\n+                \"You are linking against OpenSSL 0.9.8, which is no longer \"\n+                \"support by the OpenSSL project. You need to upgrade to a \"\n+                \"newer version of OpenSSL.\"\n+            )\n+    elif version < 0x10001000:\n+        warnings.warn(\n+            \"OpenSSL versions less than 1.0.1 are no longer supported by the \"\n+            \"OpenSSL project, please upgrade. A future version of \"\n+            \"cryptography will drop support for these versions of OpenSSL.\",\n+            DeprecationWarning\n+        )\n+\n+\n # OpenSSL is not thread safe until the locks are initialized. We call this\n # method in module scope so that it executes with the import lock. On\n # Pythons < 3.4 this import lock is a global lock, which can prevent a race\n@@ -224,17 +247,4 @@\n # is per module so this approach will not work.\n Binding.init_static_locks()\n \n-if Binding.lib.SSLeay() < 0x10000000:\n-    warnings.warn(\n-        \"OpenSSL version 0.9.8 is no longer supported by the OpenSSL project, \"\n-        \"please upgrade. The next version of cryptography will drop support \"\n-        \"for it.\",\n-        utils.DeprecatedIn12\n-    )\n-elif Binding.lib.SSLeay() < 0x10001000:\n-    warnings.warn(\n-        \"OpenSSL versions less than 1.0.1 are no longer supported by the \"\n-        \"OpenSSL project, please upgrade. A future version of cryptography \"\n-        \"will drop support for these versions.\",\n-        DeprecationWarning\n-    )\n+_verify_openssl_version(Binding.lib.SSLeay())\n", "issue": "Raise an error on openssl 0.9.8\nWith an env var (probably `CRYPTOGRAPHY_ALLOW_OPENSSL_098`) to allow disabling it for this one release.\n\n", "before_files": [{"content": "# This file is dual licensed under the terms of the Apache License, Version\n# 2.0, and the BSD License. See the LICENSE file in the root of this repository\n# for complete details.\n\nfrom __future__ import absolute_import, division, print_function\n\nimport collections\nimport os\nimport threading\nimport types\nimport warnings\n\nfrom cryptography import utils\nfrom cryptography.exceptions import InternalError\nfrom cryptography.hazmat.bindings._openssl import ffi, lib\nfrom cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES\n\n_OpenSSLError = collections.namedtuple(\"_OpenSSLError\",\n                                       [\"code\", \"lib\", \"func\", \"reason\"])\n_OpenSSLErrorWithText = collections.namedtuple(\n    \"_OpenSSLErrorWithText\", [\"code\", \"lib\", \"func\", \"reason\", \"reason_text\"]\n)\n\n\ndef _consume_errors(lib):\n    errors = []\n    while True:\n        code = lib.ERR_get_error()\n        if code == 0:\n            break\n\n        err_lib = lib.ERR_GET_LIB(code)\n        err_func = lib.ERR_GET_FUNC(code)\n        err_reason = lib.ERR_GET_REASON(code)\n\n        errors.append(_OpenSSLError(code, err_lib, err_func, err_reason))\n\n    return errors\n\n\ndef _openssl_assert(lib, ok):\n    if not ok:\n        errors = _consume_errors(lib)\n        errors_with_text = []\n        for err in errors:\n            err_text_reason = ffi.string(\n                lib.ERR_error_string(err.code, ffi.NULL)\n            )\n            errors_with_text.append(\n                _OpenSSLErrorWithText(\n                    err.code, err.lib, err.func, err.reason, err_text_reason\n                )\n            )\n\n        raise InternalError(\n            \"Unknown OpenSSL error. This error is commonly encountered when \"\n            \"another library is not cleaning up the OpenSSL error stack. If \"\n            \"you are using cryptography with another library that uses \"\n            \"OpenSSL try disabling it before reporting a bug. Otherwise \"\n            \"please file an issue at https://github.com/pyca/cryptography/\"\n            \"issues with information on how to reproduce \"\n            \"this. ({0!r})\".format(errors_with_text),\n            errors_with_text\n        )\n\n\ndef ffi_callback(signature, name, **kwargs):\n    \"\"\"Callback dispatcher\n\n    The ffi_callback() dispatcher keeps callbacks compatible between dynamic\n    and static callbacks.\n    \"\"\"\n    def wrapper(func):\n        if lib.Cryptography_STATIC_CALLBACKS:\n            # def_extern() returns a decorator that sets the internal\n            # function pointer and returns the original function unmodified.\n            ffi.def_extern(name=name, **kwargs)(func)\n            callback = getattr(lib, name)\n        else:\n            # callback() wraps the function in a cdata function.\n            callback = ffi.callback(signature, **kwargs)(func)\n        return callback\n    return wrapper\n\n\n@ffi_callback(\"int (*)(unsigned char *, int)\",\n              name=\"Cryptography_rand_bytes\",\n              error=-1)\ndef _osrandom_rand_bytes(buf, size):\n    signed = ffi.cast(\"char *\", buf)\n    result = os.urandom(size)\n    signed[0:size] = result\n    return 1\n\n\n@ffi_callback(\"int (*)(void)\", name=\"Cryptography_rand_status\")\ndef _osrandom_rand_status():\n    return 1\n\n\ndef build_conditional_library(lib, conditional_names):\n    conditional_lib = types.ModuleType(\"lib\")\n    excluded_names = set()\n    for condition, names in conditional_names.items():\n        if not getattr(lib, condition):\n            excluded_names |= set(names)\n\n    for attr in dir(lib):\n        if attr not in excluded_names:\n            setattr(conditional_lib, attr, getattr(lib, attr))\n\n    return conditional_lib\n\n\nclass Binding(object):\n    \"\"\"\n    OpenSSL API wrapper.\n    \"\"\"\n    lib = None\n    ffi = ffi\n    _lib_loaded = False\n    _locks = None\n    _lock_cb_handle = None\n    _init_lock = threading.Lock()\n    _lock_init_lock = threading.Lock()\n\n    _osrandom_engine_id = ffi.new(\"const char[]\", b\"osrandom\")\n    _osrandom_engine_name = ffi.new(\"const char[]\", b\"osrandom_engine\")\n    _osrandom_method = ffi.new(\n        \"RAND_METHOD *\",\n        dict(bytes=_osrandom_rand_bytes,\n             pseudorand=_osrandom_rand_bytes,\n             status=_osrandom_rand_status)\n    )\n\n    def __init__(self):\n        self._ensure_ffi_initialized()\n\n    @classmethod\n    def _register_osrandom_engine(cls):\n        _openssl_assert(cls.lib, cls.lib.ERR_peek_error() == 0)\n\n        engine = cls.lib.ENGINE_new()\n        _openssl_assert(cls.lib, engine != cls.ffi.NULL)\n        try:\n            result = cls.lib.ENGINE_set_id(engine, cls._osrandom_engine_id)\n            _openssl_assert(cls.lib, result == 1)\n            result = cls.lib.ENGINE_set_name(engine, cls._osrandom_engine_name)\n            _openssl_assert(cls.lib, result == 1)\n            result = cls.lib.ENGINE_set_RAND(engine, cls._osrandom_method)\n            _openssl_assert(cls.lib, result == 1)\n            result = cls.lib.ENGINE_add(engine)\n            if result != 1:\n                errors = _consume_errors(cls.lib)\n                _openssl_assert(\n                    cls.lib,\n                    errors[0].reason == cls.lib.ENGINE_R_CONFLICTING_ENGINE_ID\n                )\n\n        finally:\n            result = cls.lib.ENGINE_free(engine)\n            _openssl_assert(cls.lib, result == 1)\n\n    @classmethod\n    def _ensure_ffi_initialized(cls):\n        with cls._init_lock:\n            if not cls._lib_loaded:\n                cls.lib = build_conditional_library(lib, CONDITIONAL_NAMES)\n                cls._lib_loaded = True\n                # initialize the SSL library\n                cls.lib.SSL_library_init()\n                # adds all ciphers/digests for EVP\n                cls.lib.OpenSSL_add_all_algorithms()\n                # loads error strings for libcrypto and libssl functions\n                cls.lib.SSL_load_error_strings()\n                cls._register_osrandom_engine()\n\n    @classmethod\n    def init_static_locks(cls):\n        with cls._lock_init_lock:\n            cls._ensure_ffi_initialized()\n\n            if not cls._lock_cb_handle:\n                wrapper = ffi_callback(\n                    \"void(int, int, const char *, int)\",\n                    name=\"Cryptography_locking_cb\",\n                )\n                cls._lock_cb_handle = wrapper(cls._lock_cb)\n\n            # Use Python's implementation if available, importing _ssl triggers\n            # the setup for this.\n            __import__(\"_ssl\")\n\n            if cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL:\n                return\n\n            # If nothing else has setup a locking callback already, we set up\n            # our own\n            num_locks = cls.lib.CRYPTO_num_locks()\n            cls._locks = [threading.Lock() for n in range(num_locks)]\n\n            cls.lib.CRYPTO_set_locking_callback(cls._lock_cb_handle)\n\n    @classmethod\n    def _lock_cb(cls, mode, n, file, line):\n        lock = cls._locks[n]\n\n        if mode & cls.lib.CRYPTO_LOCK:\n            lock.acquire()\n        elif mode & cls.lib.CRYPTO_UNLOCK:\n            lock.release()\n        else:\n            raise RuntimeError(\n                \"Unknown lock mode {0}: lock={1}, file={2}, line={3}.\".format(\n                    mode, n, file, line\n                )\n            )\n\n\n# OpenSSL is not thread safe until the locks are initialized. We call this\n# method in module scope so that it executes with the import lock. On\n# Pythons < 3.4 this import lock is a global lock, which can prevent a race\n# condition registering the OpenSSL locks. On Python 3.4+ the import lock\n# is per module so this approach will not work.\nBinding.init_static_locks()\n\nif Binding.lib.SSLeay() < 0x10000000:\n    warnings.warn(\n        \"OpenSSL version 0.9.8 is no longer supported by the OpenSSL project, \"\n        \"please upgrade. The next version of cryptography will drop support \"\n        \"for it.\",\n        utils.DeprecatedIn12\n    )\nelif Binding.lib.SSLeay() < 0x10001000:\n    warnings.warn(\n        \"OpenSSL versions less than 1.0.1 are no longer supported by the \"\n        \"OpenSSL project, please upgrade. A future version of cryptography \"\n        \"will drop support for these versions.\",\n        DeprecationWarning\n    )\n", "path": "src/cryptography/hazmat/bindings/openssl/binding.py"}], "after_files": [{"content": "# This file is dual licensed under the terms of the Apache License, Version\n# 2.0, and the BSD License. See the LICENSE file in the root of this repository\n# for complete details.\n\nfrom __future__ import absolute_import, division, print_function\n\nimport collections\nimport os\nimport threading\nimport types\nimport warnings\n\nfrom cryptography.exceptions import InternalError\nfrom cryptography.hazmat.bindings._openssl import ffi, lib\nfrom cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES\n\n_OpenSSLError = collections.namedtuple(\"_OpenSSLError\",\n                                       [\"code\", \"lib\", \"func\", \"reason\"])\n_OpenSSLErrorWithText = collections.namedtuple(\n    \"_OpenSSLErrorWithText\", [\"code\", \"lib\", \"func\", \"reason\", \"reason_text\"]\n)\n\n\ndef _consume_errors(lib):\n    errors = []\n    while True:\n        code = lib.ERR_get_error()\n        if code == 0:\n            break\n\n        err_lib = lib.ERR_GET_LIB(code)\n        err_func = lib.ERR_GET_FUNC(code)\n        err_reason = lib.ERR_GET_REASON(code)\n\n        errors.append(_OpenSSLError(code, err_lib, err_func, err_reason))\n\n    return errors\n\n\ndef _openssl_assert(lib, ok):\n    if not ok:\n        errors = _consume_errors(lib)\n        errors_with_text = []\n        for err in errors:\n            err_text_reason = ffi.string(\n                lib.ERR_error_string(err.code, ffi.NULL)\n            )\n            errors_with_text.append(\n                _OpenSSLErrorWithText(\n                    err.code, err.lib, err.func, err.reason, err_text_reason\n                )\n            )\n\n        raise InternalError(\n            \"Unknown OpenSSL error. This error is commonly encountered when \"\n            \"another library is not cleaning up the OpenSSL error stack. If \"\n            \"you are using cryptography with another library that uses \"\n            \"OpenSSL try disabling it before reporting a bug. Otherwise \"\n            \"please file an issue at https://github.com/pyca/cryptography/\"\n            \"issues with information on how to reproduce \"\n            \"this. ({0!r})\".format(errors_with_text),\n            errors_with_text\n        )\n\n\ndef ffi_callback(signature, name, **kwargs):\n    \"\"\"Callback dispatcher\n\n    The ffi_callback() dispatcher keeps callbacks compatible between dynamic\n    and static callbacks.\n    \"\"\"\n    def wrapper(func):\n        if lib.Cryptography_STATIC_CALLBACKS:\n            # def_extern() returns a decorator that sets the internal\n            # function pointer and returns the original function unmodified.\n            ffi.def_extern(name=name, **kwargs)(func)\n            callback = getattr(lib, name)\n        else:\n            # callback() wraps the function in a cdata function.\n            callback = ffi.callback(signature, **kwargs)(func)\n        return callback\n    return wrapper\n\n\n@ffi_callback(\"int (*)(unsigned char *, int)\",\n              name=\"Cryptography_rand_bytes\",\n              error=-1)\ndef _osrandom_rand_bytes(buf, size):\n    signed = ffi.cast(\"char *\", buf)\n    result = os.urandom(size)\n    signed[0:size] = result\n    return 1\n\n\n@ffi_callback(\"int (*)(void)\", name=\"Cryptography_rand_status\")\ndef _osrandom_rand_status():\n    return 1\n\n\ndef build_conditional_library(lib, conditional_names):\n    conditional_lib = types.ModuleType(\"lib\")\n    excluded_names = set()\n    for condition, names in conditional_names.items():\n        if not getattr(lib, condition):\n            excluded_names |= set(names)\n\n    for attr in dir(lib):\n        if attr not in excluded_names:\n            setattr(conditional_lib, attr, getattr(lib, attr))\n\n    return conditional_lib\n\n\nclass Binding(object):\n    \"\"\"\n    OpenSSL API wrapper.\n    \"\"\"\n    lib = None\n    ffi = ffi\n    _lib_loaded = False\n    _locks = None\n    _lock_cb_handle = None\n    _init_lock = threading.Lock()\n    _lock_init_lock = threading.Lock()\n\n    _osrandom_engine_id = ffi.new(\"const char[]\", b\"osrandom\")\n    _osrandom_engine_name = ffi.new(\"const char[]\", b\"osrandom_engine\")\n    _osrandom_method = ffi.new(\n        \"RAND_METHOD *\",\n        dict(bytes=_osrandom_rand_bytes,\n             pseudorand=_osrandom_rand_bytes,\n             status=_osrandom_rand_status)\n    )\n\n    def __init__(self):\n        self._ensure_ffi_initialized()\n\n    @classmethod\n    def _register_osrandom_engine(cls):\n        _openssl_assert(cls.lib, cls.lib.ERR_peek_error() == 0)\n\n        engine = cls.lib.ENGINE_new()\n        _openssl_assert(cls.lib, engine != cls.ffi.NULL)\n        try:\n            result = cls.lib.ENGINE_set_id(engine, cls._osrandom_engine_id)\n            _openssl_assert(cls.lib, result == 1)\n            result = cls.lib.ENGINE_set_name(engine, cls._osrandom_engine_name)\n            _openssl_assert(cls.lib, result == 1)\n            result = cls.lib.ENGINE_set_RAND(engine, cls._osrandom_method)\n            _openssl_assert(cls.lib, result == 1)\n            result = cls.lib.ENGINE_add(engine)\n            if result != 1:\n                errors = _consume_errors(cls.lib)\n                _openssl_assert(\n                    cls.lib,\n                    errors[0].reason == cls.lib.ENGINE_R_CONFLICTING_ENGINE_ID\n                )\n\n        finally:\n            result = cls.lib.ENGINE_free(engine)\n            _openssl_assert(cls.lib, result == 1)\n\n    @classmethod\n    def _ensure_ffi_initialized(cls):\n        with cls._init_lock:\n            if not cls._lib_loaded:\n                cls.lib = build_conditional_library(lib, CONDITIONAL_NAMES)\n                cls._lib_loaded = True\n                # initialize the SSL library\n                cls.lib.SSL_library_init()\n                # adds all ciphers/digests for EVP\n                cls.lib.OpenSSL_add_all_algorithms()\n                # loads error strings for libcrypto and libssl functions\n                cls.lib.SSL_load_error_strings()\n                cls._register_osrandom_engine()\n\n    @classmethod\n    def init_static_locks(cls):\n        with cls._lock_init_lock:\n            cls._ensure_ffi_initialized()\n\n            if not cls._lock_cb_handle:\n                wrapper = ffi_callback(\n                    \"void(int, int, const char *, int)\",\n                    name=\"Cryptography_locking_cb\",\n                )\n                cls._lock_cb_handle = wrapper(cls._lock_cb)\n\n            # Use Python's implementation if available, importing _ssl triggers\n            # the setup for this.\n            __import__(\"_ssl\")\n\n            if cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL:\n                return\n\n            # If nothing else has setup a locking callback already, we set up\n            # our own\n            num_locks = cls.lib.CRYPTO_num_locks()\n            cls._locks = [threading.Lock() for n in range(num_locks)]\n\n            cls.lib.CRYPTO_set_locking_callback(cls._lock_cb_handle)\n\n    @classmethod\n    def _lock_cb(cls, mode, n, file, line):\n        lock = cls._locks[n]\n\n        if mode & cls.lib.CRYPTO_LOCK:\n            lock.acquire()\n        elif mode & cls.lib.CRYPTO_UNLOCK:\n            lock.release()\n        else:\n            raise RuntimeError(\n                \"Unknown lock mode {0}: lock={1}, file={2}, line={3}.\".format(\n                    mode, n, file, line\n                )\n            )\n\n\ndef _verify_openssl_version(version):\n    if version < 0x10000000:\n        if os.environ.get(\"CRYPTOGRAPHY_ALLOW_OPENSSL_098\"):\n            warnings.warn(\n                \"OpenSSL version 0.9.8 is no longer supported by the OpenSSL \"\n                \"project, please upgrade. The next version of cryptography \"\n                \"will completely remove support for it.\",\n                DeprecationWarning\n            )\n        else:\n            raise RuntimeError(\n                \"You are linking against OpenSSL 0.9.8, which is no longer \"\n                \"support by the OpenSSL project. You need to upgrade to a \"\n                \"newer version of OpenSSL.\"\n            )\n    elif version < 0x10001000:\n        warnings.warn(\n            \"OpenSSL versions less than 1.0.1 are no longer supported by the \"\n            \"OpenSSL project, please upgrade. A future version of \"\n            \"cryptography will drop support for these versions of OpenSSL.\",\n            DeprecationWarning\n        )\n\n\n# OpenSSL is not thread safe until the locks are initialized. We call this\n# method in module scope so that it executes with the import lock. On\n# Pythons < 3.4 this import lock is a global lock, which can prevent a race\n# condition registering the OpenSSL locks. On Python 3.4+ the import lock\n# is per module so this approach will not work.\nBinding.init_static_locks()\n\n_verify_openssl_version(Binding.lib.SSLeay())\n", "path": "src/cryptography/hazmat/bindings/openssl/binding.py"}]}