Skip to content

Commit c61fa7d

Browse files
committed
honor OpenSSL fail-open contracts
1 parent a5ee960 commit c61fa7d

4 files changed

Lines changed: 156 additions & 7 deletions

File tree

src/ssl.c

Lines changed: 124 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20129,19 +20129,45 @@ int wolfSSL_RAND_poll(void)
2012920129
int wolfSSL_RAND_status(void)
2013020130
{
2013120131
int ret = WOLFSSL_SUCCESS;
20132+
int useGlobalRng = 1;
2013220133
#ifndef WOLFSSL_NO_OPENSSL_RAND_CB
2013320134
if (wolfSSL_RAND_InitMutex() == 0 &&
2013420135
wc_LockMutex(&gRandMethodMutex) == 0) {
20135-
if (gRandMethods && gRandMethods->status)
20136+
if (gRandMethods && gRandMethods->status) {
2013620137
ret = gRandMethods->status();
20138+
useGlobalRng = 0;
20139+
}
2013720140
wc_UnLockMutex(&gRandMethodMutex);
2013820141
}
2013920142
else {
2014020143
ret = WOLFSSL_FAILURE;
20144+
useGlobalRng = 0;
20145+
}
20146+
#endif
20147+
20148+
/* Drive the global RNG so init / DRBG state failures (mutex
20149+
* acquisition, reseed required, corrupted state) surface to the
20150+
* caller. DRBG output is deterministic between reseeds, so this
20151+
* does not directly probe the entropy source. */
20152+
#ifdef HAVE_GLOBAL_RNG
20153+
if (useGlobalRng) {
20154+
if (wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) {
20155+
ret = WOLFSSL_FAILURE;
20156+
}
20157+
else if (wc_LockMutex(&globalRNGMutex) != 0) {
20158+
ret = WOLFSSL_FAILURE;
20159+
}
20160+
else {
20161+
byte b = 0;
20162+
int genRet = wc_RNG_GenerateBlock(&globalRNG, &b, 1);
20163+
wc_UnLockMutex(&globalRNGMutex);
20164+
ForceZero(&b, 1);
20165+
if (genRet != 0)
20166+
ret = WOLFSSL_FAILURE;
20167+
}
2014120168
}
20142-
#else
20143-
/* wolfCrypt provides enough seed internally, so return success */
2014420169
#endif
20170+
(void)useGlobalRng;
2014520171
return ret;
2014620172
}
2014720173

@@ -20173,14 +20199,106 @@ void wolfSSL_RAND_screen(void)
2017320199
}
2017420200
#endif
2017520201

20202+
#ifndef WOLFSSL_RAND_LOAD_FILE_BUF_SZ
20203+
#define WOLFSSL_RAND_LOAD_FILE_BUF_SZ 256
20204+
#endif
20205+
#ifndef WOLFSSL_RAND_LOAD_FILE_MAX_BYTES
20206+
#define WOLFSSL_RAND_LOAD_FILE_MAX_BYTES (1L << 20)
20207+
#endif
20208+
2017620209
int wolfSSL_RAND_load_file(const char* fname, long len)
2017720210
{
20211+
#if !defined(NO_FILESYSTEM) && defined(HAVE_HASHDRBG)
20212+
XFILE f;
20213+
long maxBytes;
20214+
long readSoFar = 0;
20215+
int ret = 0;
20216+
#ifndef WOLFSSL_SMALL_STACK
20217+
unsigned char buf[WOLFSSL_RAND_LOAD_FILE_BUF_SZ];
20218+
#else
20219+
unsigned char* buf;
20220+
#endif
20221+
20222+
WOLFSSL_ENTER("wolfSSL_RAND_load_file");
20223+
20224+
if (fname == NULL)
20225+
return WOLFSSL_FATAL_ERROR;
20226+
20227+
/* OpenSSL semantics: RAND_load_file(file, -1) reads up to an
20228+
* implementation-defined maximum. WOLFSSL_RAND_LOAD_FILE_MAX_BYTES
20229+
* caps the read so callers passing -1 to ingest a seed file aren't
20230+
* silently truncated at a small default. */
20231+
maxBytes = (len < 0) ? WOLFSSL_RAND_LOAD_FILE_MAX_BYTES : len;
20232+
if (maxBytes == 0)
20233+
return 0;
20234+
20235+
f = XFOPEN(fname, "rb");
20236+
if (f == XBADFILE) {
20237+
WOLFSSL_MSG("RAND_load_file: cannot open file");
20238+
return WOLFSSL_FATAL_ERROR;
20239+
}
20240+
20241+
#ifdef WOLFSSL_SMALL_STACK
20242+
buf = (unsigned char*)XMALLOC(WOLFSSL_RAND_LOAD_FILE_BUF_SZ, NULL,
20243+
DYNAMIC_TYPE_TMP_BUFFER);
20244+
if (buf == NULL) {
20245+
XFCLOSE(f);
20246+
return WOLFSSL_FATAL_ERROR;
20247+
}
20248+
#endif
20249+
#ifdef WOLFSSL_CHECK_MEM_ZERO
20250+
wc_MemZero_Add("wolfSSL_RAND_load_file buf", buf,
20251+
WOLFSSL_RAND_LOAD_FILE_BUF_SZ);
20252+
#endif
20253+
20254+
if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) {
20255+
WOLFSSL_MSG("RAND_load_file: global RNG not available");
20256+
ret = WOLFSSL_FATAL_ERROR;
20257+
goto cleanup;
20258+
}
20259+
20260+
while (readSoFar < maxBytes) {
20261+
size_t toRead = (size_t)((maxBytes - readSoFar) <
20262+
WOLFSSL_RAND_LOAD_FILE_BUF_SZ
20263+
? (maxBytes - readSoFar) : WOLFSSL_RAND_LOAD_FILE_BUF_SZ);
20264+
size_t n = XFREAD(buf, 1, toRead, f);
20265+
if (n == 0)
20266+
break;
20267+
if (wc_LockMutex(&globalRNGMutex) != 0) {
20268+
ret = WOLFSSL_FATAL_ERROR;
20269+
break;
20270+
}
20271+
if (wc_RNG_DRBG_Reseed(&globalRNG, buf, (word32)n) != 0) {
20272+
wc_UnLockMutex(&globalRNGMutex);
20273+
WOLFSSL_MSG("RAND_load_file: DRBG reseed failed");
20274+
ret = WOLFSSL_FATAL_ERROR;
20275+
break;
20276+
}
20277+
wc_UnLockMutex(&globalRNGMutex);
20278+
readSoFar += (long)n;
20279+
}
20280+
20281+
cleanup:
20282+
XFCLOSE(f);
20283+
ForceZero(buf, WOLFSSL_RAND_LOAD_FILE_BUF_SZ);
20284+
#ifdef WOLFSSL_SMALL_STACK
20285+
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
20286+
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
20287+
wc_MemZero_Check(buf, WOLFSSL_RAND_LOAD_FILE_BUF_SZ);
20288+
#endif
20289+
20290+
if (ret < 0)
20291+
return WOLFSSL_FATAL_ERROR;
20292+
return (int)readSoFar;
20293+
#else
20294+
/* Without HAVE_HASHDRBG / filesystem support there is no way to feed
20295+
* external entropy to the wolfCrypt RNG; return success so callers
20296+
* in those configurations are not broken. */
2017820297
(void)fname;
20179-
/* wolfCrypt provides enough entropy internally or will report error */
2018020298
if (len == -1)
2018120299
return 1024;
20182-
else
20183-
return (int)len;
20300+
return (int)len;
20301+
#endif
2018420302
}
2018520303

