Skip to content

Commit 807f437

Browse files
committed
osrandom_engine
* Fix naming bug caused by search 'n replace mistake * Make it easier to override osrandom auto-detection * Add engine ctrl and backend API to get implementation from ENGINE Signed-off-by: Christian Heimes <[email protected]>
1 parent 6ed7f91 commit 807f437

File tree

5 files changed

+133
-62
lines changed

5 files changed

+133
-62
lines changed

src/_cffi_src/openssl/src/osrandom_engine.c

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ static int osrandom_rand_status(void) {
6161
return 1;
6262
}
6363
}
64+
65+
static const char* osurandom_get_implementation(void) {
66+
return "CryptGenRandom";
67+
}
68+
6469
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM */
6570

6671
/****************************************************************************
@@ -89,12 +94,16 @@ static int osrandom_finish(ENGINE *e) {
8994
static int osrandom_rand_status(void) {
9095
return 1;
9196
}
92-
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM */
97+
98+
static const char* osurandom_get_implementation(void) {
99+
return "CCRandomGenerateBytes";
100+
}
101+
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_CC_RANDOM */
93102

94103
/****************************************************************************
95104
* BSD getentropy
96105
*/
97-
#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM
106+
#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY
98107
static const char *Cryptography_osrandom_engine_name = "osrandom_engine getentropy()";
99108

