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