2018620304
#endif /* OPENSSL_EXTRA */

src/ssl_p7p12.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,7 @@ int wolfSSL_PEM_write_bio_PKCS7(WOLFSSL_BIO* bio, PKCS7* p7)
988988
outputHead = (byte*)XMALLOC(outputHeadSz, bio->heap,
989989
DYNAMIC_TYPE_TMP_BUFFER);
990990
if (outputHead == NULL)
991-
return MEMORY_E;
991+
return WOLFSSL_FAILURE;
992992

993993
outputFoot = (byte*)XMALLOC(outputFootSz, bio->heap,
994994
DYNAMIC_TYPE_TMP_BUFFER);

tests/api/test_ossl_rand.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,35 @@ int test_wolfSSL_RAND_bytes(void)
249249
return EXPECT_RESULT();
250250
}
251251

252+
int test_wolfSSL_RAND_load_file(void)
253+
{
254+
EXPECT_DECLS;
255+
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && \
256+
defined(HAVE_HASHDRBG)
257+
/* NULL fname must fail. */
258+
ExpectIntEQ(RAND_load_file(NULL, 32), -1);
259+
260+
/* A non-existent path must fail. */
261+
ExpectIntEQ(RAND_load_file("/no/such/file/wolfssl_rand_load_file_test",
262+
32), -1);
263+
264+
#if defined(__linux__) || defined(__FreeBSD__)
265+
/* Reading from the OS entropy source returns the requested byte count. */
266+
ExpectIntEQ(RAND_load_file("/dev/urandom", 32), 32);
267+
268+
/* len < 0 caps at the implementation default (1 MB, matching OpenSSL's
269+
* RAND_LOAD_BUF_SIZE). */
270+
ExpectIntEQ(RAND_load_file("/dev/urandom", -1), 1L << 20);
271+
272+
/* len == 0 short-circuits to 0. */
273+
ExpectIntEQ(RAND_load_file("/dev/urandom", 0), 0);
274+
#endif
275+
276+
RAND_cleanup();
277+
#endif
278+
return EXPECT_RESULT();
279+
}
280+
252281
int test_wolfSSL_RAND(void)
253282
{
254283
EXPECT_DECLS;

tests/api/test_ossl_rand.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,14 @@
2626

2727
int test_wolfSSL_RAND_set_rand_method(void);
2828
int test_wolfSSL_RAND_bytes(void);
29+
int test_wolfSSL_RAND_load_file(void);
2930
int test_wolfSSL_RAND(void);
3031
int test_wolfSSL_RAND_poll(void);
3132

3233
#define TEST_OSSL_RAND_DECLS \
3334
TEST_DECL_GROUP("ossl_rand", test_wolfSSL_RAND_set_rand_method), \
3435
TEST_DECL_GROUP("ossl_rand", test_wolfSSL_RAND_bytes), \
36+
TEST_DECL_GROUP("ossl_rand", test_wolfSSL_RAND_load_file), \
3537
TEST_DECL_GROUP("ossl_rand", test_wolfSSL_RAND), \
3638
TEST_DECL_GROUP("ossl_rand", test_wolfSSL_RAND_poll)
3739

0 commit comments

Comments
 (0)