honor OpenSSL fail-open contracts

This commit is contained in:
Jeremiah Mackey
2026-05-07 17:14:41 +00:00
parent a5ee9604c7
commit c61fa7d633
4 changed files with 156 additions and 7 deletions
+124 -6
View File
@@ -20129,19 +20129,45 @@ int wolfSSL_RAND_poll(void)
int wolfSSL_RAND_status(void)
{
int ret = WOLFSSL_SUCCESS;
int useGlobalRng = 1;
#ifndef WOLFSSL_NO_OPENSSL_RAND_CB
if (wolfSSL_RAND_InitMutex() == 0 &&
wc_LockMutex(&gRandMethodMutex) == 0) {
if (gRandMethods && gRandMethods->status)
if (gRandMethods && gRandMethods->status) {
ret = gRandMethods->status();
useGlobalRng = 0;
}
wc_UnLockMutex(&gRandMethodMutex);
}
else {
ret = WOLFSSL_FAILURE;
useGlobalRng = 0;
}
#else
/* wolfCrypt provides enough seed internally, so return success */
#endif
/* Drive the global RNG so init / DRBG state failures (mutex
* acquisition, reseed required, corrupted state) surface to the
* caller. DRBG output is deterministic between reseeds, so this
* does not directly probe the entropy source. */
#ifdef HAVE_GLOBAL_RNG
if (useGlobalRng) {
if (wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) {
ret = WOLFSSL_FAILURE;
}
else if (wc_LockMutex(&globalRNGMutex) != 0) {
ret = WOLFSSL_FAILURE;
}
else {
byte b = 0;
int genRet = wc_RNG_GenerateBlock(&globalRNG, &b, 1);
wc_UnLockMutex(&globalRNGMutex);
ForceZero(&b, 1);
if (genRet != 0)
ret = WOLFSSL_FAILURE;
}
}
#endif
(void)useGlobalRng;
return ret;
}
@@ -20173,14 +20199,106 @@ void wolfSSL_RAND_screen(void)
}
#endif
#ifndef WOLFSSL_RAND_LOAD_FILE_BUF_SZ
#define WOLFSSL_RAND_LOAD_FILE_BUF_SZ 256
#endif
#ifndef WOLFSSL_RAND_LOAD_FILE_MAX_BYTES
#define WOLFSSL_RAND_LOAD_FILE_MAX_BYTES (1L << 20)
#endif
int wolfSSL_RAND_load_file(const char* fname, long len)
{
#if !defined(NO_FILESYSTEM) && defined(HAVE_HASHDRBG)
XFILE f;
long maxBytes;
long readSoFar = 0;
int ret = 0;
#ifndef WOLFSSL_SMALL_STACK
unsigned char buf[WOLFSSL_RAND_LOAD_FILE_BUF_SZ];
#else
unsigned char* buf;
#endif
WOLFSSL_ENTER("wolfSSL_RAND_load_file");
if (fname == NULL)
return WOLFSSL_FATAL_ERROR;
/* OpenSSL semantics: RAND_load_file(file, -1) reads up to an
* implementation-defined maximum. WOLFSSL_RAND_LOAD_FILE_MAX_BYTES
* caps the read so callers passing -1 to ingest a seed file aren't
* silently truncated at a small default. */
maxBytes = (len < 0) ? WOLFSSL_RAND_LOAD_FILE_MAX_BYTES : len;
if (maxBytes == 0)
return 0;
f = XFOPEN(fname, "rb");
if (f == XBADFILE) {
WOLFSSL_MSG("RAND_load_file: cannot open file");
return WOLFSSL_FATAL_ERROR;
}
#ifdef WOLFSSL_SMALL_STACK
buf = (unsigned char*)XMALLOC(WOLFSSL_RAND_LOAD_FILE_BUF_SZ, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (buf == NULL) {
XFCLOSE(f);
return WOLFSSL_FATAL_ERROR;
}
#endif
#ifdef WOLFSSL_CHECK_MEM_ZERO
wc_MemZero_Add("wolfSSL_RAND_load_file buf", buf,
WOLFSSL_RAND_LOAD_FILE_BUF_SZ);
#endif
if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) {
WOLFSSL_MSG("RAND_load_file: global RNG not available");
ret = WOLFSSL_FATAL_ERROR;
goto cleanup;
}
while (readSoFar < maxBytes) {
size_t toRead = (size_t)((maxBytes - readSoFar) <
WOLFSSL_RAND_LOAD_FILE_BUF_SZ
? (maxBytes - readSoFar) : WOLFSSL_RAND_LOAD_FILE_BUF_SZ);
size_t n = XFREAD(buf, 1, toRead, f);
if (n == 0)
break;
if (wc_LockMutex(&globalRNGMutex) != 0) {
ret = WOLFSSL_FATAL_ERROR;
break;
}
if (wc_RNG_DRBG_Reseed(&globalRNG, buf, (word32)n) != 0) {
wc_UnLockMutex(&globalRNGMutex);
WOLFSSL_MSG("RAND_load_file: DRBG reseed failed");
ret = WOLFSSL_FATAL_ERROR;
break;
}
wc_UnLockMutex(&globalRNGMutex);
readSoFar += (long)n;
}
cleanup:
XFCLOSE(f);
ForceZero(buf, WOLFSSL_RAND_LOAD_FILE_BUF_SZ);
#ifdef WOLFSSL_SMALL_STACK
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
wc_MemZero_Check(buf, WOLFSSL_RAND_LOAD_FILE_BUF_SZ);
#endif
if (ret < 0)
return WOLFSSL_FATAL_ERROR;
return (int)readSoFar;
#else
/* Without HAVE_HASHDRBG / filesystem support there is no way to feed
* external entropy to the wolfCrypt RNG; return success so callers
* in those configurations are not broken. */
(void)fname;
/* wolfCrypt provides enough entropy internally or will report error */
if (len == -1)
return 1024;
else
return (int)len;
return (int)len;
#endif
}
#endif /* OPENSSL_EXTRA */
+1 -1
View File
@@ -988,7 +988,7 @@ int wolfSSL_PEM_write_bio_PKCS7(WOLFSSL_BIO* bio, PKCS7* p7)
outputHead = (byte*)XMALLOC(outputHeadSz, bio->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (outputHead == NULL)
return MEMORY_E;
return WOLFSSL_FAILURE;
outputFoot = (byte*)XMALLOC(outputFootSz, bio->heap,
DYNAMIC_TYPE_TMP_BUFFER);
+29
View File
@@ -249,6 +249,35 @@ int test_wolfSSL_RAND_bytes(void)
return EXPECT_RESULT();
}
int test_wolfSSL_RAND_load_file(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && \
defined(HAVE_HASHDRBG)
/* NULL fname must fail. */
ExpectIntEQ(RAND_load_file(NULL, 32), -1);
/* A non-existent path must fail. */
ExpectIntEQ(RAND_load_file("/no/such/file/wolfssl_rand_load_file_test",
32), -1);
#if defined(__linux__) || defined(__FreeBSD__)
/* Reading from the OS entropy source returns the requested byte count. */
ExpectIntEQ(RAND_load_file("/dev/urandom", 32), 32);
/* len < 0 caps at the implementation default (1 MB, matching OpenSSL's
* RAND_LOAD_BUF_SIZE). */
ExpectIntEQ(RAND_load_file("/dev/urandom", -1), 1L << 20);
/* len == 0 short-circuits to 0. */
ExpectIntEQ(RAND_load_file("/dev/urandom", 0), 0);
#endif
RAND_cleanup();
#endif
return EXPECT_RESULT();
}
int test_wolfSSL_RAND(void)
{
EXPECT_DECLS;
+2
View File
@@ -26,12 +26,14 @@
int test_wolfSSL_RAND_set_rand_method(void);
int test_wolfSSL_RAND_bytes(void);
int test_wolfSSL_RAND_load_file(void);
int test_wolfSSL_RAND(void);
int test_wolfSSL_RAND_poll(void);
#define TEST_OSSL_RAND_DECLS \
TEST_DECL_GROUP("ossl_rand", test_wolfSSL_RAND_set_rand_method), \
TEST_DECL_GROUP("ossl_rand", test_wolfSSL_RAND_bytes), \
TEST_DECL_GROUP("ossl_rand", test_wolfSSL_RAND_load_file), \
TEST_DECL_GROUP("ossl_rand", test_wolfSSL_RAND), \
TEST_DECL_GROUP("ossl_rand", test_wolfSSL_RAND_poll)