Skip to content

Commit fbf099c

Browse files
committed
honor OpenSSL fail-open contracts
1 parent 8907979 commit fbf099c

4 files changed

Lines changed: 146 additions & 8 deletions

File tree

src/ssl.c

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20130,17 +20130,40 @@ int wolfSSL_RAND_poll(void)
2013020130
{
2013120131
int ret = WOLFSSL_SUCCESS;
2013220132
#ifndef WOLFSSL_NO_OPENSSL_RAND_CB
20133+
int customMethodChecked = 0;
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+
customMethodChecked = 1;
20139+
}
2013720140
wc_UnLockMutex(&gRandMethodMutex);
2013820141
}
2013920142
else {
20140-
ret = WOLFSSL_FAILURE;
20143+
return WOLFSSL_FAILURE;
20144+
}
20145+
if (customMethodChecked)
20146+
return ret;
20147+
#endif
20148+
20149+
/* Drive the global RNG so init / DRBG state failures (mutex
20150+
* acquisition, reseed required, corrupted state) surface to the
20151+
* caller. DRBG output is deterministic between reseeds, so this
20152+
* does not directly probe the entropy source. */
20153+
#ifdef HAVE_GLOBAL_RNG
20154+
if (wolfSSL_RAND_Init() != WOLFSSL_SUCCESS)
20155+
return WOLFSSL_FAILURE;
20156+
{
20157+
byte b = 0;
20158+
int genRet;
20159+
if (wc_LockMutex(&globalRNGMutex) != 0)
20160+
return WOLFSSL_FAILURE;
20161+
genRet = wc_RNG_GenerateBlock(&globalRNG, &b, 1);
20162+
wc_UnLockMutex(&globalRNGMutex);
20163+
ForceZero(&b, 1);
20164+
if (genRet != 0)
20165+
return WOLFSSL_FAILURE;
2014120166
}
20142-
#else
20143-
/* wolfCrypt provides enough seed internally, so return success */
2014420167
#endif
2014520168
return ret;
2014620169
}
@@ -20175,12 +20198,96 @@ void wolfSSL_RAND_screen(void)
2017520198

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

2018620293
#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)