Skip to content

Commit 76c7843

Browse files
reaperhulkalex
authored andcommitted
support NO_ENGINE (pyca#4763)
* support OPENSSL_NO_ENGINE * support some new openssl config args * sigh
1 parent 01a5179 commit 76c7843

File tree

11 files changed

+155
-18
lines changed

11 files changed

+155
-18
lines changed

.travis.yml

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ matrix:
5151
env: TOXENV=py27 OPENSSL=1.1.1a
5252
- python: 3.7
5353
env: TOXENV=py37 OPENSSL=1.1.1a
54+
- python: 3.7
55+
env: TOXENV=py37 OPENSSL=1.1.1a OPENSSL_CONFIG_FLAGS=no-engine
5456
- python: 3.7
5557
env: TOXENV=py37 LIBRESSL=2.6.5
5658
- python: 3.7

.travis/install.sh

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
set -e
44
set -x
55

6+
SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}")
7+
68
shlib_sed() {
79
# modify the shlib version to a unique one to make sure the dynamic
810
# linker doesn't load the system one.
@@ -14,12 +16,12 @@ shlib_sed() {
1416
# download, compile, and install if it's not already present via travis
1517
# cache
1618
if [ -n "${OPENSSL}" ]; then
17-
OPENSSL_DIR="ossl-2/${OPENSSL}"
19+
. "$SCRIPT_DIR/openssl_config.sh"
1820
if [[ ! -f "$HOME/$OPENSSL_DIR/bin/openssl" ]]; then
1921
curl -O "https://www.openssl.org/source/openssl-${OPENSSL}.tar.gz"
2022
tar zxf "openssl-${OPENSSL}.tar.gz"
2123
pushd "openssl-${OPENSSL}"
22-
./config shared no-ssl2 no-ssl3 -fPIC --prefix="$HOME/$OPENSSL_DIR"
24+
./config $OPENSSL_CONFIG_FLAGS -fPIC --prefix="$HOME/$OPENSSL_DIR"
2325
shlib_sed
2426
make depend
2527
make -j"$(nproc)"

.travis/openssl_config.sh

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/bash
2+
3+
set -e
4+
set -x
5+
6+
DEFAULT_CONFIG_FLAGS="shared no-ssl2 no-ssl3"
7+
if [ -n "${OPENSSL_CONFIG_FLAGS}" ]; then
8+
OPENSSL_CONFIG_FLAGS="$DEFAULT_CONFIG_FLAGS $OPENSSL_CONFIG_FLAGS"
9+
else
10+
OPENSSL_CONFIG_FLAGS=$DEFAULT_CONFIG_FLAGS
11+
fi
12+
CONFIG_HASH=$(echo "$OPENSSL_CONFIG_FLAGS" | sha1sum | sed 's/ .*$//')
13+
OPENSSL_DIR="ossl-2/${OPENSSL}${CONFIG_HASH}"

.travis/run.sh

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
#!/bin/bash -ex
22

3+
SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}")
4+
35
if [[ "${TOXENV}" == "pypy" ]]; then
46
PYENV_ROOT="$HOME/.pyenv"
57
PATH="$PYENV_ROOT/bin:$PATH"
68
eval "$(pyenv init -)"
79
fi
810
if [ -n "${LIBRESSL}" ]; then
9-
OPENSSL=$LIBRESSL
10-
export CFLAGS="-Werror -Wno-error=deprecated-declarations -Wno-error=discarded-qualifiers -Wno-error=unused-function"
11+
LIBRESSL_DIR="ossl-2/${LIBRESSL}"
12+
export CFLAGS="-Werror -Wno-error=deprecated-declarations -Wno-error=discarded-qualifiers -Wno-error=unused-function -I$HOME/$LIBRESSL_DIR/include"
13+
export PATH="$HOME/$LIBRESSL_DIR/bin:$PATH"
14+
export LDFLAGS="-L$HOME/$LIBRESSL_DIR/lib -Wl,-rpath=$HOME/$LIBRESSL_DIR/lib"
1115
fi
1216

1317
if [ -n "${OPENSSL}" ]; then
14-
OPENSSL_DIR="ossl-2/${OPENSSL}"
15-
18+
. "$SCRIPT_DIR/openssl_config.sh"
1619
export PATH="$HOME/$OPENSSL_DIR/bin:$PATH"
1720
export CFLAGS="${CFLAGS} -I$HOME/$OPENSSL_DIR/include"
1821
# rpath on linux will cause it to use an absolute path so we don't need to

CHANGELOG.rst

+4-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ Changelog
2121
which had been deprecated for nearly 3 years. Use
2222
:attr:`~cryptography.x509.Certificate.serial_number` instead.
2323
* Add support for easily mapping an object identifier to its elliptic curve
24-
class via :func:`~cryptography.hazmat.primitives.asymmetric.ec.get_curve_for_oid`.
24+
class via
25+
:func:`~cryptography.hazmat.primitives.asymmetric.ec.get_curve_for_oid`.
26+
* Add support for OpenSSL when compiled with the ``no-engine``
27+
(``OPENSSL_NO_ENGINE``) flag.
2528

2629
.. _v2-5:
2730

src/_cffi_src/openssl/engine.py

+68
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
static const unsigned int ENGINE_METHOD_RAND;
2828
2929
static const int ENGINE_R_CONFLICTING_ENGINE_ID;
30+
static const long Cryptography_HAS_ENGINE;
3031
"""
3132

3233
FUNCTIONS = """
@@ -69,4 +70,71 @@
6970
"""
7071

7172
CUSTOMIZATIONS = """
73+
#ifdef OPENSSL_NO_ENGINE
74+
static const long Cryptography_HAS_ENGINE = 0;
75+
typedef int (*ENGINE_GEN_INT_FUNC_PTR)(ENGINE *);
76+
typedef void *ENGINE_CTRL_FUNC_PTR;
77+
typedef void *ENGINE_LOAD_KEY_PTR;
78+
typedef void *ENGINE_CIPHERS_PTR;
79+
typedef void *ENGINE_DIGESTS_PTR;
80+
typedef struct ENGINE_CMD_DEFN_st {
81+
unsigned int cmd_num;
82+
const char *cmd_name;
83+
const char *cmd_desc;
84+
unsigned int cmd_flags;
85+
} ENGINE_CMD_DEFN;
86+
87+
/* This section is so osrandom_engine.c can successfully compile even
88+
when engine support is disabled */
89+
#define ENGINE_CMD_BASE 0
90+
#define ENGINE_CMD_FLAG_NO_INPUT 0
91+
#define ENGINE_F_ENGINE_CTRL 0
92+
#define ENGINE_R_INVALID_ARGUMENT 0
93+
#define ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED 0
94+
int (*ENGINE_set_cmd_defns)(ENGINE *, const ENGINE_CMD_DEFN *) = NULL;
95+
96+
static const unsigned int ENGINE_METHOD_RAND = 0;
97+
static const int ENGINE_R_CONFLICTING_ENGINE_ID = 0;
98+
99+
ENGINE *(*ENGINE_get_first)(void) = NULL;
100+
ENGINE *(*ENGINE_get_last)(void) = NULL;
101+
int (*ENGINE_add)(ENGINE *) = NULL;
102+
int (*ENGINE_remove)(ENGINE *) = NULL;
103+
ENGINE *(*ENGINE_by_id)(const char *) = NULL;
104+
int (*ENGINE_init)(ENGINE *) = NULL;
105+
int (*ENGINE_finish)(ENGINE *) = NULL;
106+
void (*ENGINE_load_builtin_engines)(void) = NULL;
107+
ENGINE *(*ENGINE_get_default_RAND)(void) = NULL;
108+
int (*ENGINE_set_default_RAND)(ENGINE *) = NULL;
109+
int (*ENGINE_register_RAND)(ENGINE *) = NULL;
110+
void (*ENGINE_unregister_RAND)(ENGINE *) = NULL;
111+
void (*ENGINE_register_all_RAND)(void) = NULL;
112+
int (*ENGINE_ctrl)(ENGINE *, int, long, void *, void (*)(void)) = NULL;
113+
int (*ENGINE_ctrl_cmd)(ENGINE *, const char *, long, void *,
114+
void (*)(void), int) = NULL;
115+
int (*ENGINE_ctrl_cmd_string)(ENGINE *, const char *, const char *,
116+
int) = NULL;
117+
118+
ENGINE *(*ENGINE_new)(void) = NULL;
119+
int (*ENGINE_free)(ENGINE *) = NULL;
120+
int (*ENGINE_up_ref)(ENGINE *) = NULL;
121+
int (*ENGINE_set_id)(ENGINE *, const char *) = NULL;
122+
int (*ENGINE_set_name)(ENGINE *, const char *) = NULL;
123+
int (*ENGINE_set_RAND)(ENGINE *, const RAND_METHOD *) = NULL;
124+
int (*ENGINE_set_destroy_function)(ENGINE *, ENGINE_GEN_INT_FUNC_PTR) = NULL;
125+
int (*ENGINE_set_init_function)(ENGINE *, ENGINE_GEN_INT_FUNC_PTR) = NULL;
126+
int (*ENGINE_set_finish_function)(ENGINE *, ENGINE_GEN_INT_FUNC_PTR) = NULL;
127+
int (*ENGINE_set_ctrl_function)(ENGINE *, ENGINE_CTRL_FUNC_PTR) = NULL;
128+
const char *(*ENGINE_get_id)(const ENGINE *) = NULL;
129+
const char *(*ENGINE_get_name)(const ENGINE *) = NULL;
130+
const RAND_METHOD *(*ENGINE_get_RAND)(const ENGINE *) = NULL;
131+
132+
void (*ENGINE_add_conf_module)(void) = NULL;
133+
/* these became macros in 1.1.0 */
134+
void (*ENGINE_load_openssl)(void) = NULL;
135+
void (*ENGINE_load_dynamic)(void) = NULL;
136+
void (*ENGINE_cleanup)(void) = NULL;
137+
#else
138+
static const long Cryptography_HAS_ENGINE = 1;
139+
#endif
72140
"""

src/_cffi_src/openssl/ssl.py

-1
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,6 @@
334334
const COMP_METHOD *SSL_get_current_compression(SSL *);
335335
const COMP_METHOD *SSL_get_current_expansion(SSL *);
336336
const char *SSL_COMP_get_name(const COMP_METHOD *);
337-
int SSL_CTX_set_client_cert_engine(SSL_CTX *, ENGINE *);
338337
339338
unsigned long SSL_set_mode(SSL *, unsigned long);
340339
unsigned long SSL_get_mode(SSL *);

src/cryptography/hazmat/backends/openssl/backend.py

+9-8
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,15 @@ def _get_osurandom_engine(self):
150150
self.openssl_assert(res == 1)
151151

152152
def activate_osrandom_engine(self):
153-
# Unregister and free the current engine.
154-
self.activate_builtin_random()
155-
with self._get_osurandom_engine() as e:
156-
# Set the engine as the default RAND provider.
157-
res = self._lib.ENGINE_set_default_RAND(e)
158-
self.openssl_assert(res == 1)
159-
# Reset the RNG to use the new engine.
160-
self._lib.RAND_cleanup()
153+
if self._lib.Cryptography_HAS_ENGINE:
154+
# Unregister and free the current engine.
155+
self.activate_builtin_random()
156+
with self._get_osurandom_engine() as e:
157+
# Set the engine as the default RAND provider.
158+
res = self._lib.ENGINE_set_default_RAND(e)
159+
self.openssl_assert(res == 1)
160+
# Reset the RNG to use the new engine.
161+
self._lib.RAND_cleanup()
161162

162163
def osrandom_engine_implementation(self):
163164
buf = self._ffi.new("char[]", 64)

src/cryptography/hazmat/bindings/openssl/_conditional.py

+42
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,47 @@ def cryptography_has_evp_r_memory_limit_exceeded():
341341
]
342342

343343

344+
def cryptography_has_engine():
345+
return [
346+
"ENGINE_get_first",
347+
"ENGINE_get_last",
348+
"ENGINE_add",
349+
"ENGINE_remove",
350+
"ENGINE_by_id",
351+
"ENGINE_init",
352+
"ENGINE_finish",
353+
"ENGINE_load_builtin_engines",
354+
"ENGINE_get_default_RAND",
355+
"ENGINE_set_default_RAND",
356+
"ENGINE_register_RAND",
357+
"ENGINE_unregister_RAND",
358+
"ENGINE_register_all_RAND",
359+
"ENGINE_ctrl",
360+
"ENGINE_ctrl_cmd",
361+
"ENGINE_ctrl_cmd_string",
362+
"ENGINE_new",
363+
"ENGINE_free",
364+
"ENGINE_up_ref",
365+
"ENGINE_set_id",
366+
"ENGINE_set_name",
367+
"ENGINE_set_RAND",
368+
"ENGINE_set_destroy_function",
369+
"ENGINE_set_init_function",
370+
"ENGINE_set_finish_function",
371+
"ENGINE_set_ctrl_function",
372+
"ENGINE_get_id",
373+
"ENGINE_get_name",
374+
"ENGINE_get_RAND",
375+
"ENGINE_add_conf_module",
376+
"ENGINE_load_openssl",
377+
"ENGINE_load_dynamic",
378+
"ENGINE_cleanup",
379+
"ENGINE_METHOD_RAND",
380+
"ENGINE_R_CONFLICTING_ENGINE_ID",
381+
"Cryptography_add_osrandom_engine",
382+
]
383+
384+
344385
# This is a mapping of
345386
# {condition: function-returning-names-dependent-on-that-condition} so we can
346387
# loop over them and delete unsupported names at runtime. It will be removed
@@ -412,4 +453,5 @@ def cryptography_has_evp_r_memory_limit_exceeded():
412453
"Cryptography_HAS_EVP_R_MEMORY_LIMIT_EXCEEDED": (
413454
cryptography_has_evp_r_memory_limit_exceeded
414455
),
456+
"Cryptography_HAS_ENGINE": cryptography_has_engine,
415457
}

src/cryptography/hazmat/bindings/openssl/binding.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ def _register_osrandom_engine(cls):
115115
# reliably clear the error queue. Once we clear it here we will
116116
# error on any subsequent unexpected item in the stack.
117117
cls.lib.ERR_clear_error()
118-
result = cls.lib.Cryptography_add_osrandom_engine()
119-
_openssl_assert(cls.lib, result in (1, 2))
118+
if cls.lib.Cryptography_HAS_ENGINE:
119+
result = cls.lib.Cryptography_add_osrandom_engine()
120+
_openssl_assert(cls.lib, result in (1, 2))
120121

121122
@classmethod
122123
def _ensure_ffi_initialized(cls):

tests/hazmat/backends/test_openssl.py

+3
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ def test_bn_to_int(self):
170170
assert backend._bn_to_int(bn) == 0
171171

172172

173+
@pytest.mark.skipif(
174+
backend._lib.Cryptography_HAS_ENGINE == 0,
175+
reason="Requires OpenSSL with ENGINE support")
173176
class TestOpenSSLRandomEngine(object):
174177
def setup(self):
175178
# The default RAND engine is global and shared between

0 commit comments

Comments
 (0)