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

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

62 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 os 

8import sys 

9import threading 

10import types 

11import typing 

12import warnings 

13 

14import cryptography 

15from cryptography.exceptions import InternalError 

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

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

18 

19 

20def _openssl_assert( 

21 ok: bool, 

22 errors: list[openssl.OpenSSLError] | None = None, 

23) -> None: 

24 if not ok: 

25 if errors is None: 

26 errors = openssl.capture_error_stack() 

27 

28 raise InternalError( 

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

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

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

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

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

34 "issues with information on how to reproduce " 

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

36 errors, 

37 ) 

38 

39 

40def build_conditional_library( 

41 lib: typing.Any, 

42 conditional_names: dict[str, typing.Callable[[], list[str]]], 

43) -> typing.Any: 

44 conditional_lib = types.ModuleType("lib") 

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

46 excluded_names = set() 

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

48 if not getattr(lib, condition): 

49 excluded_names.update(names_cb()) 

50 

51 for attr in dir(lib): 

52 if attr not in excluded_names: 

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

54 

55 return conditional_lib 

56 

57 

58class Binding: 

59 """ 

60 OpenSSL API wrapper. 

61 """ 

62 

63 lib: typing.ClassVar = None 

64 ffi = _openssl.ffi 

65 _lib_loaded = False 

66 _init_lock = threading.Lock() 

67 _legacy_provider: typing.Any = ffi.NULL 

68 _default_provider: typing.Any = ffi.NULL 

69 

70 def __init__(self) -> None: 

71 self._ensure_ffi_initialized() 

72 

73 def _enable_fips(self) -> None: 

74 # This function enables FIPS mode for OpenSSL 3.0.0 on installs that 

75 # have the FIPS provider installed properly. 

76 _openssl_assert(self.lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER) 

77 self._base_provider = self.lib.OSSL_PROVIDER_load( 

78 self.ffi.NULL, b"base" 

79 ) 

80 _openssl_assert(self._base_provider != self.ffi.NULL) 

81 self.lib._fips_provider = self.lib.OSSL_PROVIDER_load( 

82 self.ffi.NULL, b"fips" 

83 ) 

84 _openssl_assert(self.lib._fips_provider != self.ffi.NULL) 

85 

86 res = self.lib.EVP_default_properties_enable_fips(self.ffi.NULL, 1) 

87 _openssl_assert(res == 1) 

88 

89 @classmethod 

90 def _ensure_ffi_initialized(cls) -> None: 

91 with cls._init_lock: 

92 if not cls._lib_loaded: 

93 cls.lib = build_conditional_library( 

94 _openssl.lib, CONDITIONAL_NAMES 

95 ) 

96 cls._lib_loaded = True 

97 

98 @classmethod 

99 def init_static_locks(cls) -> None: 

100 cls._ensure_ffi_initialized() 

101 

102 

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

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

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

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

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

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

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

110 # ImportError if they do not 

111 so_package_version = _openssl.ffi.string( 

112 _openssl.lib.CRYPTOGRAPHY_PACKAGE_VERSION 

113 ) 

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

115 raise ImportError( 

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

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

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

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

120 "Loaded python version: {}, shared object version: {}".format( 

121 version, so_package_version 

122 ) 

123 ) 

124 

125 _openssl_assert( 

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

127 ) 

128 

129 

130_verify_package_version(cryptography.__version__) 

131 

132Binding.init_static_locks() 

133 

134if ( 

135 sys.platform == "win32" 

136 and os.environ.get("PROCESSOR_ARCHITEW6432") is not None 

137): 

138 warnings.warn( 

139 "You are using cryptography on a 32-bit Python on a 64-bit Windows " 

140 "Operating System. Cryptography will be significantly faster if you " 

141 "switch to using a 64-bit Python.", 

142 UserWarning, 

143 stacklevel=2, 

144 )