Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/cryptography/hazmat/bindings/openssl/binding.py: 92%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

48 statements  

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 

5from __future__ import annotations 

6 

7import threading 

8import types 

9import typing 

10from collections.abc import Callable, Mapping 

11 

12import cryptography 

13from cryptography.exceptions import InternalError 

14from cryptography.hazmat.bindings._rust import _openssl, openssl 

15from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES 

16 

17 

18def _openssl_assert(ok: bool) -> None: 

19 if not ok: 

20 errors = openssl.capture_error_stack() 

21 

22 raise InternalError( 

23 "Unknown OpenSSL error. This error is commonly encountered when " 

24 "another library is not cleaning up the OpenSSL error stack. If " 

25 "you are using cryptography with another library that uses " 

26 "OpenSSL try disabling it before reporting a bug. Otherwise " 

27 "please file an issue at https://github.com/pyca/cryptography/" 

28 "issues with information on how to reproduce " 

29 f"this. ({errors!r})", 

30 errors, 

31 ) 

32 

33 

34def build_conditional_library( 

35 lib: typing.Any, 

36 conditional_names: Mapping[str, Callable[[], list[str]]], 

37) -> typing.Any: 

38 conditional_lib = types.ModuleType("lib") 

39 conditional_lib._original_lib = lib # type: ignore[attr-defined] 

40 excluded_names = set() 

41 for condition, names_cb in conditional_names.items(): 

42 if not getattr(lib, condition): 

43 excluded_names.update(names_cb()) 

44 

45 for attr in dir(lib): 

46 if attr not in excluded_names: 

47 setattr(conditional_lib, attr, getattr(lib, attr)) 

48 

49 return conditional_lib 

50 

51 

52class Binding: 

53 """ 

54 OpenSSL API wrapper. 

55 """ 

56 

57 lib: typing.ClassVar[typing.Any] = None 

58 ffi: typing.Any = _openssl.ffi 

59 _lib_loaded = False 

60 _init_lock = threading.Lock() 

61 

62 def __init__(self) -> None: 

63 self._ensure_ffi_initialized() 

64 

65 @classmethod 

66 def _ensure_ffi_initialized(cls) -> None: 

67 with cls._init_lock: 

68 if not cls._lib_loaded: 

69 cls.lib = build_conditional_library( 

70 _openssl.lib, CONDITIONAL_NAMES 

71 ) 

72 cls._lib_loaded = True 

73 

74 @classmethod 

75 def init_static_locks(cls) -> None: 

76 cls._ensure_ffi_initialized() 

77 

78 

79def _verify_package_version(version: str) -> None: 

80 # Occasionally we run into situations where the version of the Python 

81 # package does not match the version of the shared object that is loaded. 

82 # This may occur in environments where multiple versions of cryptography 

83 # are installed and available in the python path. To avoid errors cropping 

84 # up later this code checks that the currently imported package and the 

85 # shared object that were loaded have the same version and raise an 

86 # ImportError if they do not 

87 so_package_version = _openssl.ffi.string( 

88 _openssl.lib.CRYPTOGRAPHY_PACKAGE_VERSION 

89 ) 

90 if version.encode("ascii") != so_package_version: 

91 raise ImportError( 

92 "The version of cryptography does not match the loaded " 

93 "shared object. This can happen if you have multiple copies of " 

94 "cryptography installed in your Python path. Please try creating " 

95 "a new virtual environment to resolve this issue. " 

96 f"Loaded python version: {version}, " 

97 f"shared object version: {so_package_version}" 

98 ) 

99 

100 _openssl_assert( 

101 _openssl.lib.OpenSSL_version_num() == openssl.openssl_version(), 

102 ) 

103 

104 

105_verify_package_version(cryptography.__version__) 

106 

107Binding.init_static_locks()