100109
static int osrandom_init(ENGINE *e) {
@@ -109,7 +118,7 @@ static int osrandom_rand_bytes(unsigned char *buffer, int size) {
109118
len = size > 256 : 256: size;
110119
res = getentropy(buffer, len);
111120
if (res < 0) {
112-
CRYPTOGRAPHY_OSRANDOM_put_error(
121+
CRYPTOGRAPHY_OSRANDOM_put_error(as
113122
"osrandom_engine.py:getentropy()");
114123
return 0;
115124
}
@@ -126,7 +135,11 @@ static int osrandom_finish(ENGINE *e) {
126135
static int osrandom_rand_status(void) {
127136
return 1;
128137
}
129-
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM */
138+
139+
static const char* osurandom_get_implementation(void) {
140+
return "getentropy";
141+
}
142+
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY */
130143

131144
/****************************************************************************
132145
* /dev/urandom helpers for all non-BSD Unix platforms
@@ -233,13 +246,13 @@ static void dev_urandom_close(void) {
233246
}
234247
}
235248
}
236-
#endif
249+
#endif /* CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM */
237250

238251
/****************************************************************************
239252
* Linux getrandom engine with fallback to dev_urandom
240253
*/
241254

242-
#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY
255+
#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM
243256
static const char *Cryptography_osrandom_engine_name = "osrandom_engine getrandom()";
244257

245258
static int getrandom_works = -1;
@@ -305,7 +318,14 @@ static int osrandom_rand_status(void) {
305318
}
306319
return 1;
307320
}
308-
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY */
321+
322+
static const char* osurandom_get_implementation(void) {
323+
if (getrandom_works == 1) {
324+
return "getrandom";
325+
}
326+
return "/dev/urandom";
327+
}
328+
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM */
309329

310330
/****************************************************************************
311331
* dev_urandom engine for all remaining platforms
@@ -338,8 +358,15 @@ static int osrandom_rand_status(void) {
338358
return 1;
339359
}
340360

361+
static const char* osurandom_get_implementation(void) {
362+
return "/dev/urandom";
363+
}
341364
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM */
342365

366+
/****************************************************************************
367+
* ENGINE boiler plate
368+
*/
369+
343370
/* This replicates the behavior of the OpenSSL FIPS RNG, which returns a
344371
-1 in the event that there is an error when calling RAND_pseudo_bytes. */
345372
static int osrandom_pseudo_rand_bytes(unsigned char *buffer, int size) {
@@ -360,6 +387,39 @@ static RAND_METHOD osrandom_rand = {
360387
osrandom_rand_status,
361388
};
362389

390+
static const ENGINE_CMD_DEFN osrandom_cmd_defns[] = {
391+
{CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION,
392+
"get_implementation",
393+
"Get CPRNG implementation.",
394+
ENGINE_CMD_FLAG_NO_INPUT},
395+
{0, NULL, NULL, 0}
396+
};
397+
398+
static int osrandom_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) {
399+
const char* name;
400+
size_t len;
401+
402+
switch (cmd) {
403+
case CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION:
404+
name = osurandom_get_implementation();
405+
len = strlen(name);
406+
if ((p == NULL) && (i == 0)) {
407+
/* return required buffer len */
408+
return len;
409+
}
410+
if ((p == NULL) || ((size_t)i <= len)) {
411+
/* no buffer or buffer too small */
412+
ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_INVALID_ARGUMENT);
413+
return 0;
414+
}
415+
strncpy((char *)p, name, len);
416+
return len;
417+
default:
418+
ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
419+
return 0;
420+
}
421+
}
422+
363423
/* Returns 1 if successfully added, 2 if engine has previously been added,
364424
and 0 for error. */
365425
int Cryptography_add_osrandom_engine(void) {
@@ -380,7 +440,9 @@ int Cryptography_add_osrandom_engine(void) {
380440
!ENGINE_set_name(e, Cryptography_osrandom_engine_name) ||
381441
!ENGINE_set_RAND(e, &osrandom_rand) ||
382442
!ENGINE_set_init_function(e, osrandom_init) ||
383-
!ENGINE_set_finish_function(e, osrandom_finish)) {
443+
!ENGINE_set_finish_function(e, osrandom_finish) ||
444+
!ENGINE_set_cmd_defns(e, osrandom_cmd_defns) ||
445+
!ENGINE_set_ctrl_function(e, osrandom_ctrl)) {
384446
ENGINE_free(e);
385447
return 0;
386448
}

src/_cffi_src/openssl/src/osrandom_engine.h

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -38,34 +38,33 @@
3838
#define CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM 4
3939
#define CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM 5
4040

41-
/* getentropy is not available in FreeBSD-10.1-RELEASE-p5 and older
42-
* TODO: check NetBSD and Darwin */
43-
#if defined(_WIN32)
44-
/* Windows */
45-
#define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM
46-
#elif defined(__APPLE__) && defined(CRYPTOGRAPHY_HAVE_COMMON_RANDOM_H)
47-
/* OSX 10.10+ */
48-
#define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_CC_RANDOM
49-
#elif defined(BSD) && defined(SYS_getentropy)
50-
/* OpenBSD 5.6+ */
51-
#define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM
52-
#elif defined(__linux__) && defined(SYS_getrandom)
53-
/* Linux 3.4.17+ */
54-
#define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY
55-
#define CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM 1
56-
#endif
57-
58-
/* Fall back to /dev/urandom */
5941
#ifndef CRYPTOGRAPHY_OSRANDOM_ENGINE
60-
#define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM
42+
#if defined(_WIN32)
43+
/* Windows */
44+
#define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM
45+
#elif defined(__APPLE__) && defined(CRYPTOGRAPHY_HAVE_COMMON_RANDOM_H)
46+
/* OSX 10.10+ */
47+
#define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_CC_RANDOM
48+
#elif defined(BSD) && defined(SYS_getentropy)
49+
/* OpenBSD 5.6+ */
50+
#define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY
51+
#elif defined(__linux__) && defined(SYS_getrandom)
52+
/* Linux 3.4.17+ */
53+
#define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM
54+
#else
55+
/* Keep this as last entry, fall back to /dev/urandom */
56+
#define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM
57+
#endif
58+
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE */
59+
60+
/* Fallbacks need /dev/urandom helper functions. */
61+
#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM || \
62+
CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM
6163
#define CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM 1
6264
#endif
6365

64-
/* Open SSL 1.1.0+ has no ERR_R_RAND_LIB */
65-
#ifdef ERR_R_RAND_LIB
66-
#define CRYPTOGRAPHY_OSRANDOM_put_error(funcname) \
67-
ERR_put_error(ERR_LIB_RAND, 0, ERR_R_RAND_LIB, funcname, 0)
68-
#else
69-
#define CRYPTOGRAPHY_OSRANDOM_put_error(funcname) \
66+
#define CRYPTOGRAPHY_OSRANDOM_put_error(funcname) \
7067
ERR_put_error(ERR_LIB_RAND, 0, 0, funcname, 0)
71-
#endif
68+
69+
/* engine ctrl */
70+
#define CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION ENGINE_CMD_BASE

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

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import base64
88
import calendar
99
import collections
10+
import contextlib
1011
import itertools
1112
import sys
1213
from contextlib import contextmanager
@@ -153,28 +154,45 @@ def activate_builtin_random(self):
153154
res = self._lib.ENGINE_finish(e)
154155
self.openssl_assert(res == 1)
155156

156-
def activate_osrandom_engine(self):
157-
# Unregister and free the current engine.
158-
self.activate_builtin_random()
157+
@contextlib.contextmanager
158+
def _get_osurandom_engine(self):
159159
# Fetches an engine by id and returns it. This creates a structural
160160
# reference.
161161
e = self._lib.ENGINE_by_id(self._binding._osrandom_engine_id)
162162
self.openssl_assert(e != self._ffi.NULL)
163163
# Initialize the engine for use. This adds a functional reference.
164164
res = self._lib.ENGINE_init(e)
165165
self.openssl_assert(res == 1)
166-
# Set the engine as the default RAND provider.
167-
res = self._lib.ENGINE_set_default_RAND(e)
168-
self.openssl_assert(res == 1)
169-
# Decrement the structural ref incremented by ENGINE_by_id.
170-
res = self._lib.ENGINE_free(e)
171-
self.openssl_assert(res == 1)
172-
# Decrement the functional ref incremented by ENGINE_init.
173-
res = self._lib.ENGINE_finish(e)
174-
self.openssl_assert(res == 1)
166+
167+
try:
168+
yield e
169+
finally:
170+
# Decrement the structural ref incremented by ENGINE_by_id.
171+
res = self._lib.ENGINE_free(e)
172+
self.openssl_assert(res == 1)
173+
# Decrement the functional ref incremented by ENGINE_init.
174+
res = self._lib.ENGINE_finish(e)
175+
self.openssl_assert(res == 1)
176+
177+
def activate_osrandom_engine(self):
178+
# Unregister and free the current engine.
179+
self.activate_builtin_random()
180+
with self._get_osurandom_engine() as e:
181+
# Set the engine as the default RAND provider.
182+
res = self._lib.ENGINE_set_default_RAND(e)
183+
self.openssl_assert(res == 1)
175184
# Reset the RNG to use the new engine.
176185
self._lib.RAND_cleanup()
177186

187+
def osrandom_engine_implementation(self):
188+
buf = self._ffi.new("char[]", 64)
189+
with self._get_osurandom_engine() as e:
190+
res = self._lib.ENGINE_ctrl_cmd(e, b"get_implementation",
191+
len(buf), buf,
192+
self._ffi.NULL, 0)
193+
self.openssl_assert(res > 0)
194+
return self._ffi.string(buf).decode('ascii')
195+
178196
def openssl_version_text(self):
179197
"""
180198
Friendly string name of the loaded OpenSSL library. This is not

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

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from __future__ import absolute_import, division, print_function
66

77
import collections
8-
import os
98
import threading
109
import types
1110
import warnings
@@ -82,21 +81,6 @@ def wrapper(func):
8281
return wrapper
8382

8483

85-
@ffi_callback("int (*)(unsigned char *, int)",
86-
name="Cryptography_rand_bytes",
87-
error=-1)
88-
def _osrandom_rand_bytes(buf, size):
89-
signed = ffi.cast("char *", buf)
90-
result = os.urandom(size)
91-
signed[0:size] = result
92-
return 1
93-
94-
95-
@ffi_callback("int (*)(void)", name="Cryptography_rand_status")
96-
def _osrandom_rand_status():
97-
return 1
98-
99-
10084
def build_conditional_library(lib, conditional_names):
10185
conditional_lib = types.ModuleType("lib")
10286
excluded_names = set()

tests/hazmat/backends/test_openssl.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,14 @@ def test_activate_builtin_random_already_active(self):
269269
e = backend._lib.ENGINE_get_default_RAND()
270270
assert e == backend._ffi.NULL
271271

272+
def test_osrandom_engine_implementation(self):
273+
name = backend.osrandom_engine_implementation()
274+
assert name
275+
if sys.platform.startswith('linux'):
276+
assert name in ['getrandom', '/dev/urandom']
277+
elif sys.platform == 'win32':
278+
assert name == 'CryptGenRandom'
279+
272280
def test_activate_osrandom_already_default(self):
273281
e = backend._lib.ENGINE_get_default_RAND()
274282
name = backend._lib.ENGINE_get_name(e)

0 commit comments

Comments
 (0)