1# coding: utf-8
2from __future__ import unicode_literals, division, absolute_import, print_function
3
4from .. import ffi
5from .._ffi import buffer_from_bytes, byte_string_from_buffer, null
6from .._types import str_cls
7
8if ffi() == 'cffi':
9 from ._libcrypto_cffi import (
10 libcrypto,
11 version as libcrypto_version,
12 version_info as libcrypto_version_info
13 )
14else:
15 from ._libcrypto_ctypes import (
16 libcrypto,
17 version as libcrypto_version,
18 version_info as libcrypto_version_info
19 )
20
21
22__all__ = [
23 'get_first_openssl_error',
24 'handle_openssl_error',
25 'libcrypto',
26 'libcrypto_legacy_support',
27 'libcrypto_version',
28 'libcrypto_version_info',
29 'LibcryptoConst',
30 'peek_openssl_error',
31 'raise_openssl_error',
32]
33
34
35_encoding = 'utf-8'
36_fallback_encodings = ['utf-8', 'cp1252']
37
38
39if libcrypto_version_info < (1, 1):
40 libcrypto.ERR_load_crypto_strings()
41libcrypto.OPENSSL_config(null())
42
43
44# This enables legacy algorithms in OpenSSL 3.0, such as RC2, etc
45# which are used by various tests and some old protocols and things
46# like PKCS12
47libcrypto_legacy_support = True
48if libcrypto_version_info >= (3, ):
49
50 libcrypto.OSSL_PROVIDER_load(null(), "legacy".encode("ascii"))
51 libcrypto.OSSL_PROVIDER_load(null(), "default".encode("ascii"))
52
53 if libcrypto.OSSL_PROVIDER_available(null(), "legacy".encode("ascii")) == 0:
54 libcrypto_legacy_support = False
55
56
57def _try_decode(value):
58
59 try:
60 return str_cls(value, _encoding)
61
62 # If the "correct" encoding did not work, try some defaults, and then just
63 # obliterate characters that we can't seen to decode properly
64 except (UnicodeDecodeError):
65 for encoding in _fallback_encodings:
66 try:
67 return str_cls(value, encoding, errors='strict')
68 except (UnicodeDecodeError):
69 pass
70
71 return str_cls(value, errors='replace')
72
73
74def get_first_openssl_error():
75 """
76 Returns the first OpenSSL error code and drains the rest of the error queue.
77
78 :return:
79 An integer error code
80 """
81
82 error_num = libcrypto.ERR_get_error()
83 while libcrypto.ERR_get_error():
84 pass
85
86 return error_num
87
88
89def raise_openssl_error(error_num, exception_class=None):
90 """
91 Raises an exception for an OpenSSL error code.
92
93 :param error_num:
94 An integer error code
95
96 :param exception_class:
97 The exception class to use
98
99 :raises:
100 OSError - when exception_class is not specified
101 """
102
103 if exception_class is None:
104 exception_class = OSError
105
106 buffer = buffer_from_bytes(120)
107 libcrypto.ERR_error_string(error_num, buffer)
108
109 # Since we are dealing with a string, it is NULL terminated
110 error_string = byte_string_from_buffer(buffer)
111
112 raise exception_class(_try_decode(error_string))
113
114
115def handle_openssl_error(result, exception_class=None):
116 """
117 Checks if an error occurred, and if so throws an OSError containing the
118 last OpenSSL error message
119
120 :param result:
121 An integer result code - 1 or greater indicates success
122
123 :param exception_class:
124 The exception class to use for the exception if an error occurred
125
126 :raises:
127 OSError - when an OpenSSL error occurs
128 """
129
130 if result > 0:
131 return
132
133 error_num = get_first_openssl_error()
134 raise_openssl_error(error_num, exception_class)
135
136
137def peek_openssl_error():
138 """
139 Peeks into the error stack and pulls out the lib, func and reason
140
141 :return:
142 A three-element tuple of integers (lib, func, reason)
143 """
144
145 error = libcrypto.ERR_peek_error()
146 if libcrypto_version_info < (3, 0):
147 lib = int((error >> 24) & 0xff)
148 func = int((error >> 12) & 0xfff)
149 reason = int(error & 0xfff)
150 else:
151 lib = int((error >> 23) & 0xff)
152 # OpenSSL 3.0 removed ERR_GET_FUNC()
153 func = 0
154 reason = int(error & 0x7fffff)
155
156 return (lib, func, reason)
157
158
159class LibcryptoConst():
160 EVP_CTRL_SET_RC2_KEY_BITS = 3
161
162 SSLEAY_VERSION = 0
163
164 RSA_PKCS1_PADDING = 1
165 RSA_NO_PADDING = 3
166 RSA_PKCS1_OAEP_PADDING = 4
167
168 # OpenSSL 0.9.x
169 EVP_MD_CTX_FLAG_PSS_MDLEN = -1
170
171 # OpenSSL 1.x.x
172 EVP_PKEY_CTRL_RSA_PADDING = 0x1001
173 RSA_PKCS1_PSS_PADDING = 6
174 EVP_PKEY_CTRL_RSA_PSS_SALTLEN = 0x1002
175 EVP_PKEY_RSA = 6
176 EVP_PKEY_OP_SIGN = 1 << 3
177 EVP_PKEY_OP_VERIFY = 1 << 4
178
179 NID_X9_62_prime256v1 = 415
180 NID_secp384r1 = 715
181 NID_secp521r1 = 716
182
183 OPENSSL_EC_NAMED_CURVE = 1
184
185 DH_GENERATOR_2 = 2