|
| 1 | +From b506ed4aeb2c86788422427624a03eb9bda52efc Mon Sep 17 00:00:00 2001 |
| 2 | +From: JacobBarthelmeh <jacob@wolfssl.com> |
| 3 | +Date: Tue, 10 Jun 2025 12:49:08 -0600 |
| 4 | +Subject: [PATCH] add sanity checks on pid with RNG |
| 5 | + |
| 6 | +CVE: CVE-2025-7394 |
| 7 | +Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/31490ab813a5aac096f50800c26c690d8ae586d2] |
| 8 | +Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com> |
| 9 | +--- |
| 10 | + CMakeLists.txt | 1 + |
| 11 | + configure.ac | 4 +- |
| 12 | + src/ssl.c | 40 +++++++++++- |
| 13 | + wolfcrypt/src/random.c | 126 ++++++++++++++++++++++--------------- |
| 14 | + wolfssl/wolfcrypt/random.h | 3 + |
| 15 | + 5 files changed, 118 insertions(+), 56 deletions(-) |
| 16 | + |
| 17 | +diff --git a/CMakeLists.txt b/CMakeLists.txt |
| 18 | +index 4e6f05fc6..910a36648 100644 |
| 19 | +--- a/CMakeLists.txt |
| 20 | ++++ b/CMakeLists.txt |
| 21 | +@@ -124,6 +124,7 @@ check_function_exists("memset" HAVE_MEMSET) |
| 22 | + check_function_exists("socket" HAVE_SOCKET) |
| 23 | + check_function_exists("strftime" HAVE_STRFTIME) |
| 24 | + check_function_exists("__atomic_fetch_add" HAVE_C___ATOMIC) |
| 25 | ++check_function_exists("getpid" HAVE_GETPID) |
| 26 | + |
| 27 | + include(CheckTypeSize) |
| 28 | + |
| 29 | +diff --git a/configure.ac b/configure.ac |
| 30 | +index c973b7e39..43ddd4767 100644 |
| 31 | +--- a/configure.ac |
| 32 | ++++ b/configure.ac |
| 33 | +@@ -125,8 +125,8 @@ AC_CHECK_HEADER(stdatomic.h, [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSL_HAVE_ATOMIC_H" |
| 34 | + # check if functions of interest are linkable, but also check if |
| 35 | + # they're declared by the expected headers, and if not, supersede the |
| 36 | + # unusable positive from AC_CHECK_FUNCS(). |
| 37 | +-AC_CHECK_FUNCS([gethostbyname getaddrinfo gettimeofday gmtime_r gmtime_s inet_ntoa memset socket strftime atexit]) |
| 38 | +-AC_CHECK_DECLS([gethostbyname, getaddrinfo, gettimeofday, gmtime_r, gmtime_s, inet_ntoa, memset, socket, strftime, atexit], [], [ |
| 39 | ++AC_CHECK_FUNCS([gethostbyname getaddrinfo gettimeofday gmtime_r gmtime_s inet_ntoa memset socket strftime atexit getpid]) |
| 40 | ++AC_CHECK_DECLS([gethostbyname, getaddrinfo, gettimeofday, gmtime_r, gmtime_s, inet_ntoa, memset, socket, strftime, atexit, getpid], [], [ |
| 41 | + if test "$(eval echo \$"$(eval 'echo ac_cv_func_${as_decl_name}')")" = "yes" |
| 42 | + then |
| 43 | + AC_MSG_NOTICE([ note: earlier check for $(eval 'echo ${as_decl_name}') superseded.]) |
| 44 | +diff --git a/src/ssl.c b/src/ssl.c |
| 45 | +index a1421d523..872aed594 100644 |
| 46 | +--- a/src/ssl.c |
| 47 | ++++ b/src/ssl.c |
| 48 | +@@ -23615,6 +23615,10 @@ int wolfSSL_RAND_Init(void) |
| 49 | + if (initGlobalRNG == 0) { |
| 50 | + ret = wc_InitRng(&globalRNG); |
| 51 | + if (ret == 0) { |
| 52 | ++ #if defined(HAVE_GETPID) && defined(HAVE_FIPS) && \ |
| 53 | ++ FIPS_VERSION3_LT(6,0,0))) |
| 54 | ++ currentPid = getpid(); |
| 55 | ++ #endif |
| 56 | + initGlobalRNG = 1; |
| 57 | + ret = WOLFSSL_SUCCESS; |
| 58 | + } |
| 59 | +@@ -24045,8 +24049,30 @@ int wolfSSL_RAND_pseudo_bytes(unsigned char* buf, int num) |
| 60 | + return ret; |
| 61 | + } |
| 62 | + |
| 63 | +-/* returns WOLFSSL_SUCCESS if the bytes generated are valid otherwise |
| 64 | +- * WOLFSSL_FAILURE */ |
| 65 | ++#if defined(HAVE_GETPID) && defined(HAVE_FIPS) && FIPS_VERSION3_LT(6,0,0))) |
| 66 | ++/* In older FIPS bundles add check for reseed here since it does not exist in |
| 67 | ++ * the older random.c certified files. */ |
| 68 | ++static pid_t currentPid = 0; |
| 69 | ++ |
| 70 | ++/* returns WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure */ |
| 71 | ++static int RandCheckReSeed() |
| 72 | ++{ |
| 73 | ++ int ret = WOLFSSL_SUCCESS; |
| 74 | ++ pid_t p; |
| 75 | ++ |
| 76 | ++ p = getpid(); |
| 77 | ++ if (p != currentPid) { |
| 78 | ++ currentPid = p; |
| 79 | ++ if (wolfSSL_RAND_poll() != WOLFSSL_SUCCESS) { |
| 80 | ++ ret = WOLFSSL_FAILURE; |
| 81 | ++ } |
| 82 | ++ } |
| 83 | ++ return ret; |
| 84 | ++} |
| 85 | ++#endif |
| 86 | ++ |
| 87 | ++/* returns WOLFSSL_SUCCESS (1) if the bytes generated are valid otherwise 0 |
| 88 | ++ * on failure */ |
| 89 | + int wolfSSL_RAND_bytes(unsigned char* buf, int num) |
| 90 | + { |
| 91 | + int ret = 0; |
| 92 | +@@ -24089,6 +24115,16 @@ int wolfSSL_RAND_bytes(unsigned char* buf, int num) |
| 93 | + */ |
| 94 | + if (initGlobalRNG) { |
| 95 | + rng = &globalRNG; |
| 96 | ++ |
| 97 | ++ #if defined(HAVE_GETPID) && defined(HAVE_FIPS) && \ |
| 98 | ++ FIPS_VERSION3_LT(6,0,0))) |
| 99 | ++ if (RandCheckReSeed() != WOLFSSL_SUCCESS) { |
| 100 | ++ wc_UnLockMutex(&globalRNGMutex); |
| 101 | ++ WOLFSSL_MSG("Issue with check pid and reseed"); |
| 102 | ++ return ret; |
| 103 | ++ } |
| 104 | ++ #endif |
| 105 | ++ |
| 106 | + used_global = 1; |
| 107 | + } |
| 108 | + else { |
| 109 | +diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c |
| 110 | +index 89c7411c9..b440e274b 100644 |
| 111 | +--- a/wolfcrypt/src/random.c |
| 112 | ++++ b/wolfcrypt/src/random.c |
| 113 | +@@ -1599,6 +1599,9 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, |
| 114 | + #else |
| 115 | + rng->heap = heap; |
| 116 | + #endif |
| 117 | ++#ifdef HAVE_GETPID |
| 118 | ++ rng->pid = getpid(); |
| 119 | ++#endif |
| 120 | + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) |
| 121 | + rng->devId = devId; |
| 122 | + #if defined(WOLF_CRYPTO_CB) |
| 123 | +@@ -1849,6 +1852,63 @@ int wc_InitRngNonce_ex(WC_RNG* rng, byte* nonce, word32 nonceSz, |
| 124 | + return _InitRng(rng, nonce, nonceSz, heap, devId); |
| 125 | + } |
| 126 | + |
| 127 | ++#ifdef HAVE_HASHDRBG |
| 128 | ++static int PollAndReSeed(WC_RNG* rng) |
| 129 | ++{ |
| 130 | ++ int ret = DRBG_NEED_RESEED; |
| 131 | ++ int devId = INVALID_DEVID; |
| 132 | ++#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) |
| 133 | ++ devId = rng->devId; |
| 134 | ++#endif |
| 135 | ++ if (wc_RNG_HealthTestLocal(1, rng->heap, devId) == 0) { |
| 136 | ++ #ifndef WOLFSSL_SMALL_STACK |
| 137 | ++ byte newSeed[SEED_SZ + SEED_BLOCK_SZ]; |
| 138 | ++ ret = DRBG_SUCCESS; |
| 139 | ++ #else |
| 140 | ++ byte* newSeed = (byte*)XMALLOC(SEED_SZ + SEED_BLOCK_SZ, rng->heap, |
| 141 | ++ DYNAMIC_TYPE_SEED); |
| 142 | ++ ret = (newSeed == NULL) ? MEMORY_E : DRBG_SUCCESS; |
| 143 | ++ #endif |
| 144 | ++ if (ret == DRBG_SUCCESS) { |
| 145 | ++ #ifdef WC_RNG_SEED_CB |
| 146 | ++ if (seedCb == NULL) { |
| 147 | ++ ret = DRBG_NO_SEED_CB; |
| 148 | ++ } |
| 149 | ++ else { |
| 150 | ++ ret = seedCb(&rng->seed, newSeed, SEED_SZ + SEED_BLOCK_SZ); |
| 151 | ++ if (ret != 0) { |
| 152 | ++ ret = DRBG_FAILURE; |
| 153 | ++ } |
| 154 | ++ } |
| 155 | ++ #else |
| 156 | ++ ret = wc_GenerateSeed(&rng->seed, newSeed, |
| 157 | ++ SEED_SZ + SEED_BLOCK_SZ); |
| 158 | ++ #endif |
| 159 | ++ if (ret != 0) |
| 160 | ++ ret = DRBG_FAILURE; |
| 161 | ++ } |
| 162 | ++ if (ret == DRBG_SUCCESS) |
| 163 | ++ ret = wc_RNG_TestSeed(newSeed, SEED_SZ + SEED_BLOCK_SZ); |
| 164 | ++ |
| 165 | ++ if (ret == DRBG_SUCCESS) |
| 166 | ++ ret = Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, |
| 167 | ++ newSeed + SEED_BLOCK_SZ, SEED_SZ); |
| 168 | ++ #ifdef WOLFSSL_SMALL_STACK |
| 169 | ++ if (newSeed != NULL) { |
| 170 | ++ ForceZero(newSeed, SEED_SZ + SEED_BLOCK_SZ); |
| 171 | ++ } |
| 172 | ++ XFREE(newSeed, rng->heap, DYNAMIC_TYPE_SEED); |
| 173 | ++ #else |
| 174 | ++ ForceZero(newSeed, sizeof(newSeed)); |
| 175 | ++ #endif |
| 176 | ++ } |
| 177 | ++ else { |
| 178 | ++ ret = DRBG_CONT_FAILURE; |
| 179 | ++ } |
| 180 | ++ |
| 181 | ++ return ret; |
| 182 | ++} |
| 183 | ++#endif |
| 184 | + |
| 185 | + /* place a generated block in output */ |
| 186 | + WOLFSSL_ABI |
| 187 | +@@ -1908,60 +1968,22 @@ int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) |
| 188 | + if (rng->status != DRBG_OK) |
| 189 | + return RNG_FAILURE_E; |
| 190 | + |
| 191 | ++#ifdef HAVE_GETPID |
| 192 | ++ if (rng->pid != getpid()) { |
| 193 | ++ rng->pid = getpid(); |
| 194 | ++ ret = PollAndReSeed(rng); |
| 195 | ++ if (ret != DRBG_SUCCESS) { |
| 196 | ++ rng->status = DRBG_FAILED; |
| 197 | ++ return RNG_FAILURE_E; |
| 198 | ++ } |
| 199 | ++ } |
| 200 | ++#endif |
| 201 | ++ |
| 202 | + ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz); |
| 203 | + if (ret == DRBG_NEED_RESEED) { |
| 204 | +- int devId = INVALID_DEVID; |
| 205 | +- #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) |
| 206 | +- devId = rng->devId; |
| 207 | +- #endif |
| 208 | +- if (wc_RNG_HealthTestLocal(1, rng->heap, devId) == 0) { |
| 209 | +- #ifndef WOLFSSL_SMALL_STACK |
| 210 | +- byte newSeed[SEED_SZ + SEED_BLOCK_SZ]; |
| 211 | +- ret = DRBG_SUCCESS; |
| 212 | +- #else |
| 213 | +- byte* newSeed = (byte*)XMALLOC(SEED_SZ + SEED_BLOCK_SZ, rng->heap, |
| 214 | +- DYNAMIC_TYPE_SEED); |
| 215 | +- ret = (newSeed == NULL) ? MEMORY_E : DRBG_SUCCESS; |
| 216 | +- #endif |
| 217 | +- if (ret == DRBG_SUCCESS) { |
| 218 | +- #ifdef WC_RNG_SEED_CB |
| 219 | +- if (seedCb == NULL) { |
| 220 | +- ret = DRBG_NO_SEED_CB; |
| 221 | +- } |
| 222 | +- else { |
| 223 | +- ret = seedCb(&rng->seed, newSeed, SEED_SZ + SEED_BLOCK_SZ); |
| 224 | +- if (ret != 0) { |
| 225 | +- ret = DRBG_FAILURE; |
| 226 | +- } |
| 227 | +- } |
| 228 | +- #else |
| 229 | +- ret = wc_GenerateSeed(&rng->seed, newSeed, |
| 230 | +- SEED_SZ + SEED_BLOCK_SZ); |
| 231 | +- #endif |
| 232 | +- if (ret != 0) |
| 233 | +- ret = DRBG_FAILURE; |
| 234 | +- } |
| 235 | +- if (ret == DRBG_SUCCESS) |
| 236 | +- ret = wc_RNG_TestSeed(newSeed, SEED_SZ + SEED_BLOCK_SZ); |
| 237 | +- |
| 238 | +- if (ret == DRBG_SUCCESS) |
| 239 | +- ret = Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, |
| 240 | +- newSeed + SEED_BLOCK_SZ, SEED_SZ); |
| 241 | +- if (ret == DRBG_SUCCESS) |
| 242 | +- ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz); |
| 243 | +- |
| 244 | +- #ifdef WOLFSSL_SMALL_STACK |
| 245 | +- if (newSeed != NULL) { |
| 246 | +- ForceZero(newSeed, SEED_SZ + SEED_BLOCK_SZ); |
| 247 | +- } |
| 248 | +- XFREE(newSeed, rng->heap, DYNAMIC_TYPE_SEED); |
| 249 | +- #else |
| 250 | +- ForceZero(newSeed, sizeof(newSeed)); |
| 251 | +- #endif |
| 252 | +- } |
| 253 | +- else { |
| 254 | +- ret = DRBG_CONT_FAILURE; |
| 255 | +- } |
| 256 | ++ ret = PollAndReSeed(rng); |
| 257 | ++ if (ret == DRBG_SUCCESS) |
| 258 | ++ ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz); |
| 259 | + } |
| 260 | + |
| 261 | + if (ret == DRBG_SUCCESS) { |
| 262 | +diff --git a/wolfssl/wolfcrypt/random.h b/wolfssl/wolfcrypt/random.h |
| 263 | +index 9dd616328..f472e1f40 100644 |
| 264 | +--- a/wolfssl/wolfcrypt/random.h |
| 265 | ++++ b/wolfssl/wolfcrypt/random.h |
| 266 | +@@ -183,6 +183,9 @@ struct WC_RNG { |
| 267 | + #endif |
| 268 | + byte status; |
| 269 | + #endif |
| 270 | ++#ifdef HAVE_GETPID |
| 271 | ++ pid_t pid; |
| 272 | ++#endif |
| 273 | + #ifdef WOLFSSL_ASYNC_CRYPT |
| 274 | + WC_ASYNC_DEV asyncDev; |
| 275 | + #endif |
0 commit comments