123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- # This file is dual licensed under the terms of the Apache License, Version
- # 2.0, and the BSD License. See the LICENSE file in the root of this repository
- # for complete details.
- from __future__ import annotations
- import os
- import sys
- import threading
- import types
- import typing
- import warnings
- import cryptography
- from cryptography.exceptions import InternalError
- from cryptography.hazmat.bindings._rust import _openssl, openssl
- from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES
- def _openssl_assert(ok: bool) -> None:
- if not ok:
- errors = openssl.capture_error_stack()
- raise InternalError(
- "Unknown OpenSSL error. This error is commonly encountered when "
- "another library is not cleaning up the OpenSSL error stack. If "
- "you are using cryptography with another library that uses "
- "OpenSSL try disabling it before reporting a bug. Otherwise "
- "please file an issue at https://github.com/pyca/cryptography/"
- "issues with information on how to reproduce "
- f"this. ({errors!r})",
- errors,
- )
- def build_conditional_library(
- lib: typing.Any,
- conditional_names: dict[str, typing.Callable[[], list[str]]],
- ) -> typing.Any:
- conditional_lib = types.ModuleType("lib")
- conditional_lib._original_lib = lib # type: ignore[attr-defined]
- excluded_names = set()
- for condition, names_cb in conditional_names.items():
- if not getattr(lib, condition):
- excluded_names.update(names_cb())
- for attr in dir(lib):
- if attr not in excluded_names:
- setattr(conditional_lib, attr, getattr(lib, attr))
- return conditional_lib
- class Binding:
- """
- OpenSSL API wrapper.
- """
- lib: typing.ClassVar = None
- ffi = _openssl.ffi
- _lib_loaded = False
- _init_lock = threading.Lock()
- def __init__(self) -> None:
- self._ensure_ffi_initialized()
- @classmethod
- def _ensure_ffi_initialized(cls) -> None:
- with cls._init_lock:
- if not cls._lib_loaded:
- cls.lib = build_conditional_library(
- _openssl.lib, CONDITIONAL_NAMES
- )
- cls._lib_loaded = True
- @classmethod
- def init_static_locks(cls) -> None:
- cls._ensure_ffi_initialized()
- def _verify_package_version(version: str) -> None:
- # Occasionally we run into situations where the version of the Python
- # package does not match the version of the shared object that is loaded.
- # This may occur in environments where multiple versions of cryptography
- # are installed and available in the python path. To avoid errors cropping
- # up later this code checks that the currently imported package and the
- # shared object that were loaded have the same version and raise an
- # ImportError if they do not
- so_package_version = _openssl.ffi.string(
- _openssl.lib.CRYPTOGRAPHY_PACKAGE_VERSION
- )
- if version.encode("ascii") != so_package_version:
- raise ImportError(
- "The version of cryptography does not match the loaded "
- "shared object. This can happen if you have multiple copies of "
- "cryptography installed in your Python path. Please try creating "
- "a new virtual environment to resolve this issue. "
- f"Loaded python version: {version}, "
- f"shared object version: {so_package_version}"
- )
- _openssl_assert(
- _openssl.lib.OpenSSL_version_num() == openssl.openssl_version(),
- )
- _verify_package_version(cryptography.__version__)
- Binding.init_static_locks()
- if (
- sys.platform == "win32"
- and os.environ.get("PROCESSOR_ARCHITEW6432") is not None
- ):
- warnings.warn(
- "You are using cryptography on a 32-bit Python on a 64-bit Windows "
- "Operating System. Cryptography will be significantly faster if you "
- "switch to using a 64-bit Python.",
- UserWarning,
- stacklevel=2,
- )
|