Skip to content

Commit 2abbab4

Browse files
committed
Add error reporting and fail for EAGAIN
Add error reporting strings for various error cases. This gives us much nicer and understandable error messages. SYS_getrandom() EAGAIN is now an error. Cryptography refuses to initialize its osrandom engine when the Kernel's CPRNG hasn't been seeded yet. Signed-off-by: Christian Heimes <[email protected]>
1 parent 8575fb2 commit 2abbab4

File tree

2 files changed

+216
-32
lines changed

2 files changed

+216
-32
lines changed

src/_cffi_src/openssl/src/osrandom_engine.c

Lines changed: 184 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ static int osrandom_init(ENGINE *e) {
3030
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
3131
return 1;
3232
} else {
33+
ERR_Cryptography_OSRandom_error(
34+
CRYPTOGRAPHY_OSRANDOM_F_INIT,
35+
CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT,
36+
__FILE__, __LINE__
37+
);
3338
return 0;
3439
}
3540
}
@@ -40,8 +45,11 @@ static int osrandom_rand_bytes(unsigned char *buffer, int size) {
4045
}
4146

4247
if (!CryptGenRandom(hCryptProv, (DWORD)size, buffer)) {
43-
CRYPTOGRAPHY_OSRANDOM_put_error(
44-
"osrandom_engine.py:CryptGenRandom()");
48+
ERR_Cryptography_OSRandom_error(
49+
CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
50+
CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM,
51+
__FILE__, __LINE__
52+
);
4553
return 0;
4654
}
4755
return 1;
@@ -52,6 +60,11 @@ static int osrandom_finish(ENGINE *e) {
5260
hCryptProv = 0;
5361
return 1;
5462
} else {
63+
ERR_Cryptography_OSRandom_error(
64+
CRYPTOGRAPHY_OSRANDOM_F_FINISH,
65+
CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT,
66+
__FILE__, __LINE__
67+
);
5568
return 0;
5669
}
5770
}
@@ -83,8 +96,11 @@ static int osrandom_rand_bytes(unsigned char *buffer, int size) {
8396
len = size > 256 ? 256 : size;
8497
res = getentropy(buffer, len);
8598
if (res < 0) {
86-
CRYPTOGRAPHY_OSRANDOM_put_error(
87-
"osrandom_engine.py:getentropy()");
99+
ERR_Cryptography_OSRandom_error(
100+
CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
101+
CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED,
102+
__FILE__, __LINE__
103+
);
88104
return 0;
89105
}
90106
buffer += len;
@@ -166,8 +182,11 @@ static int dev_urandom_fd(void) {
166182
n = close(fd);
167183
} while (n < 0 && errno == EINTR);
168184
}
169-
CRYPTOGRAPHY_OSRANDOM_put_error(
170-
"osrandom_engine.py:dev_urandom_fd()");
185+
ERR_Cryptography_OSRandom_error(
186+
CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD,
187+
CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED,
188+
__FILE__, __LINE__
189+
);
171190
return -1;
172191
}
173192

@@ -186,8 +205,11 @@ static int dev_urandom_read(unsigned char *buffer, int size) {
186205
} while (n < 0 && errno == EINTR);
187206

