Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/hazmat/bindings/openssl/binding.py: 73%
73 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 07:26 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 07:26 +0000
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.
5from __future__ import annotations
7import os
8import sys
9import threading
10import types
11import typing
12import warnings
14import cryptography
15from cryptography.exceptions import InternalError
16from cryptography.hazmat.bindings._rust import _openssl, openssl
17from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES
20def _openssl_assert(
21 lib,
22 ok: bool,
23 errors: list[openssl.OpenSSLError] | None = None,
24) -> None:
25 if not ok:
26 if errors is None:
27 errors = openssl.capture_error_stack()
29 raise InternalError(
30 "Unknown OpenSSL error. This error is commonly encountered when "
31 "another library is not cleaning up the OpenSSL error stack. If "
32 "you are using cryptography with another library that uses "
33 "OpenSSL try disabling it before reporting a bug. Otherwise "
34 "please file an issue at https://github.com/pyca/cryptography/"
35 "issues with information on how to reproduce "
36 f"this. ({errors!r})",
37 errors,
38 )
41def _legacy_provider_error(loaded: bool) -> None:
42 if not loaded:
43 raise RuntimeError(
44 "OpenSSL 3.0's legacy provider failed to load. This is a fatal "
45 "error by default, but cryptography supports running without "
46 "legacy algorithms by setting the environment variable "
47 "CRYPTOGRAPHY_OPENSSL_NO_LEGACY. If you did not expect this error,"
48 " you have likely made a mistake with your OpenSSL configuration."
49 )
52def build_conditional_library(
53 lib: typing.Any,
54 conditional_names: dict[str, typing.Callable[[], list[str]]],
55) -> typing.Any:
56 conditional_lib = types.ModuleType("lib")
57 conditional_lib._original_lib = lib # type: ignore[attr-defined]
58 excluded_names = set()
59 for condition, names_cb in conditional_names.items():
60 if not getattr(lib, condition):
61 excluded_names.update(names_cb())
63 for attr in dir(lib):
64 if attr not in excluded_names:
65 setattr(conditional_lib, attr, getattr(lib, attr))
67 return conditional_lib
70class Binding:
71 """
72 OpenSSL API wrapper.
73 """
75 lib: typing.ClassVar = None
76 ffi = _openssl.ffi
77 _lib_loaded = False
78 _init_lock = threading.Lock()
79 _legacy_provider: typing.Any = ffi.NULL
80 _legacy_provider_loaded = False
81 _default_provider: typing.Any = ffi.NULL
83 def __init__(self) -> None:
84 self._ensure_ffi_initialized()
86 def _enable_fips(self) -> None:
87 # This function enables FIPS mode for OpenSSL 3.0.0 on installs that
88 # have the FIPS provider installed properly.
89 _openssl_assert(self.lib, self.lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER)
90 self._base_provider = self.lib.OSSL_PROVIDER_load(
91 self.ffi.NULL, b"base"
92 )
93 _openssl_assert(self.lib, self._base_provider != self.ffi.NULL)
94 self.lib._fips_provider = self.lib.OSSL_PROVIDER_load(
95 self.ffi.NULL, b"fips"
96 )
97 _openssl_assert(self.lib, self.lib._fips_provider != self.ffi.NULL)
99 res = self.lib.EVP_default_properties_enable_fips(self.ffi.NULL, 1)
100 _openssl_assert(self.lib, res == 1)
102 @classmethod
103 def _ensure_ffi_initialized(cls) -> None:
104 with cls._init_lock:
105 if not cls._lib_loaded:
106 cls.lib = build_conditional_library(
107 _openssl.lib, CONDITIONAL_NAMES
108 )
109 cls._lib_loaded = True
110 # As of OpenSSL 3.0.0 we must register a legacy cipher provider
111 # to get RC2 (needed for junk asymmetric private key
112 # serialization), RC4, Blowfish, IDEA, SEED, etc. These things
113 # are ugly legacy, but we aren't going to get rid of them
114 # any time soon.
115 if cls.lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER:
116 if not os.environ.get("CRYPTOGRAPHY_OPENSSL_NO_LEGACY"):
117 cls._legacy_provider = cls.lib.OSSL_PROVIDER_load(
118 cls.ffi.NULL, b"legacy"
119 )
120 cls._legacy_provider_loaded = (
121 cls._legacy_provider != cls.ffi.NULL
122 )
123 _legacy_provider_error(cls._legacy_provider_loaded)
125 cls._default_provider = cls.lib.OSSL_PROVIDER_load(
126 cls.ffi.NULL, b"default"
127 )
128 _openssl_assert(
129 cls.lib, cls._default_provider != cls.ffi.NULL
130 )
132 @classmethod
133 def init_static_locks(cls) -> None:
134 cls._ensure_ffi_initialized()
137def _verify_package_version(version: str) -> None:
138 # Occasionally we run into situations where the version of the Python
139 # package does not match the version of the shared object that is loaded.
140 # This may occur in environments where multiple versions of cryptography
141 # are installed and available in the python path. To avoid errors cropping
142 # up later this code checks that the currently imported package and the
143 # shared object that were loaded have the same version and raise an
144 # ImportError if they do not
145 so_package_version = _openssl.ffi.string(
146 _openssl.lib.CRYPTOGRAPHY_PACKAGE_VERSION
147 )
148 if version.encode("ascii") != so_package_version:
149 raise ImportError(
150 "The version of cryptography does not match the loaded "
151 "shared object. This can happen if you have multiple copies of "
152 "cryptography installed in your Python path. Please try creating "
153 "a new virtual environment to resolve this issue. "
154 "Loaded python version: {}, shared object version: {}".format(
155 version, so_package_version
156 )
157 )
159 _openssl_assert(
160 _openssl.lib,
161 _openssl.lib.OpenSSL_version_num() == openssl.openssl_version(),
162 )
165_verify_package_version(cryptography.__version__)
167Binding.init_static_locks()
169if (
170 sys.platform == "win32"
171 and os.environ.get("PROCESSOR_ARCHITEW6432") is not None
172):
173 warnings.warn(
174 "You are using cryptography on a 32-bit Python on a 64-bit Windows "
175 "Operating System. Cryptography will be significantly faster if you "
176 "switch to using a 64-bit Python.",
177 UserWarning,
178 stacklevel=2,
179 )