/src/openssl111/crypto/rand/rand_unix.c
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | /* | 
| 2 |  |  * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. | 
| 3 |  |  * | 
| 4 |  |  * Licensed under the OpenSSL license (the "License").  You may not use | 
| 5 |  |  * this file except in compliance with the License.  You can obtain a copy | 
| 6 |  |  * in the file LICENSE in the source distribution or at | 
| 7 |  |  * https://www.openssl.org/source/license.html | 
| 8 |  |  */ | 
| 9 |  |  | 
| 10 |  | #ifndef _GNU_SOURCE | 
| 11 |  | # define _GNU_SOURCE | 
| 12 |  | #endif | 
| 13 |  | #include "e_os.h" | 
| 14 |  | #include <stdio.h> | 
| 15 |  | #include "internal/cryptlib.h" | 
| 16 |  | #include <openssl/rand.h> | 
| 17 |  | #include <openssl/crypto.h> | 
| 18 |  | #include "rand_local.h" | 
| 19 |  | #include "crypto/rand.h" | 
| 20 |  | #include <stdio.h> | 
| 21 |  | #include "internal/dso.h" | 
| 22 |  | #ifdef __linux | 
| 23 |  | # include <sys/syscall.h> | 
| 24 |  | # ifdef DEVRANDOM_WAIT | 
| 25 |  | #  include <sys/shm.h> | 
| 26 |  | #  include <sys/utsname.h> | 
| 27 |  | # endif | 
| 28 |  | #endif | 
| 29 |  | #if (defined(__FreeBSD__) || defined(__NetBSD__)) && !defined(OPENSSL_SYS_UEFI) | 
| 30 |  | # include <sys/types.h> | 
| 31 |  | # include <sys/sysctl.h> | 
| 32 |  | # include <sys/param.h> | 
| 33 |  | #endif | 
| 34 |  | #if defined(__OpenBSD__) | 
| 35 |  | # include <sys/param.h> | 
| 36 |  | #endif | 
| 37 |  |  | 
| 38 |  | #if defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__) | 
| 39 |  | # include <sys/types.h> | 
| 40 |  | # include <sys/stat.h> | 
| 41 |  | # include <fcntl.h> | 
| 42 |  | # include <unistd.h> | 
| 43 |  | # include <sys/time.h> | 
| 44 |  |  | 
| 45 |  | static uint64_t get_time_stamp(void); | 
| 46 |  | static uint64_t get_timer_bits(void); | 
| 47 |  |  | 
| 48 |  | /* Macro to convert two thirty two bit values into a sixty four bit one */ | 
| 49 | 1 | # define TWO32TO64(a, b) ((((uint64_t)(a)) << 32) + (b)) | 
| 50 |  |  | 
| 51 |  | /* | 
| 52 |  |  * Check for the existence and support of POSIX timers.  The standard | 
| 53 |  |  * says that the _POSIX_TIMERS macro will have a positive value if they | 
| 54 |  |  * are available. | 
| 55 |  |  * | 
| 56 |  |  * However, we want an additional constraint: that the timer support does | 
| 57 |  |  * not require an extra library dependency.  Early versions of glibc | 
| 58 |  |  * require -lrt to be specified on the link line to access the timers, | 
| 59 |  |  * so this needs to be checked for. | 
| 60 |  |  * | 
| 61 |  |  * It is worse because some libraries define __GLIBC__ but don't | 
| 62 |  |  * support the version testing macro (e.g. uClibc).  This means | 
| 63 |  |  * an extra check is needed. | 
| 64 |  |  * | 
| 65 |  |  * The final condition is: | 
| 66 |  |  *      "have posix timers and either not glibc or glibc without -lrt" | 
| 67 |  |  * | 
| 68 |  |  * The nested #if sequences are required to avoid using a parameterised | 
| 69 |  |  * macro that might be undefined. | 
| 70 |  |  */ | 
| 71 |  | # undef OSSL_POSIX_TIMER_OKAY | 
| 72 |  | # if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 | 
| 73 |  | #  if defined(__GLIBC__) | 
| 74 |  | #   if defined(__GLIBC_PREREQ) | 
| 75 |  | #    if __GLIBC_PREREQ(2, 17) | 
| 76 |  | #     define OSSL_POSIX_TIMER_OKAY | 
| 77 |  | #    endif | 
| 78 |  | #   endif | 
| 79 |  | #  else | 
| 80 |  | #   define OSSL_POSIX_TIMER_OKAY | 
| 81 |  | #  endif | 
| 82 |  | # endif | 
| 83 |  | #endif /* (defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_SYS_VXWORKS)) | 
| 84 |  |           || defined(__DJGPP__) */ | 
| 85 |  |  | 
| 86 |  | #if defined(OPENSSL_RAND_SEED_NONE) | 
| 87 |  | /* none means none. this simplifies the following logic */ | 
| 88 |  | # undef OPENSSL_RAND_SEED_OS | 
| 89 |  | # undef OPENSSL_RAND_SEED_GETRANDOM | 
| 90 |  | # undef OPENSSL_RAND_SEED_LIBRANDOM | 
| 91 |  | # undef OPENSSL_RAND_SEED_DEVRANDOM | 
| 92 |  | # undef OPENSSL_RAND_SEED_RDTSC | 
| 93 |  | # undef OPENSSL_RAND_SEED_RDCPU | 
| 94 |  | # undef OPENSSL_RAND_SEED_EGD | 
| 95 |  | #endif | 
| 96 |  |  | 
| 97 |  | #if (defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI)) && \ | 
| 98 |  |         !defined(OPENSSL_RAND_SEED_NONE) | 
| 99 |  | # error "UEFI and VXWorks only support seeding NONE" | 
| 100 |  | #endif | 
| 101 |  |  | 
| 102 |  | #if defined(OPENSSL_SYS_VXWORKS) | 
| 103 |  | /* empty implementation */ | 
| 104 |  | int rand_pool_init(void) | 
| 105 |  | { | 
| 106 |  |     return 1; | 
| 107 |  | } | 
| 108 |  |  | 
| 109 |  | void rand_pool_cleanup(void) | 
| 110 |  | { | 
| 111 |  | } | 
| 112 |  |  | 
| 113 |  | void rand_pool_keep_random_devices_open(int keep) | 
| 114 |  | { | 
| 115 |  | } | 
| 116 |  |  | 
| 117 |  | size_t rand_pool_acquire_entropy(RAND_POOL *pool) | 
| 118 |  | { | 
| 119 |  |     return rand_pool_entropy_available(pool); | 
| 120 |  | } | 
| 121 |  | #endif | 
| 122 |  |  | 
| 123 |  | #if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) \ | 
| 124 |  |     || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_VXWORKS) \ | 
| 125 |  |     || defined(OPENSSL_SYS_UEFI)) | 
| 126 |  |  | 
| 127 |  | # if defined(OPENSSL_SYS_VOS) | 
| 128 |  |  | 
| 129 |  | #  ifndef OPENSSL_RAND_SEED_OS | 
| 130 |  | #   error "Unsupported seeding method configured; must be os" | 
| 131 |  | #  endif | 
| 132 |  |  | 
| 133 |  | #  if defined(OPENSSL_SYS_VOS_HPPA) && defined(OPENSSL_SYS_VOS_IA32) | 
| 134 |  | #   error "Unsupported HP-PA and IA32 at the same time." | 
| 135 |  | #  endif | 
| 136 |  | #  if !defined(OPENSSL_SYS_VOS_HPPA) && !defined(OPENSSL_SYS_VOS_IA32) | 
| 137 |  | #   error "Must have one of HP-PA or IA32" | 
| 138 |  | #  endif | 
| 139 |  |  | 
| 140 |  | /* | 
| 141 |  |  * The following algorithm repeatedly samples the real-time clock (RTC) to | 
| 142 |  |  * generate a sequence of unpredictable data.  The algorithm relies upon the | 
| 143 |  |  * uneven execution speed of the code (due to factors such as cache misses, | 
| 144 |  |  * interrupts, bus activity, and scheduling) and upon the rather large | 
| 145 |  |  * relative difference between the speed of the clock and the rate at which | 
| 146 |  |  * it can be read.  If it is ported to an environment where execution speed | 
| 147 |  |  * is more constant or where the RTC ticks at a much slower rate, or the | 
| 148 |  |  * clock can be read with fewer instructions, it is likely that the results | 
| 149 |  |  * would be far more predictable.  This should only be used for legacy | 
| 150 |  |  * platforms. | 
| 151 |  |  * | 
| 152 |  |  * As a precaution, we assume only 2 bits of entropy per byte. | 
| 153 |  |  */ | 
| 154 |  | size_t rand_pool_acquire_entropy(RAND_POOL *pool) | 
| 155 |  | { | 
| 156 |  |     short int code; | 
| 157 |  |     int i, k; | 
| 158 |  |     size_t bytes_needed; | 
| 159 |  |     struct timespec ts; | 
| 160 |  |     unsigned char v; | 
| 161 |  | #  ifdef OPENSSL_SYS_VOS_HPPA | 
| 162 |  |     long duration; | 
| 163 |  |     extern void s$sleep(long *_duration, short int *_code); | 
| 164 |  | #  else | 
| 165 |  |     long long duration; | 
| 166 |  |     extern void s$sleep2(long long *_duration, short int *_code); | 
| 167 |  | #  endif | 
| 168 |  |  | 
| 169 |  |     bytes_needed = rand_pool_bytes_needed(pool, 4 /*entropy_factor*/); | 
| 170 |  |  | 
| 171 |  |     for (i = 0; i < bytes_needed; i++) { | 
| 172 |  |         /* | 
| 173 |  |          * burn some cpu; hope for interrupts, cache collisions, bus | 
| 174 |  |          * interference, etc. | 
| 175 |  |          */ | 
| 176 |  |         for (k = 0; k < 99; k++) | 
| 177 |  |             ts.tv_nsec = random(); | 
| 178 |  |  | 
| 179 |  | #  ifdef OPENSSL_SYS_VOS_HPPA | 
| 180 |  |         /* sleep for 1/1024 of a second (976 us).  */ | 
| 181 |  |         duration = 1; | 
| 182 |  |         s$sleep(&duration, &code); | 
| 183 |  | #  else | 
| 184 |  |         /* sleep for 1/65536 of a second (15 us).  */ | 
| 185 |  |         duration = 1; | 
| 186 |  |         s$sleep2(&duration, &code); | 
| 187 |  | #  endif | 
| 188 |  |  | 
| 189 |  |         /* Get wall clock time, take 8 bits. */ | 
| 190 |  |         clock_gettime(CLOCK_REALTIME, &ts); | 
| 191 |  |         v = (unsigned char)(ts.tv_nsec & 0xFF); | 
| 192 |  |         rand_pool_add(pool, arg, &v, sizeof(v) , 2); | 
| 193 |  |     } | 
| 194 |  |     return rand_pool_entropy_available(pool); | 
| 195 |  | } | 
| 196 |  |  | 
| 197 |  | void rand_pool_cleanup(void) | 
| 198 |  | { | 
| 199 |  | } | 
| 200 |  |  | 
| 201 |  | void rand_pool_keep_random_devices_open(int keep) | 
| 202 |  | { | 
| 203 |  | } | 
| 204 |  |  | 
| 205 |  | # else | 
| 206 |  |  | 
| 207 |  | #  if defined(OPENSSL_RAND_SEED_EGD) && \ | 
| 208 |  |         (defined(OPENSSL_NO_EGD) || !defined(DEVRANDOM_EGD)) | 
| 209 |  | #   error "Seeding uses EGD but EGD is turned off or no device given" | 
| 210 |  | #  endif | 
| 211 |  |  | 
| 212 |  | #  if defined(OPENSSL_RAND_SEED_DEVRANDOM) && !defined(DEVRANDOM) | 
| 213 |  | #   error "Seeding uses urandom but DEVRANDOM is not configured" | 
| 214 |  | #  endif | 
| 215 |  |  | 
| 216 |  | #  if defined(OPENSSL_RAND_SEED_OS) | 
| 217 |  | #   if !defined(DEVRANDOM) | 
| 218 |  | #    error "OS seeding requires DEVRANDOM to be configured" | 
| 219 |  | #   endif | 
| 220 |  | #   define OPENSSL_RAND_SEED_GETRANDOM | 
| 221 |  | #   define OPENSSL_RAND_SEED_DEVRANDOM | 
| 222 |  | #  endif | 
| 223 |  |  | 
| 224 |  | #  if defined(OPENSSL_RAND_SEED_LIBRANDOM) | 
| 225 |  | #   error "librandom not (yet) supported" | 
| 226 |  | #  endif | 
| 227 |  |  | 
| 228 |  | #  if (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND) | 
| 229 |  | /* | 
| 230 |  |  * sysctl_random(): Use sysctl() to read a random number from the kernel | 
| 231 |  |  * Returns the number of bytes returned in buf on success, -1 on failure. | 
| 232 |  |  */ | 
| 233 |  | static ssize_t sysctl_random(char *buf, size_t buflen) | 
| 234 |  | { | 
| 235 |  |     int mib[2]; | 
| 236 |  |     size_t done = 0; | 
| 237 |  |     size_t len; | 
| 238 |  |  | 
| 239 |  |     /* | 
| 240 |  |      * Note: sign conversion between size_t and ssize_t is safe even | 
| 241 |  |      * without a range check, see comment in syscall_random() | 
| 242 |  |      */ | 
| 243 |  |  | 
| 244 |  |     /* | 
| 245 |  |      * On FreeBSD old implementations returned longs, newer versions support | 
| 246 |  |      * variable sizes up to 256 byte. The code below would not work properly | 
| 247 |  |      * when the sysctl returns long and we want to request something not a | 
| 248 |  |      * multiple of longs, which should never be the case. | 
| 249 |  |      */ | 
| 250 |  | #if   defined(__FreeBSD__) | 
| 251 |  |     if (!ossl_assert(buflen % sizeof(long) == 0)) { | 
| 252 |  |         errno = EINVAL; | 
| 253 |  |         return -1; | 
| 254 |  |     } | 
| 255 |  | #endif | 
| 256 |  |  | 
| 257 |  |     /* | 
| 258 |  |      * On NetBSD before 4.0 KERN_ARND was an alias for KERN_URND, and only | 
| 259 |  |      * filled in an int, leaving the rest uninitialized. Since NetBSD 4.0 | 
| 260 |  |      * it returns a variable number of bytes with the current version supporting | 
| 261 |  |      * up to 256 bytes. | 
| 262 |  |      * Just return an error on older NetBSD versions. | 
| 263 |  |      */ | 
| 264 |  | #if   defined(__NetBSD__) && __NetBSD_Version__ < 400000000 | 
| 265 |  |     errno = ENOSYS; | 
| 266 |  |     return -1; | 
| 267 |  | #endif | 
| 268 |  |  | 
| 269 |  |     mib[0] = CTL_KERN; | 
| 270 |  |     mib[1] = KERN_ARND; | 
| 271 |  |  | 
| 272 |  |     do { | 
| 273 |  |         len = buflen > 256 ? 256 : buflen; | 
| 274 |  |         if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) | 
| 275 |  |             return done > 0 ? done : -1; | 
| 276 |  |         done += len; | 
| 277 |  |         buf += len; | 
| 278 |  |         buflen -= len; | 
| 279 |  |     } while (buflen > 0); | 
| 280 |  |  | 
| 281 |  |     return done; | 
| 282 |  | } | 
| 283 |  | #  endif | 
| 284 |  |  | 
| 285 |  | #  if defined(OPENSSL_RAND_SEED_GETRANDOM) | 
| 286 |  |  | 
| 287 |  | #   if defined(__linux) && !defined(__NR_getrandom) | 
| 288 |  | #    if defined(__arm__) | 
| 289 |  | #     define __NR_getrandom    (__NR_SYSCALL_BASE+384) | 
| 290 |  | #    elif defined(__i386__) | 
| 291 |  | #     define __NR_getrandom    355 | 
| 292 |  | #    elif defined(__x86_64__) | 
| 293 |  | #     if defined(__ILP32__) | 
| 294 |  | #      define __NR_getrandom   (__X32_SYSCALL_BIT + 318) | 
| 295 |  | #     else | 
| 296 |  | #      define __NR_getrandom   318 | 
| 297 |  | #     endif | 
| 298 |  | #    elif defined(__xtensa__) | 
| 299 |  | #     define __NR_getrandom    338 | 
| 300 |  | #    elif defined(__s390__) || defined(__s390x__) | 
| 301 |  | #     define __NR_getrandom    349 | 
| 302 |  | #    elif defined(__bfin__) | 
| 303 |  | #     define __NR_getrandom    389 | 
| 304 |  | #    elif defined(__powerpc__) | 
| 305 |  | #     define __NR_getrandom    359 | 
| 306 |  | #    elif defined(__mips__) || defined(__mips64) | 
| 307 |  | #     if _MIPS_SIM == _MIPS_SIM_ABI32 | 
| 308 |  | #      define __NR_getrandom   (__NR_Linux + 353) | 
| 309 |  | #     elif _MIPS_SIM == _MIPS_SIM_ABI64 | 
| 310 |  | #      define __NR_getrandom   (__NR_Linux + 313) | 
| 311 |  | #     elif _MIPS_SIM == _MIPS_SIM_NABI32 | 
| 312 |  | #      define __NR_getrandom   (__NR_Linux + 317) | 
| 313 |  | #     endif | 
| 314 |  | #    elif defined(__hppa__) | 
| 315 |  | #     define __NR_getrandom    (__NR_Linux + 339) | 
| 316 |  | #    elif defined(__sparc__) | 
| 317 |  | #     define __NR_getrandom    347 | 
| 318 |  | #    elif defined(__ia64__) | 
| 319 |  | #     define __NR_getrandom    1339 | 
| 320 |  | #    elif defined(__alpha__) | 
| 321 |  | #     define __NR_getrandom    511 | 
| 322 |  | #    elif defined(__sh__) | 
| 323 |  | #     if defined(__SH5__) | 
| 324 |  | #      define __NR_getrandom   373 | 
| 325 |  | #     else | 
| 326 |  | #      define __NR_getrandom   384 | 
| 327 |  | #     endif | 
| 328 |  | #    elif defined(__avr32__) | 
| 329 |  | #     define __NR_getrandom    317 | 
| 330 |  | #    elif defined(__microblaze__) | 
| 331 |  | #     define __NR_getrandom    385 | 
| 332 |  | #    elif defined(__m68k__) | 
| 333 |  | #     define __NR_getrandom    352 | 
| 334 |  | #    elif defined(__cris__) | 
| 335 |  | #     define __NR_getrandom    356 | 
| 336 |  | #    elif defined(__aarch64__) | 
| 337 |  | #     define __NR_getrandom    278 | 
| 338 |  | #    else /* generic */ | 
| 339 |  | #     define __NR_getrandom    278 | 
| 340 |  | #    endif | 
| 341 |  | #   endif | 
| 342 |  |  | 
| 343 |  | /* | 
| 344 |  |  * syscall_random(): Try to get random data using a system call | 
| 345 |  |  * returns the number of bytes returned in buf, or < 0 on error. | 
| 346 |  |  */ | 
| 347 |  | static ssize_t syscall_random(void *buf, size_t buflen) | 
| 348 | 3 | { | 
| 349 |  |     /* | 
| 350 |  |      * Note: 'buflen' equals the size of the buffer which is used by the | 
| 351 |  |      * get_entropy() callback of the RAND_DRBG. It is roughly bounded by | 
| 352 |  |      * | 
| 353 |  |      *   2 * RAND_POOL_FACTOR * (RAND_DRBG_STRENGTH / 8) = 2^14 | 
| 354 |  |      * | 
| 355 |  |      * which is way below the OSSL_SSIZE_MAX limit. Therefore sign conversion | 
| 356 |  |      * between size_t and ssize_t is safe even without a range check. | 
| 357 |  |      */ | 
| 358 |  |  | 
| 359 |  |     /* | 
| 360 |  |      * Do runtime detection to find getentropy(). | 
| 361 |  |      * | 
| 362 |  |      * Known OSs that should support this: | 
| 363 |  |      * - Darwin since 16 (OSX 10.12, IOS 10.0). | 
| 364 |  |      * - Solaris since 11.3 | 
| 365 |  |      * - OpenBSD since 5.6 | 
| 366 |  |      * - Linux since 3.17 with glibc 2.25 | 
| 367 |  |      * - FreeBSD since 12.0 (1200061) | 
| 368 |  |      * | 
| 369 |  |      * Note: Sometimes getentropy() can be provided but not implemented | 
| 370 |  |      * internally. So we need to check errno for ENOSYS | 
| 371 |  |      */ | 
| 372 | 3 | #  if defined(__GNUC__) && __GNUC__>=2 && defined(__ELF__) && !defined(__hpux) | 
| 373 | 3 |     extern int getentropy(void *buffer, size_t length) __attribute__((weak)); | 
| 374 |  |  | 
| 375 | 3 |     if (getentropy != NULL) { | 
| 376 | 3 |         if (getentropy(buf, buflen) == 0) | 
| 377 | 3 |             return (ssize_t)buflen; | 
| 378 | 0 |         if (errno != ENOSYS) | 
| 379 | 0 |             return -1; | 
| 380 | 0 |     } | 
| 381 |  | #  elif defined(OPENSSL_APPLE_CRYPTO_RANDOM) | 
| 382 |  |     if (CCRandomGenerateBytes(buf, buflen) == kCCSuccess) | 
| 383 |  |       return (ssize_t)buflen; | 
| 384 |  |  | 
| 385 |  |     return -1; | 
| 386 |  | #  else | 
| 387 |  |     union { | 
| 388 |  |         void *p; | 
| 389 |  |         int (*f)(void *buffer, size_t length); | 
| 390 |  |     } p_getentropy; | 
| 391 |  |  | 
| 392 |  |     /* | 
| 393 |  |      * We could cache the result of the lookup, but we normally don't | 
| 394 |  |      * call this function often. | 
| 395 |  |      */ | 
| 396 |  |     ERR_set_mark(); | 
| 397 |  |     p_getentropy.p = DSO_global_lookup("getentropy"); | 
| 398 |  |     ERR_pop_to_mark(); | 
| 399 |  |     if (p_getentropy.p != NULL) | 
| 400 |  |         return p_getentropy.f(buf, buflen) == 0 ? (ssize_t)buflen : -1; | 
| 401 |  | #  endif | 
| 402 |  |  | 
| 403 |  |     /* Linux supports this since version 3.17 */ | 
| 404 | 0 | #  if defined(__linux) && defined(__NR_getrandom) | 
| 405 | 0 |     return syscall(__NR_getrandom, buf, buflen, 0); | 
| 406 |  | #  elif (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND) | 
| 407 |  |     return sysctl_random(buf, buflen); | 
| 408 |  | #  else | 
| 409 |  |     errno = ENOSYS; | 
| 410 |  |     return -1; | 
| 411 |  | #  endif | 
| 412 | 3 | } | 
| 413 |  | #  endif    /* defined(OPENSSL_RAND_SEED_GETRANDOM) */ | 
| 414 |  |  | 
| 415 |  | #  if defined(OPENSSL_RAND_SEED_DEVRANDOM) | 
| 416 |  | static const char *random_device_paths[] = { DEVRANDOM }; | 
| 417 |  | static struct random_device { | 
| 418 |  |     int fd; | 
| 419 |  |     dev_t dev; | 
| 420 |  |     ino_t ino; | 
| 421 |  |     mode_t mode; | 
| 422 |  |     dev_t rdev; | 
| 423 |  | } random_devices[OSSL_NELEM(random_device_paths)]; | 
| 424 |  | static int keep_random_devices_open = 1; | 
| 425 |  |  | 
| 426 |  | #   if defined(__linux) && defined(DEVRANDOM_WAIT) \ | 
| 427 |  |        && defined(OPENSSL_RAND_SEED_GETRANDOM) | 
| 428 |  | static void *shm_addr; | 
| 429 |  |  | 
| 430 |  | static void cleanup_shm(void) | 
| 431 | 0 | { | 
| 432 | 0 |     shmdt(shm_addr); | 
| 433 | 0 | } | 
| 434 |  |  | 
| 435 |  | /* | 
| 436 |  |  * Ensure that the system randomness source has been adequately seeded. | 
| 437 |  |  * This is done by having the first start of libcrypto, wait until the device | 
| 438 |  |  * /dev/random becomes able to supply a byte of entropy.  Subsequent starts | 
| 439 |  |  * of the library and later reseedings do not need to do this. | 
| 440 |  |  */ | 
| 441 |  | static int wait_random_seeded(void) | 
| 442 | 0 | { | 
| 443 | 0 |     static int seeded = OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID < 0; | 
| 444 | 0 |     static const int kernel_version[] = { DEVRANDOM_SAFE_KERNEL }; | 
| 445 | 0 |     int kernel[2]; | 
| 446 | 0 |     int shm_id, fd, r; | 
| 447 | 0 |     char c, *p; | 
| 448 | 0 |     struct utsname un; | 
| 449 | 0 |     fd_set fds; | 
| 450 |  | 
 | 
| 451 | 0 |     if (!seeded) { | 
| 452 |  |         /* See if anything has created the global seeded indication */ | 
| 453 | 0 |         if ((shm_id = shmget(OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID, 1, 0)) == -1) { | 
| 454 |  |             /* | 
| 455 |  |              * Check the kernel's version and fail if it is too recent. | 
| 456 |  |              * | 
| 457 |  |              * Linux kernels from 4.8 onwards do not guarantee that | 
| 458 |  |              * /dev/urandom is properly seeded when /dev/random becomes | 
| 459 |  |              * readable.  However, such kernels support the getentropy(2) | 
| 460 |  |              * system call and this should always succeed which renders | 
| 461 |  |              * this alternative but essentially identical source moot. | 
| 462 |  |              */ | 
| 463 | 0 |             if (uname(&un) == 0) { | 
| 464 | 0 |                 kernel[0] = atoi(un.release); | 
| 465 | 0 |                 p = strchr(un.release, '.'); | 
| 466 | 0 |                 kernel[1] = p == NULL ? 0 : atoi(p + 1); | 
| 467 | 0 |                 if (kernel[0] > kernel_version[0] | 
| 468 | 0 |                     || (kernel[0] == kernel_version[0] | 
| 469 | 0 |                         && kernel[1] >= kernel_version[1])) { | 
| 470 | 0 |                     return 0; | 
| 471 | 0 |                 } | 
| 472 | 0 |             } | 
| 473 |  |             /* Open /dev/random and wait for it to be readable */ | 
| 474 | 0 |             if ((fd = open(DEVRANDOM_WAIT, O_RDONLY)) != -1) { | 
| 475 | 0 |                 if (DEVRANDM_WAIT_USE_SELECT && fd < FD_SETSIZE) { | 
| 476 | 0 |                     FD_ZERO(&fds); | 
| 477 | 0 |                     FD_SET(fd, &fds); | 
| 478 | 0 |                     while ((r = select(fd + 1, &fds, NULL, NULL, NULL)) < 0 | 
| 479 | 0 |                            && errno == EINTR); | 
| 480 | 0 |                 } else { | 
| 481 | 0 |                     while ((r = read(fd, &c, 1)) < 0 && errno == EINTR); | 
| 482 | 0 |                 } | 
| 483 | 0 |                 close(fd); | 
| 484 | 0 |                 if (r == 1) { | 
| 485 | 0 |                     seeded = 1; | 
| 486 |  |                     /* Create the shared memory indicator */ | 
| 487 | 0 |                     shm_id = shmget(OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID, 1, | 
| 488 | 0 |                                     IPC_CREAT | S_IRUSR | S_IRGRP | S_IROTH); | 
| 489 | 0 |                 } | 
| 490 | 0 |             } | 
| 491 | 0 |         } | 
| 492 | 0 |         if (shm_id != -1) { | 
| 493 | 0 |             seeded = 1; | 
| 494 |  |             /* | 
| 495 |  |              * Map the shared memory to prevent its premature destruction. | 
| 496 |  |              * If this call fails, it isn't a big problem. | 
| 497 |  |              */ | 
| 498 | 0 |             shm_addr = shmat(shm_id, NULL, SHM_RDONLY); | 
| 499 | 0 |             if (shm_addr != (void *)-1) | 
| 500 | 0 |                 OPENSSL_atexit(&cleanup_shm); | 
| 501 | 0 |         } | 
| 502 | 0 |     } | 
| 503 | 0 |     return seeded; | 
| 504 | 0 | } | 
| 505 |  | #   else /* defined __linux && DEVRANDOM_WAIT && OPENSSL_RAND_SEED_GETRANDOM */ | 
| 506 |  | static int wait_random_seeded(void) | 
| 507 |  | { | 
| 508 |  |     return 1; | 
| 509 |  | } | 
| 510 |  | #   endif | 
| 511 |  |  | 
| 512 |  | /* | 
| 513 |  |  * Verify that the file descriptor associated with the random source is | 
| 514 |  |  * still valid. The rationale for doing this is the fact that it is not | 
| 515 |  |  * uncommon for daemons to close all open file handles when daemonizing. | 
| 516 |  |  * So the handle might have been closed or even reused for opening | 
| 517 |  |  * another file. | 
| 518 |  |  */ | 
| 519 |  | static int check_random_device(struct random_device * rd) | 
| 520 | 88 | { | 
| 521 | 88 |     struct stat st; | 
| 522 |  |  | 
| 523 | 88 |     return rd->fd != -1 | 
| 524 | 88 |            && fstat(rd->fd, &st) != -1 | 
| 525 | 88 |            && rd->dev == st.st_dev | 
| 526 | 88 |            && rd->ino == st.st_ino | 
| 527 | 88 |            && ((rd->mode ^ st.st_mode) & ~(S_IRWXU | S_IRWXG | S_IRWXO)) == 0 | 
| 528 | 88 |            && rd->rdev == st.st_rdev; | 
| 529 | 88 | } | 
| 530 |  |  | 
| 531 |  | /* | 
| 532 |  |  * Open a random device if required and return its file descriptor or -1 on error | 
| 533 |  |  */ | 
| 534 |  | static int get_random_device(size_t n) | 
| 535 | 0 | { | 
| 536 | 0 |     struct stat st; | 
| 537 | 0 |     struct random_device * rd = &random_devices[n]; | 
| 538 |  |  | 
| 539 |  |     /* reuse existing file descriptor if it is (still) valid */ | 
| 540 | 0 |     if (check_random_device(rd)) | 
| 541 | 0 |         return rd->fd; | 
| 542 |  |  | 
| 543 |  |     /* open the random device ... */ | 
| 544 | 0 |     if ((rd->fd = open(random_device_paths[n], O_RDONLY)) == -1) | 
| 545 | 0 |         return rd->fd; | 
| 546 |  |  | 
| 547 |  |     /* ... and cache its relevant stat(2) data */ | 
| 548 | 0 |     if (fstat(rd->fd, &st) != -1) { | 
| 549 | 0 |         rd->dev = st.st_dev; | 
| 550 | 0 |         rd->ino = st.st_ino; | 
| 551 | 0 |         rd->mode = st.st_mode; | 
| 552 | 0 |         rd->rdev = st.st_rdev; | 
| 553 | 0 |     } else { | 
| 554 | 0 |         close(rd->fd); | 
| 555 | 0 |         rd->fd = -1; | 
| 556 | 0 |     } | 
| 557 |  | 
 | 
| 558 | 0 |     return rd->fd; | 
| 559 | 0 | } | 
| 560 |  |  | 
| 561 |  | /* | 
| 562 |  |  * Close a random device making sure it is a random device | 
| 563 |  |  */ | 
| 564 |  | static void close_random_device(size_t n) | 
| 565 | 88 | { | 
| 566 | 88 |     struct random_device * rd = &random_devices[n]; | 
| 567 |  |  | 
| 568 | 88 |     if (check_random_device(rd)) | 
| 569 | 0 |         close(rd->fd); | 
| 570 | 88 |     rd->fd = -1; | 
| 571 | 88 | } | 
| 572 |  |  | 
| 573 |  | int rand_pool_init(void) | 
| 574 | 9 | { | 
| 575 | 9 |     size_t i; | 
| 576 |  |  | 
| 577 | 45 |     for (i = 0; i < OSSL_NELEM(random_devices); i++) | 
| 578 | 36 |         random_devices[i].fd = -1; | 
| 579 |  |  | 
| 580 | 9 |     return 1; | 
| 581 | 9 | } | 
| 582 |  |  | 
| 583 |  | void rand_pool_cleanup(void) | 
| 584 | 9 | { | 
| 585 | 9 |     size_t i; | 
| 586 |  |  | 
| 587 | 45 |     for (i = 0; i < OSSL_NELEM(random_devices); i++) | 
| 588 | 36 |         close_random_device(i); | 
| 589 | 9 | } | 
| 590 |  |  | 
| 591 |  | void rand_pool_keep_random_devices_open(int keep) | 
| 592 | 0 | { | 
| 593 | 0 |     if (!keep) | 
| 594 | 0 |         rand_pool_cleanup(); | 
| 595 |  | 
 | 
| 596 | 0 |     keep_random_devices_open = keep; | 
| 597 | 0 | } | 
| 598 |  |  | 
| 599 |  | #  else     /* !defined(OPENSSL_RAND_SEED_DEVRANDOM) */ | 
| 600 |  |  | 
| 601 |  | int rand_pool_init(void) | 
| 602 |  | { | 
| 603 |  |     return 1; | 
| 604 |  | } | 
| 605 |  |  | 
| 606 |  | void rand_pool_cleanup(void) | 
| 607 |  | { | 
| 608 |  | } | 
| 609 |  |  | 
| 610 |  | void rand_pool_keep_random_devices_open(int keep) | 
| 611 |  | { | 
| 612 |  | } | 
| 613 |  |  | 
| 614 |  | #  endif    /* defined(OPENSSL_RAND_SEED_DEVRANDOM) */ | 
| 615 |  |  | 
| 616 |  | /* | 
| 617 |  |  * Try the various seeding methods in turn, exit when successful. | 
| 618 |  |  * | 
| 619 |  |  * TODO(DRBG): If more than one entropy source is available, is it | 
| 620 |  |  * preferable to stop as soon as enough entropy has been collected | 
| 621 |  |  * (as favored by @rsalz) or should one rather be defensive and add | 
| 622 |  |  * more entropy than requested and/or from different sources? | 
| 623 |  |  * | 
| 624 |  |  * Currently, the user can select multiple entropy sources in the | 
| 625 |  |  * configure step, yet in practice only the first available source | 
| 626 |  |  * will be used. A more flexible solution has been requested, but | 
| 627 |  |  * currently it is not clear how this can be achieved without | 
| 628 |  |  * overengineering the problem. There are many parameters which | 
| 629 |  |  * could be taken into account when selecting the order and amount | 
| 630 |  |  * of input from the different entropy sources (trust, quality, | 
| 631 |  |  * possibility of blocking). | 
| 632 |  |  */ | 
| 633 |  | size_t rand_pool_acquire_entropy(RAND_POOL *pool) | 
| 634 | 1 | { | 
| 635 |  | #  if defined(OPENSSL_RAND_SEED_NONE) | 
| 636 |  |     return rand_pool_entropy_available(pool); | 
| 637 |  | #  else | 
| 638 | 1 |     size_t entropy_available; | 
| 639 |  |  | 
| 640 | 1 | #   if defined(OPENSSL_RAND_SEED_GETRANDOM) | 
| 641 | 1 |     { | 
| 642 | 1 |         size_t bytes_needed; | 
| 643 | 1 |         unsigned char *buffer; | 
| 644 | 1 |         ssize_t bytes; | 
| 645 |  |         /* Maximum allowed number of consecutive unsuccessful attempts */ | 
| 646 | 1 |         int attempts = 3; | 
| 647 |  |  | 
| 648 | 1 |         bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); | 
| 649 | 2 |         while (bytes_needed != 0 && attempts-- > 0) { | 
| 650 | 1 |             buffer = rand_pool_add_begin(pool, bytes_needed); | 
| 651 | 1 |             bytes = syscall_random(buffer, bytes_needed); | 
| 652 | 1 |             if (bytes > 0) { | 
| 653 | 1 |                 rand_pool_add_end(pool, bytes, 8 * bytes); | 
| 654 | 1 |                 bytes_needed -= bytes; | 
| 655 | 1 |                 attempts = 3; /* reset counter after successful attempt */ | 
| 656 | 1 |             } else if (bytes < 0 && errno != EINTR) { | 
| 657 | 0 |                 break; | 
| 658 | 0 |             } | 
| 659 | 1 |         } | 
| 660 | 1 |     } | 
| 661 | 1 |     entropy_available = rand_pool_entropy_available(pool); | 
| 662 | 1 |     if (entropy_available > 0) | 
| 663 | 1 |         return entropy_available; | 
| 664 | 0 | #   endif | 
| 665 |  |  | 
| 666 |  | #   if defined(OPENSSL_RAND_SEED_LIBRANDOM) | 
| 667 |  |     { | 
| 668 |  |         /* Not yet implemented. */ | 
| 669 |  |     } | 
| 670 |  | #   endif | 
| 671 |  |  | 
| 672 | 0 | #   if defined(OPENSSL_RAND_SEED_DEVRANDOM) | 
| 673 | 0 |     if (wait_random_seeded()) { | 
| 674 | 0 |         size_t bytes_needed; | 
| 675 | 0 |         unsigned char *buffer; | 
| 676 | 0 |         size_t i; | 
| 677 |  | 
 | 
| 678 | 0 |         bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); | 
| 679 | 0 |         for (i = 0; bytes_needed > 0 && i < OSSL_NELEM(random_device_paths); | 
| 680 | 0 |              i++) { | 
| 681 | 0 |             ssize_t bytes = 0; | 
| 682 |  |             /* Maximum number of consecutive unsuccessful attempts */ | 
| 683 | 0 |             int attempts = 3; | 
| 684 | 0 |             const int fd = get_random_device(i); | 
| 685 |  | 
 | 
| 686 | 0 |             if (fd == -1) | 
| 687 | 0 |                 continue; | 
| 688 |  |  | 
| 689 | 0 |             while (bytes_needed != 0 && attempts-- > 0) { | 
| 690 | 0 |                 buffer = rand_pool_add_begin(pool, bytes_needed); | 
| 691 | 0 |                 bytes = read(fd, buffer, bytes_needed); | 
| 692 |  | 
 | 
| 693 | 0 |                 if (bytes > 0) { | 
| 694 | 0 |                     rand_pool_add_end(pool, bytes, 8 * bytes); | 
| 695 | 0 |                     bytes_needed -= bytes; | 
| 696 | 0 |                     attempts = 3; /* reset counter on successful attempt */ | 
| 697 | 0 |                 } else if (bytes < 0 && errno != EINTR) { | 
| 698 | 0 |                     break; | 
| 699 | 0 |                 } | 
| 700 | 0 |             } | 
| 701 | 0 |             if (bytes < 0 || !keep_random_devices_open) | 
| 702 | 0 |                 close_random_device(i); | 
| 703 |  | 
 | 
| 704 | 0 |             bytes_needed = rand_pool_bytes_needed(pool, 1); | 
| 705 | 0 |         } | 
| 706 | 0 |         entropy_available = rand_pool_entropy_available(pool); | 
| 707 | 0 |         if (entropy_available > 0) | 
| 708 | 0 |             return entropy_available; | 
| 709 | 0 |     } | 
| 710 | 0 | #   endif | 
| 711 |  |  | 
| 712 |  | #   if defined(OPENSSL_RAND_SEED_RDTSC) | 
| 713 |  |     entropy_available = rand_acquire_entropy_from_tsc(pool); | 
| 714 |  |     if (entropy_available > 0) | 
| 715 |  |         return entropy_available; | 
| 716 |  | #   endif | 
| 717 |  |  | 
| 718 |  | #   if defined(OPENSSL_RAND_SEED_RDCPU) | 
| 719 |  |     entropy_available = rand_acquire_entropy_from_cpu(pool); | 
| 720 |  |     if (entropy_available > 0) | 
| 721 |  |         return entropy_available; | 
| 722 |  | #   endif | 
| 723 |  |  | 
| 724 |  | #   if defined(OPENSSL_RAND_SEED_EGD) | 
| 725 |  |     { | 
| 726 |  |         static const char *paths[] = { DEVRANDOM_EGD, NULL }; | 
| 727 |  |         size_t bytes_needed; | 
| 728 |  |         unsigned char *buffer; | 
| 729 |  |         int i; | 
| 730 |  |  | 
| 731 |  |         bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); | 
| 732 |  |         for (i = 0; bytes_needed > 0 && paths[i] != NULL; i++) { | 
| 733 |  |             size_t bytes = 0; | 
| 734 |  |             int num; | 
| 735 |  |  | 
| 736 |  |             buffer = rand_pool_add_begin(pool, bytes_needed); | 
| 737 |  |             num = RAND_query_egd_bytes(paths[i], | 
| 738 |  |                                        buffer, (int)bytes_needed); | 
| 739 |  |             if (num == (int)bytes_needed) | 
| 740 |  |                 bytes = bytes_needed; | 
| 741 |  |  | 
| 742 |  |             rand_pool_add_end(pool, bytes, 8 * bytes); | 
| 743 |  |             bytes_needed = rand_pool_bytes_needed(pool, 1); | 
| 744 |  |         } | 
| 745 |  |         entropy_available = rand_pool_entropy_available(pool); | 
| 746 |  |         if (entropy_available > 0) | 
| 747 |  |             return entropy_available; | 
| 748 |  |     } | 
| 749 |  | #   endif | 
| 750 |  |  | 
| 751 | 0 |     return rand_pool_entropy_available(pool); | 
| 752 | 0 | #  endif | 
| 753 | 0 | } | 
| 754 |  | # endif | 
| 755 |  | #endif | 
| 756 |  |  | 
| 757 |  | #if defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__) | 
| 758 |  | int rand_pool_add_nonce_data(RAND_POOL *pool) | 
| 759 | 1 | { | 
| 760 | 1 |     struct { | 
| 761 | 1 |         pid_t pid; | 
| 762 | 1 |         CRYPTO_THREAD_ID tid; | 
| 763 | 1 |         uint64_t time; | 
| 764 | 1 |     } data = { 0 }; | 
| 765 |  |  | 
| 766 |  |     /* | 
| 767 |  |      * Add process id, thread id, and a high resolution timestamp to | 
| 768 |  |      * ensure that the nonce is unique with high probability for | 
| 769 |  |      * different process instances. | 
| 770 |  |      */ | 
| 771 | 1 |     data.pid = getpid(); | 
| 772 | 1 |     data.tid = CRYPTO_THREAD_get_current_id(); | 
| 773 | 1 |     data.time = get_time_stamp(); | 
| 774 |  |  | 
| 775 | 1 |     return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); | 
| 776 | 1 | } | 
| 777 |  |  | 
| 778 |  | int rand_pool_add_additional_data(RAND_POOL *pool) | 
| 779 | 16.1k | { | 
| 780 | 16.1k |     struct { | 
| 781 | 16.1k |         int fork_id; | 
| 782 | 16.1k |         CRYPTO_THREAD_ID tid; | 
| 783 | 16.1k |         uint64_t time; | 
| 784 | 16.1k |     } data = { 0 }; | 
| 785 |  |  | 
| 786 |  |     /* | 
| 787 |  |      * Add some noise from the thread id and a high resolution timer. | 
| 788 |  |      * The fork_id adds some extra fork-safety. | 
| 789 |  |      * The thread id adds a little randomness if the drbg is accessed | 
| 790 |  |      * concurrently (which is the case for the <master> drbg). | 
| 791 |  |      */ | 
| 792 | 16.1k |     data.fork_id = openssl_get_fork_id(); | 
| 793 | 16.1k |     data.tid = CRYPTO_THREAD_get_current_id(); | 
| 794 | 16.1k |     data.time = get_timer_bits(); | 
| 795 |  |  | 
| 796 | 16.1k |     return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); | 
| 797 | 16.1k | } | 
| 798 |  |  | 
| 799 |  |  | 
| 800 |  | /* | 
| 801 |  |  * Get the current time with the highest possible resolution | 
| 802 |  |  * | 
| 803 |  |  * The time stamp is added to the nonce, so it is optimized for not repeating. | 
| 804 |  |  * The current time is ideal for this purpose, provided the computer's clock | 
| 805 |  |  * is synchronized. | 
| 806 |  |  */ | 
| 807 |  | static uint64_t get_time_stamp(void) | 
| 808 | 1 | { | 
| 809 | 1 | # if defined(OSSL_POSIX_TIMER_OKAY) | 
| 810 | 1 |     { | 
| 811 | 1 |         struct timespec ts; | 
| 812 |  |  | 
| 813 | 1 |         if (clock_gettime(CLOCK_REALTIME, &ts) == 0) | 
| 814 | 1 |             return TWO32TO64(ts.tv_sec, ts.tv_nsec); | 
| 815 | 1 |     } | 
| 816 | 0 | # endif | 
| 817 | 0 | # if defined(__unix__) \ | 
| 818 | 0 |      || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) | 
| 819 | 0 |     { | 
| 820 | 0 |         struct timeval tv; | 
| 821 |  | 
 | 
| 822 | 0 |         if (gettimeofday(&tv, NULL) == 0) | 
| 823 | 0 |             return TWO32TO64(tv.tv_sec, tv.tv_usec); | 
| 824 | 0 |     } | 
| 825 | 0 | # endif | 
| 826 | 0 |     return time(NULL); | 
| 827 | 0 | } | 
| 828 |  |  | 
| 829 |  | /* | 
| 830 |  |  * Get an arbitrary timer value of the highest possible resolution | 
| 831 |  |  * | 
| 832 |  |  * The timer value is added as random noise to the additional data, | 
| 833 |  |  * which is not considered a trusted entropy sourec, so any result | 
| 834 |  |  * is acceptable. | 
| 835 |  |  */ | 
| 836 |  | static uint64_t get_timer_bits(void) | 
| 837 | 16.1k | { | 
| 838 | 16.1k |     uint64_t res = OPENSSL_rdtsc(); | 
| 839 |  |  | 
| 840 | 16.1k |     if (res != 0) | 
| 841 | 16.1k |         return res; | 
| 842 |  |  | 
| 843 |  | # if defined(__sun) || defined(__hpux) | 
| 844 |  |     return gethrtime(); | 
| 845 |  | # elif defined(_AIX) | 
| 846 |  |     { | 
| 847 |  |         timebasestruct_t t; | 
| 848 |  |  | 
| 849 |  |         read_wall_time(&t, TIMEBASE_SZ); | 
| 850 |  |         return TWO32TO64(t.tb_high, t.tb_low); | 
| 851 |  |     } | 
| 852 |  | # elif defined(OSSL_POSIX_TIMER_OKAY) | 
| 853 | 0 |     { | 
| 854 | 0 |         struct timespec ts; | 
| 855 |  | 
 | 
| 856 | 0 | #  ifdef CLOCK_BOOTTIME | 
| 857 | 0 | #   define CLOCK_TYPE CLOCK_BOOTTIME | 
| 858 |  | #  elif defined(_POSIX_MONOTONIC_CLOCK) | 
| 859 |  | #   define CLOCK_TYPE CLOCK_MONOTONIC | 
| 860 |  | #  else | 
| 861 |  | #   define CLOCK_TYPE CLOCK_REALTIME | 
| 862 |  | #  endif | 
| 863 |  | 
 | 
| 864 | 0 |         if (clock_gettime(CLOCK_TYPE, &ts) == 0) | 
| 865 | 0 |             return TWO32TO64(ts.tv_sec, ts.tv_nsec); | 
| 866 | 0 |     } | 
| 867 | 0 | # endif | 
| 868 | 0 | # if defined(__unix__) \ | 
| 869 | 0 |      || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) | 
| 870 | 0 |     { | 
| 871 | 0 |         struct timeval tv; | 
| 872 |  | 
 | 
| 873 | 0 |         if (gettimeofday(&tv, NULL) == 0) | 
| 874 | 0 |             return TWO32TO64(tv.tv_sec, tv.tv_usec); | 
| 875 | 0 |     } | 
| 876 | 0 | # endif | 
| 877 | 0 |     return time(NULL); | 
| 878 | 0 | } | 
| 879 |  | #endif /* (defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_SYS_VXWORKS)) | 
| 880 |  |           || defined(__DJGPP__) */ |