188207
if (n <= 0) {
189-
CRYPTOGRAPHY_OSRANDOM_put_error(
190-
"osrandom_engine.py:dev_urandom_read()");
208+
ERR_Cryptography_OSRandom_error(
209+
CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ,
210+
CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED,
211+
__FILE__, __LINE__
212+
);
191213
return 0;
192214
}
193215
buffer += n;
@@ -221,28 +243,51 @@ static void dev_urandom_close(void) {
221243
#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM
222244
static const char *Cryptography_osrandom_engine_name = "osrandom_engine getrandom()";
223245

224-
static int getrandom_works = -1;
246+
static int getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT;
225247

226248
static int osrandom_init(ENGINE *e) {
227249
/* We try to detect working getrandom until we succeed. */
228-
if (getrandom_works != 1) {
250+
if (getrandom_works != CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS) {
229251
long n;
230252
char dest[1];
231253
n = syscall(SYS_getrandom, dest, sizeof(dest), GRND_NONBLOCK);
232-
if (n < 0) {
233-
/* Can fail with:
234-
* - ENOSYS: Kernel does not support the syscall.
235-
* - ENOPERM: seccomp prevents syscall.
236-
* - EAGAIN: Kernel CRPNG has not been seeded yet.
237-
* EINTR cannot occur for buflen < 256.
238-
*/
239-
getrandom_works = 0;
254+
if (n == sizeof(dest)) {
255+
getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS;
240256
} else {
241-
getrandom_works = 1;
257+
int e = errno;
258+
switch(e) {
259+
case ENOSYS:
260+
/* Fallback: Kernel does not support the syscall. */
261+
getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK;
262+
break;
263+
case EPERM:
264+
/* Fallback: seccomp prevents syscall */
265+
getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK;
266+
break;
267+
case EAGAIN:
268+
/* Failure: Kernel CRPNG has not been seeded yet */
269+
ERR_Cryptography_OSRandom_error(
270+
CRYPTOGRAPHY_OSRANDOM_F_INIT,
271+
CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_EAGAIN,
272+
__FILE__, __LINE__
273+
);
274+
getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED;
275+
break;
276+
default:
277+
/* EINTR cannot occur for buflen < 256. */
278+
ERR_Cryptography_OSRandom_error(
279+
CRYPTOGRAPHY_OSRANDOM_F_INIT,
280+
CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED,
281+
"errno", e
282+
);
283+
getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED;
284+
break;
285+
}
242286
}
243287
}
288+
244289
/* fallback to dev urandom */
245-
if (getrandom_works == 0) {
290+
if (getrandom_works == CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK) {
246291
int fd = dev_urandom_fd();
247292
if (fd < 0) {
248293
return 0;
@@ -252,25 +297,45 @@ static int osrandom_init(ENGINE *e) {
252297
}
253298

254299
static int osrandom_rand_bytes(unsigned char *buffer, int size) {
255-
if (getrandom_works == 1) {
256-
long n;
300+
long n;
301+
302+
switch(getrandom_works) {
303+
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
304+
ERR_Cryptography_OSRandom_error(
305+
CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
306+
CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED,
307+
__FILE__, __LINE__
308+
);
309+
return 0;
310+
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
311+
ERR_Cryptography_OSRandom_error(
312+
CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
313+
CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT,
314+
__FILE__, __LINE__
315+
);
316+
return 0;
317+
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
318+
return dev_urandom_read(buffer, size);
319+
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
257320
while (size > 0) {
258321
do {
259322
n = syscall(SYS_getrandom, buffer, size, GRND_NONBLOCK);
260323
} while (n < 0 && errno == EINTR);
261324

262325
if (n <= 0) {
263-
CRYPTOGRAPHY_OSRANDOM_put_error(
264-
"osrandom_engine.py:SYS_getrandom");
326+
ERR_Cryptography_OSRandom_error(
327+
CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
328+
CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED,
329+
__FILE__, __LINE__
330+
);
265331
return 0;
266332
}
267333
buffer += n;
268334
size -= n;
269335
}
270336
return 1;
271-
} else {
272-
return dev_urandom_read(buffer, size);
273337
}
338+
return 0; /* unreachable */
274339
}
275340

276341
static int osrandom_finish(ENGINE *e) {
@@ -279,17 +344,31 @@ static int osrandom_finish(ENGINE *e) {
279344
}
280345

281346
static int osrandom_rand_status(void) {
282-
if ((getrandom_works != 1) && (urandom_cache.fd < 0)) {
347+
switch(getrandom_works) {
348+
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
349+
return 0;
350+
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
283351
return 0;
352+
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
353+
return urandom_cache.fd >= 0;
354+
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
355+
return 1;
284356
}
285-
return 1;
357+
return 0; /* unreachable */
286358
}
287359

288360
static const char *osurandom_get_implementation(void) {
289-
if (getrandom_works == 1) {
361+
switch(getrandom_works) {
362+
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
363+
return "<failed>";
364+
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
365+
return "<not initialized>";
366+
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
367+
return "/dev/urandom";
368+
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
290369
return "getrandom";
291370
}
292-
return "/dev/urandom";
371+
return "<invalid>"; /* unreachable */
293372
}
294373
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM */
295374

@@ -384,10 +463,85 @@ static int osrandom_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
384463
}
385464
}
386465

466+
/* error reporting */
467+
#define ERR_FUNC(func) ERR_PACK(0, func, 0)
468+
#define ERR_REASON(reason) ERR_PACK(0, 0, reason)
469+
470+
static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_lib_name[] = {
471+
{0, "osrandom_engine"},
472+
{0, NULL}
473+
};
474+
475+
static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_str_funcs[] = {
476+
{ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_INIT),
477+
"osrandom_init"},
478+
{ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES),
479+
"osrandom_rand_bytes"},
480+
{ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_FINISH),
481+
"osrandom_finish"},
482+
{ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD),
483+
"dev_urandom_fd"},
484+
{ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ),
485+
"dev_urandom_read"},
486+
{0, NULL}
487+
};
488+
489+
static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_str_reasons[] = {
490+
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT),
491+
"CryptAcquireContext() failed."},
492+
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM),
493+
"CryptGenRandom() failed."},
494+
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT),
495+
"CryptReleaseContext() failed."},
496+
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED),
497+
"getentropy() failed"},
498+
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED),
499+
"open('/dev/urandom') failed."},
500+
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED),
501+
"Reading from /dev/urandom fd failed."},
502+
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED),
503+
"getrandom() initialization failed."},
504+
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_EAGAIN),
505+
"getrandom() initialization failed with EAGAIN. Most likely Kernel "
506+
"CPRNG is not seeded yet."},
507+
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED),
508+
"getrandom() initialization failed with unexpected errno."},
509+
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED),
510+
"getrandom() syscall failed."},
511+
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT),
512+
"getrandom() engine was not properly initialized."},
513+
{0, NULL}
514+
};
515+
516+
static int Cryptography_OSRandom_lib_error_code = 0;
517+
518+
static void ERR_load_Cryptography_OSRandom_strings(void)
519+
{
520+
if (Cryptography_OSRandom_lib_error_code == 0) {
521+
Cryptography_OSRandom_lib_error_code = ERR_get_next_error_library();
522+
ERR_load_strings(Cryptography_OSRandom_lib_error_code,
523+
CRYPTOGRAPHY_OSRANDOM_lib_name);
524+
ERR_load_strings(Cryptography_OSRandom_lib_error_code,
525+
CRYPTOGRAPHY_OSRANDOM_str_funcs);
526+
ERR_load_strings(Cryptography_OSRandom_lib_error_code,
527+
CRYPTOGRAPHY_OSRANDOM_str_reasons);
528+
}
529+
}
530+
531+
static void ERR_Cryptography_OSRandom_error(int function, int reason,
532+
char *file, int line)
533+
{
534+
ERR_PUT_error(Cryptography_OSRandom_lib_error_code, function, reason,
535+
file, line);
536+
}
537+
387538
/* Returns 1 if successfully added, 2 if engine has previously been added,
388539
and 0 for error. */
389540
int Cryptography_add_osrandom_engine(void) {
390541
ENGINE *e;
542+
543+
ERR_load_Cryptography_OSRandom_strings();
544+
391545
e = ENGINE_by_id(Cryptography_osrandom_engine_id);
392546
if (e != NULL) {
393547
ENGINE_free(e);

src/_cffi_src/openssl/src/osrandom_engine.h

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,38 @@
5151
#define CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM 1
5252
#endif
5353

54-
#define CRYPTOGRAPHY_OSRANDOM_put_error(funcname) \
55-
ERR_put_error(ERR_LIB_RAND, 0, 0, funcname, 0)
54+
enum {
55+
CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED = -2,
56+
CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT,
57+
CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK,
58+
CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS
59+
};
5660

5761
/* engine ctrl */
5862
#define CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION ENGINE_CMD_BASE
63+
64+
/* error reporting */
65+
static void ERR_load_Cryptography_OSRandom_strings(void);
66+
static void ERR_Cryptography_OSRandom_error(int function, int reason,
67+
char *file, int line);
68+
69+
#define CRYPTOGRAPHY_OSRANDOM_F_INIT 100
70+
#define CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES 101
71+
#define CRYPTOGRAPHY_OSRANDOM_F_FINISH 102
72+
#define CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD 300
73+
#define CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ 301
74+
75+
#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT 100
76+
#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM 101
77+
#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT 102
78+
79+
#define CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED 200
80+
81+
#define CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED 300
82+
#define CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED 301
83+
84+
#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED 400
85+
#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_EAGAIN 401
86+
#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED 402
87+
#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED 403
88+
#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT 404

0 commit comments

Comments
 (0)