security/nss/lib/freebl/unix_rand.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include <stdio.h>
michael@0 6 #include <string.h>
michael@0 7 #include <signal.h>
michael@0 8 #include <unistd.h>
michael@0 9 #include <limits.h>
michael@0 10 #include <errno.h>
michael@0 11 #include <stdlib.h>
michael@0 12 #include <sys/time.h>
michael@0 13 #include <sys/wait.h>
michael@0 14 #include <sys/stat.h>
michael@0 15 #include "secrng.h"
michael@0 16 #include "secerr.h"
michael@0 17 #include "prerror.h"
michael@0 18 #include "prthread.h"
michael@0 19 #include "prprf.h"
michael@0 20
michael@0 21 size_t RNG_FileUpdate(const char *fileName, size_t limit);
michael@0 22
michael@0 23 /*
michael@0 24 * When copying data to the buffer we want the least signicant bytes
michael@0 25 * from the input since those bits are changing the fastest. The address
michael@0 26 * of least significant byte depends upon whether we are running on
michael@0 27 * a big-endian or little-endian machine.
michael@0 28 *
michael@0 29 * Does this mean the least signicant bytes are the most significant
michael@0 30 * to us? :-)
michael@0 31 */
michael@0 32
michael@0 33 static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen)
michael@0 34 {
michael@0 35 union endianness {
michael@0 36 PRInt32 i;
michael@0 37 char c[4];
michael@0 38 } u;
michael@0 39
michael@0 40 if (srclen <= dstlen) {
michael@0 41 memcpy(dst, src, srclen);
michael@0 42 return srclen;
michael@0 43 }
michael@0 44 u.i = 0x01020304;
michael@0 45 if (u.c[0] == 0x01) {
michael@0 46 /* big-endian case */
michael@0 47 memcpy(dst, (char*)src + (srclen - dstlen), dstlen);
michael@0 48 } else {
michael@0 49 /* little-endian case */
michael@0 50 memcpy(dst, src, dstlen);
michael@0 51 }
michael@0 52 return dstlen;
michael@0 53 }
michael@0 54
michael@0 55 #ifdef SOLARIS
michael@0 56
michael@0 57 #include <kstat.h>
michael@0 58
michael@0 59 static const PRUint32 entropy_buf_len = 4096; /* buffer up to 4 KB */
michael@0 60
michael@0 61 /* Buffer entropy data, and feed it to the RNG, entropy_buf_len bytes at a time.
michael@0 62 * Returns error if RNG_RandomUpdate fails. Also increments *total_fed
michael@0 63 * by the number of bytes successfully buffered.
michael@0 64 */
michael@0 65 static SECStatus BufferEntropy(char* inbuf, PRUint32 inlen,
michael@0 66 char* entropy_buf, PRUint32* entropy_buffered,
michael@0 67 PRUint32* total_fed)
michael@0 68 {
michael@0 69 PRUint32 tocopy = 0;
michael@0 70 PRUint32 avail = 0;
michael@0 71 SECStatus rv = SECSuccess;
michael@0 72
michael@0 73 while (inlen) {
michael@0 74 avail = entropy_buf_len - *entropy_buffered;
michael@0 75 if (!avail) {
michael@0 76 /* Buffer is full, time to feed it to the RNG. */
michael@0 77 rv = RNG_RandomUpdate(entropy_buf, entropy_buf_len);
michael@0 78 if (SECSuccess != rv) {
michael@0 79 break;
michael@0 80 }
michael@0 81 *entropy_buffered = 0;
michael@0 82 avail = entropy_buf_len;
michael@0 83 }
michael@0 84 tocopy = PR_MIN(avail, inlen);
michael@0 85 memcpy(entropy_buf + *entropy_buffered, inbuf, tocopy);
michael@0 86 *entropy_buffered += tocopy;
michael@0 87 inlen -= tocopy;
michael@0 88 inbuf += tocopy;
michael@0 89 *total_fed += tocopy;
michael@0 90 }
michael@0 91 return rv;
michael@0 92 }
michael@0 93
michael@0 94 /* Feed kernel statistics structures and ks_data field to the RNG.
michael@0 95 * Returns status as well as the number of bytes successfully fed to the RNG.
michael@0 96 */
michael@0 97 static SECStatus RNG_kstat(PRUint32* fed)
michael@0 98 {
michael@0 99 kstat_ctl_t* kc = NULL;
michael@0 100 kstat_t* ksp = NULL;
michael@0 101 PRUint32 entropy_buffered = 0;
michael@0 102 char* entropy_buf = NULL;
michael@0 103 SECStatus rv = SECSuccess;
michael@0 104
michael@0 105 PORT_Assert(fed);
michael@0 106 if (!fed) {
michael@0 107 return SECFailure;
michael@0 108 }
michael@0 109 *fed = 0;
michael@0 110
michael@0 111 kc = kstat_open();
michael@0 112 PORT_Assert(kc);
michael@0 113 if (!kc) {
michael@0 114 return SECFailure;
michael@0 115 }
michael@0 116 entropy_buf = (char*) PORT_Alloc(entropy_buf_len);
michael@0 117 PORT_Assert(entropy_buf);
michael@0 118 if (entropy_buf) {
michael@0 119 for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
michael@0 120 if (-1 == kstat_read(kc, ksp, NULL)) {
michael@0 121 /* missing data from a single kstat shouldn't be fatal */
michael@0 122 continue;
michael@0 123 }
michael@0 124 rv = BufferEntropy((char*)ksp, sizeof(kstat_t),
michael@0 125 entropy_buf, &entropy_buffered,
michael@0 126 fed);
michael@0 127 if (SECSuccess != rv) {
michael@0 128 break;
michael@0 129 }
michael@0 130
michael@0 131 if (ksp->ks_data && ksp->ks_data_size>0 && ksp->ks_ndata>0) {
michael@0 132 rv = BufferEntropy((char*)ksp->ks_data, ksp->ks_data_size,
michael@0 133 entropy_buf, &entropy_buffered,
michael@0 134 fed);
michael@0 135 if (SECSuccess != rv) {
michael@0 136 break;
michael@0 137 }
michael@0 138 }
michael@0 139 }
michael@0 140 if (SECSuccess == rv && entropy_buffered) {
michael@0 141 /* Buffer is not empty, time to feed it to the RNG */
michael@0 142 rv = RNG_RandomUpdate(entropy_buf, entropy_buffered);
michael@0 143 }
michael@0 144 PORT_Free(entropy_buf);
michael@0 145 } else {
michael@0 146 rv = SECFailure;
michael@0 147 }
michael@0 148 if (kstat_close(kc)) {
michael@0 149 PORT_Assert(0);
michael@0 150 rv = SECFailure;
michael@0 151 }
michael@0 152 return rv;
michael@0 153 }
michael@0 154
michael@0 155 #endif
michael@0 156
michael@0 157 #if defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(FREEBSD) \
michael@0 158 || defined(NETBSD) || defined(DARWIN) || defined(OPENBSD) \
michael@0 159 || defined(NTO) || defined(__riscos__)
michael@0 160 #include <sys/times.h>
michael@0 161
michael@0 162 #define getdtablesize() sysconf(_SC_OPEN_MAX)
michael@0 163
michael@0 164 static size_t
michael@0 165 GetHighResClock(void *buf, size_t maxbytes)
michael@0 166 {
michael@0 167 int ticks;
michael@0 168 struct tms buffer;
michael@0 169
michael@0 170 ticks=times(&buffer);
michael@0 171 return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
michael@0 172 }
michael@0 173
michael@0 174 static void
michael@0 175 GiveSystemInfo(void)
michael@0 176 {
michael@0 177 long si;
michael@0 178
michael@0 179 /*
michael@0 180 * Is this really necessary? Why not use rand48 or something?
michael@0 181 */
michael@0 182 si = sysconf(_SC_CHILD_MAX);
michael@0 183 RNG_RandomUpdate(&si, sizeof(si));
michael@0 184
michael@0 185 si = sysconf(_SC_STREAM_MAX);
michael@0 186 RNG_RandomUpdate(&si, sizeof(si));
michael@0 187
michael@0 188 si = sysconf(_SC_OPEN_MAX);
michael@0 189 RNG_RandomUpdate(&si, sizeof(si));
michael@0 190 }
michael@0 191 #endif
michael@0 192
michael@0 193 #if defined(__sun)
michael@0 194 #if defined(__svr4) || defined(SVR4)
michael@0 195 #include <sys/systeminfo.h>
michael@0 196
michael@0 197 #define getdtablesize() sysconf(_SC_OPEN_MAX)
michael@0 198
michael@0 199 static void
michael@0 200 GiveSystemInfo(void)
michael@0 201 {
michael@0 202 int rv;
michael@0 203 char buf[2000];
michael@0 204
michael@0 205 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
michael@0 206 if (rv > 0) {
michael@0 207 RNG_RandomUpdate(buf, rv);
michael@0 208 }
michael@0 209 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
michael@0 210 if (rv > 0) {
michael@0 211 RNG_RandomUpdate(buf, rv);
michael@0 212 }
michael@0 213 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
michael@0 214 if (rv > 0) {
michael@0 215 RNG_RandomUpdate(buf, rv);
michael@0 216 }
michael@0 217 }
michael@0 218
michael@0 219 static size_t
michael@0 220 GetHighResClock(void *buf, size_t maxbytes)
michael@0 221 {
michael@0 222 hrtime_t t;
michael@0 223 t = gethrtime();
michael@0 224 if (t) {
michael@0 225 return CopyLowBits(buf, maxbytes, &t, sizeof(t));
michael@0 226 }
michael@0 227 return 0;
michael@0 228 }
michael@0 229 #else /* SunOS (Sun, but not SVR4) */
michael@0 230
michael@0 231 extern long sysconf(int name);
michael@0 232
michael@0 233 static size_t
michael@0 234 GetHighResClock(void *buf, size_t maxbytes)
michael@0 235 {
michael@0 236 return 0;
michael@0 237 }
michael@0 238
michael@0 239 static void
michael@0 240 GiveSystemInfo(void)
michael@0 241 {
michael@0 242 long si;
michael@0 243
michael@0 244 /* This is not very good */
michael@0 245 si = sysconf(_SC_CHILD_MAX);
michael@0 246 RNG_RandomUpdate(&si, sizeof(si));
michael@0 247 }
michael@0 248 #endif
michael@0 249 #endif /* Sun */
michael@0 250
michael@0 251 #if defined(__hpux)
michael@0 252 #include <sys/unistd.h>
michael@0 253
michael@0 254 #define getdtablesize() sysconf(_SC_OPEN_MAX)
michael@0 255
michael@0 256 #if defined(__ia64)
michael@0 257 #include <ia64/sys/inline.h>
michael@0 258
michael@0 259 static size_t
michael@0 260 GetHighResClock(void *buf, size_t maxbytes)
michael@0 261 {
michael@0 262 PRUint64 t;
michael@0 263
michael@0 264 t = _Asm_mov_from_ar(_AREG44);
michael@0 265 return CopyLowBits(buf, maxbytes, &t, sizeof(t));
michael@0 266 }
michael@0 267 #else
michael@0 268 static size_t
michael@0 269 GetHighResClock(void *buf, size_t maxbytes)
michael@0 270 {
michael@0 271 extern int ret_cr16();
michael@0 272 int cr16val;
michael@0 273
michael@0 274 cr16val = ret_cr16();
michael@0 275 return CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val));
michael@0 276 }
michael@0 277 #endif
michael@0 278
michael@0 279 static void
michael@0 280 GiveSystemInfo(void)
michael@0 281 {
michael@0 282 long si;
michael@0 283
michael@0 284 /* This is not very good */
michael@0 285 si = sysconf(_AES_OS_VERSION);
michael@0 286 RNG_RandomUpdate(&si, sizeof(si));
michael@0 287 si = sysconf(_SC_CPU_VERSION);
michael@0 288 RNG_RandomUpdate(&si, sizeof(si));
michael@0 289 }
michael@0 290 #endif /* HPUX */
michael@0 291
michael@0 292 #if defined(OSF1)
michael@0 293 #include <sys/types.h>
michael@0 294 #include <sys/sysinfo.h>
michael@0 295 #include <sys/systeminfo.h>
michael@0 296 #include <c_asm.h>
michael@0 297
michael@0 298 static void
michael@0 299 GiveSystemInfo(void)
michael@0 300 {
michael@0 301 char buf[BUFSIZ];
michael@0 302 int rv;
michael@0 303 int off = 0;
michael@0 304
michael@0 305 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
michael@0 306 if (rv > 0) {
michael@0 307 RNG_RandomUpdate(buf, rv);
michael@0 308 }
michael@0 309 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
michael@0 310 if (rv > 0) {
michael@0 311 RNG_RandomUpdate(buf, rv);
michael@0 312 }
michael@0 313 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
michael@0 314 if (rv > 0) {
michael@0 315 RNG_RandomUpdate(buf, rv);
michael@0 316 }
michael@0 317 }
michael@0 318
michael@0 319 /*
michael@0 320 * Use the "get the cycle counter" instruction on the alpha.
michael@0 321 * The low 32 bits completely turn over in less than a minute.
michael@0 322 * The high 32 bits are some non-counter gunk that changes sometimes.
michael@0 323 */
michael@0 324 static size_t
michael@0 325 GetHighResClock(void *buf, size_t maxbytes)
michael@0 326 {
michael@0 327 unsigned long t;
michael@0 328
michael@0 329 t = asm("rpcc %v0");
michael@0 330 return CopyLowBits(buf, maxbytes, &t, sizeof(t));
michael@0 331 }
michael@0 332
michael@0 333 #endif /* Alpha */
michael@0 334
michael@0 335 #if defined(_IBMR2)
michael@0 336 static size_t
michael@0 337 GetHighResClock(void *buf, size_t maxbytes)
michael@0 338 {
michael@0 339 return 0;
michael@0 340 }
michael@0 341
michael@0 342 static void
michael@0 343 GiveSystemInfo(void)
michael@0 344 {
michael@0 345 /* XXX haven't found any yet! */
michael@0 346 }
michael@0 347 #endif /* IBM R2 */
michael@0 348
michael@0 349 #if defined(LINUX)
michael@0 350 #include <sys/sysinfo.h>
michael@0 351
michael@0 352 static size_t
michael@0 353 GetHighResClock(void *buf, size_t maxbytes)
michael@0 354 {
michael@0 355 return 0;
michael@0 356 }
michael@0 357
michael@0 358 static void
michael@0 359 GiveSystemInfo(void)
michael@0 360 {
michael@0 361 #ifndef NO_SYSINFO
michael@0 362 struct sysinfo si;
michael@0 363 if (sysinfo(&si) == 0) {
michael@0 364 RNG_RandomUpdate(&si, sizeof(si));
michael@0 365 }
michael@0 366 #endif
michael@0 367 }
michael@0 368 #endif /* LINUX */
michael@0 369
michael@0 370 #if defined(NCR)
michael@0 371
michael@0 372 #include <sys/utsname.h>
michael@0 373 #include <sys/systeminfo.h>
michael@0 374
michael@0 375 #define getdtablesize() sysconf(_SC_OPEN_MAX)
michael@0 376
michael@0 377 static size_t
michael@0 378 GetHighResClock(void *buf, size_t maxbytes)
michael@0 379 {
michael@0 380 return 0;
michael@0 381 }
michael@0 382
michael@0 383 static void
michael@0 384 GiveSystemInfo(void)
michael@0 385 {
michael@0 386 int rv;
michael@0 387 char buf[2000];
michael@0 388
michael@0 389 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
michael@0 390 if (rv > 0) {
michael@0 391 RNG_RandomUpdate(buf, rv);
michael@0 392 }
michael@0 393 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
michael@0 394 if (rv > 0) {
michael@0 395 RNG_RandomUpdate(buf, rv);
michael@0 396 }
michael@0 397 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
michael@0 398 if (rv > 0) {
michael@0 399 RNG_RandomUpdate(buf, rv);
michael@0 400 }
michael@0 401 }
michael@0 402
michael@0 403 #endif /* NCR */
michael@0 404
michael@0 405 #if defined(sgi)
michael@0 406 #include <fcntl.h>
michael@0 407 #undef PRIVATE
michael@0 408 #include <sys/mman.h>
michael@0 409 #include <sys/syssgi.h>
michael@0 410 #include <sys/immu.h>
michael@0 411 #include <sys/systeminfo.h>
michael@0 412 #include <sys/utsname.h>
michael@0 413 #include <wait.h>
michael@0 414
michael@0 415 static void
michael@0 416 GiveSystemInfo(void)
michael@0 417 {
michael@0 418 int rv;
michael@0 419 char buf[4096];
michael@0 420
michael@0 421 rv = syssgi(SGI_SYSID, &buf[0]);
michael@0 422 if (rv > 0) {
michael@0 423 RNG_RandomUpdate(buf, MAXSYSIDSIZE);
michael@0 424 }
michael@0 425 #ifdef SGI_RDUBLK
michael@0 426 rv = syssgi(SGI_RDUBLK, getpid(), &buf[0], sizeof(buf));
michael@0 427 if (rv > 0) {
michael@0 428 RNG_RandomUpdate(buf, sizeof(buf));
michael@0 429 }
michael@0 430 #endif /* SGI_RDUBLK */
michael@0 431 rv = syssgi(SGI_INVENT, SGI_INV_READ, buf, sizeof(buf));
michael@0 432 if (rv > 0) {
michael@0 433 RNG_RandomUpdate(buf, sizeof(buf));
michael@0 434 }
michael@0 435 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
michael@0 436 if (rv > 0) {
michael@0 437 RNG_RandomUpdate(buf, rv);
michael@0 438 }
michael@0 439 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
michael@0 440 if (rv > 0) {
michael@0 441 RNG_RandomUpdate(buf, rv);
michael@0 442 }
michael@0 443 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
michael@0 444 if (rv > 0) {
michael@0 445 RNG_RandomUpdate(buf, rv);
michael@0 446 }
michael@0 447 }
michael@0 448
michael@0 449 static size_t GetHighResClock(void *buf, size_t maxbuf)
michael@0 450 {
michael@0 451 unsigned phys_addr, raddr, cycleval;
michael@0 452 static volatile unsigned *iotimer_addr = NULL;
michael@0 453 static int tries = 0;
michael@0 454 static int cntr_size;
michael@0 455 int mfd;
michael@0 456 long s0[2];
michael@0 457 struct timeval tv;
michael@0 458
michael@0 459 #ifndef SGI_CYCLECNTR_SIZE
michael@0 460 #define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */
michael@0 461 #endif
michael@0 462
michael@0 463 if (iotimer_addr == NULL) {
michael@0 464 if (tries++ > 1) {
michael@0 465 /* Don't keep trying if it didn't work */
michael@0 466 return 0;
michael@0 467 }
michael@0 468
michael@0 469 /*
michael@0 470 ** For SGI machines we can use the cycle counter, if it has one,
michael@0 471 ** to generate some truly random numbers
michael@0 472 */
michael@0 473 phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
michael@0 474 if (phys_addr) {
michael@0 475 int pgsz = getpagesize();
michael@0 476 int pgoffmask = pgsz - 1;
michael@0 477
michael@0 478 raddr = phys_addr & ~pgoffmask;
michael@0 479 mfd = open("/dev/mmem", O_RDONLY);
michael@0 480 if (mfd < 0) {
michael@0 481 return 0;
michael@0 482 }
michael@0 483 iotimer_addr = (unsigned *)
michael@0 484 mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr);
michael@0 485 if (iotimer_addr == (void*)-1) {
michael@0 486 close(mfd);
michael@0 487 iotimer_addr = NULL;
michael@0 488 return 0;
michael@0 489 }
michael@0 490 iotimer_addr = (unsigned*)
michael@0 491 ((__psint_t)iotimer_addr | (phys_addr & pgoffmask));
michael@0 492 /*
michael@0 493 * The file 'mfd' is purposefully not closed.
michael@0 494 */
michael@0 495 cntr_size = syssgi(SGI_CYCLECNTR_SIZE);
michael@0 496 if (cntr_size < 0) {
michael@0 497 struct utsname utsinfo;
michael@0 498
michael@0 499 /*
michael@0 500 * We must be executing on a 6.0 or earlier system, since the
michael@0 501 * SGI_CYCLECNTR_SIZE call is not supported.
michael@0 502 *
michael@0 503 * The only pre-6.1 platforms with 64-bit counters are
michael@0 504 * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
michael@0 505 */
michael@0 506 uname(&utsinfo);
michael@0 507 if (!strncmp(utsinfo.machine, "IP19", 4) ||
michael@0 508 !strncmp(utsinfo.machine, "IP21", 4))
michael@0 509 cntr_size = 64;
michael@0 510 else
michael@0 511 cntr_size = 32;
michael@0 512 }
michael@0 513 cntr_size /= 8; /* Convert from bits to bytes */
michael@0 514 }
michael@0 515 }
michael@0 516
michael@0 517 s0[0] = *iotimer_addr;
michael@0 518 if (cntr_size > 4)
michael@0 519 s0[1] = *(iotimer_addr + 1);
michael@0 520 memcpy(buf, (char *)&s0[0], cntr_size);
michael@0 521 return CopyLowBits(buf, maxbuf, &s0, cntr_size);
michael@0 522 }
michael@0 523 #endif
michael@0 524
michael@0 525 #if defined(sony)
michael@0 526 #include <sys/systeminfo.h>
michael@0 527
michael@0 528 #define getdtablesize() sysconf(_SC_OPEN_MAX)
michael@0 529
michael@0 530 static size_t
michael@0 531 GetHighResClock(void *buf, size_t maxbytes)
michael@0 532 {
michael@0 533 return 0;
michael@0 534 }
michael@0 535
michael@0 536 static void
michael@0 537 GiveSystemInfo(void)
michael@0 538 {
michael@0 539 int rv;
michael@0 540 char buf[2000];
michael@0 541
michael@0 542 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
michael@0 543 if (rv > 0) {
michael@0 544 RNG_RandomUpdate(buf, rv);
michael@0 545 }
michael@0 546 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
michael@0 547 if (rv > 0) {
michael@0 548 RNG_RandomUpdate(buf, rv);
michael@0 549 }
michael@0 550 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
michael@0 551 if (rv > 0) {
michael@0 552 RNG_RandomUpdate(buf, rv);
michael@0 553 }
michael@0 554 }
michael@0 555 #endif /* sony */
michael@0 556
michael@0 557 #if defined(sinix)
michael@0 558 #include <sys/systeminfo.h>
michael@0 559 #include <sys/times.h>
michael@0 560
michael@0 561 int gettimeofday(struct timeval *, struct timezone *);
michael@0 562 int gethostname(char *, int);
michael@0 563
michael@0 564 #define getdtablesize() sysconf(_SC_OPEN_MAX)
michael@0 565
michael@0 566 static size_t
michael@0 567 GetHighResClock(void *buf, size_t maxbytes)
michael@0 568 {
michael@0 569 int ticks;
michael@0 570 struct tms buffer;
michael@0 571
michael@0 572 ticks=times(&buffer);
michael@0 573 return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
michael@0 574 }
michael@0 575
michael@0 576 static void
michael@0 577 GiveSystemInfo(void)
michael@0 578 {
michael@0 579 int rv;
michael@0 580 char buf[2000];
michael@0 581
michael@0 582 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
michael@0 583 if (rv > 0) {
michael@0 584 RNG_RandomUpdate(buf, rv);
michael@0 585 }
michael@0 586 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
michael@0 587 if (rv > 0) {
michael@0 588 RNG_RandomUpdate(buf, rv);
michael@0 589 }
michael@0 590 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
michael@0 591 if (rv > 0) {
michael@0 592 RNG_RandomUpdate(buf, rv);
michael@0 593 }
michael@0 594 }
michael@0 595 #endif /* sinix */
michael@0 596
michael@0 597
michael@0 598 #ifdef BEOS
michael@0 599 #include <be/kernel/OS.h>
michael@0 600
michael@0 601 static size_t
michael@0 602 GetHighResClock(void *buf, size_t maxbytes)
michael@0 603 {
michael@0 604 bigtime_t bigtime; /* Actually a int64 */
michael@0 605
michael@0 606 bigtime = real_time_clock_usecs();
michael@0 607 return CopyLowBits(buf, maxbytes, &bigtime, sizeof(bigtime));
michael@0 608 }
michael@0 609
michael@0 610 static void
michael@0 611 GiveSystemInfo(void)
michael@0 612 {
michael@0 613 system_info *info = NULL;
michael@0 614 PRInt32 val;
michael@0 615 get_system_info(info);
michael@0 616 if (info) {
michael@0 617 val = info->boot_time;
michael@0 618 RNG_RandomUpdate(&val, sizeof(val));
michael@0 619 val = info->used_pages;
michael@0 620 RNG_RandomUpdate(&val, sizeof(val));
michael@0 621 val = info->used_ports;
michael@0 622 RNG_RandomUpdate(&val, sizeof(val));
michael@0 623 val = info->used_threads;
michael@0 624 RNG_RandomUpdate(&val, sizeof(val));
michael@0 625 val = info->used_teams;
michael@0 626 RNG_RandomUpdate(&val, sizeof(val));
michael@0 627 }
michael@0 628 }
michael@0 629 #endif /* BEOS */
michael@0 630
michael@0 631 #if defined(nec_ews)
michael@0 632 #include <sys/systeminfo.h>
michael@0 633
michael@0 634 #define getdtablesize() sysconf(_SC_OPEN_MAX)
michael@0 635
michael@0 636 static size_t
michael@0 637 GetHighResClock(void *buf, size_t maxbytes)
michael@0 638 {
michael@0 639 return 0;
michael@0 640 }
michael@0 641
michael@0 642 static void
michael@0 643 GiveSystemInfo(void)
michael@0 644 {
michael@0 645 int rv;
michael@0 646 char buf[2000];
michael@0 647
michael@0 648 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
michael@0 649 if (rv > 0) {
michael@0 650 RNG_RandomUpdate(buf, rv);
michael@0 651 }
michael@0 652 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
michael@0 653 if (rv > 0) {
michael@0 654 RNG_RandomUpdate(buf, rv);
michael@0 655 }
michael@0 656 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
michael@0 657 if (rv > 0) {
michael@0 658 RNG_RandomUpdate(buf, rv);
michael@0 659 }
michael@0 660 }
michael@0 661 #endif /* nec_ews */
michael@0 662
michael@0 663 size_t RNG_GetNoise(void *buf, size_t maxbytes)
michael@0 664 {
michael@0 665 struct timeval tv;
michael@0 666 int n = 0;
michael@0 667 int c;
michael@0 668
michael@0 669 n = GetHighResClock(buf, maxbytes);
michael@0 670 maxbytes -= n;
michael@0 671
michael@0 672 (void)gettimeofday(&tv, 0);
michael@0 673 c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_usec, sizeof(tv.tv_usec));
michael@0 674 n += c;
michael@0 675 maxbytes -= c;
michael@0 676 c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_sec, sizeof(tv.tv_sec));
michael@0 677 n += c;
michael@0 678 return n;
michael@0 679 }
michael@0 680
michael@0 681 #define SAFE_POPEN_MAXARGS 10 /* must be at least 2 */
michael@0 682
michael@0 683 /*
michael@0 684 * safe_popen is static to this module and we know what arguments it is
michael@0 685 * called with. Note that this version only supports a single open child
michael@0 686 * process at any time.
michael@0 687 */
michael@0 688 static pid_t safe_popen_pid;
michael@0 689 static struct sigaction oldact;
michael@0 690
michael@0 691 static FILE *
michael@0 692 safe_popen(char *cmd)
michael@0 693 {
michael@0 694 int p[2], fd, argc;
michael@0 695 pid_t pid;
michael@0 696 char *argv[SAFE_POPEN_MAXARGS + 1];
michael@0 697 FILE *fp;
michael@0 698 static char blank[] = " \t";
michael@0 699 static struct sigaction newact;
michael@0 700
michael@0 701 if (pipe(p) < 0)
michael@0 702 return 0;
michael@0 703
michael@0 704 fp = fdopen(p[0], "r");
michael@0 705 if (fp == 0) {
michael@0 706 close(p[0]);
michael@0 707 close(p[1]);
michael@0 708 return 0;
michael@0 709 }
michael@0 710
michael@0 711 /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */
michael@0 712 newact.sa_handler = SIG_DFL;
michael@0 713 newact.sa_flags = 0;
michael@0 714 sigfillset(&newact.sa_mask);
michael@0 715 sigaction (SIGCHLD, &newact, &oldact);
michael@0 716
michael@0 717 pid = fork();
michael@0 718 switch (pid) {
michael@0 719 int ndesc;
michael@0 720
michael@0 721 case -1:
michael@0 722 fclose(fp); /* this closes p[0], the fd associated with fp */
michael@0 723 close(p[1]);
michael@0 724 sigaction (SIGCHLD, &oldact, NULL);
michael@0 725 return 0;
michael@0 726
michael@0 727 case 0:
michael@0 728 /* dup write-side of pipe to stderr and stdout */
michael@0 729 if (p[1] != 1) dup2(p[1], 1);
michael@0 730 if (p[1] != 2) dup2(p[1], 2);
michael@0 731
michael@0 732 /*
michael@0 733 * close the other file descriptors, except stdin which we
michael@0 734 * try reassociating with /dev/null, first (bug 174993)
michael@0 735 */
michael@0 736 if (!freopen("/dev/null", "r", stdin))
michael@0 737 close(0);
michael@0 738 ndesc = getdtablesize();
michael@0 739 for (fd = PR_MIN(65536, ndesc); --fd > 2; close(fd));
michael@0 740
michael@0 741 /* clean up environment in the child process */
michael@0 742 putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc");
michael@0 743 putenv("SHELL=/bin/sh");
michael@0 744 putenv("IFS= \t");
michael@0 745
michael@0 746 /*
michael@0 747 * The caller may have passed us a string that is in text
michael@0 748 * space. It may be illegal to modify the string
michael@0 749 */
michael@0 750 cmd = strdup(cmd);
michael@0 751 /* format argv */
michael@0 752 argv[0] = strtok(cmd, blank);
michael@0 753 argc = 1;
michael@0 754 while ((argv[argc] = strtok(0, blank)) != 0) {
michael@0 755 if (++argc == SAFE_POPEN_MAXARGS) {
michael@0 756 argv[argc] = 0;
michael@0 757 break;
michael@0 758 }
michael@0 759 }
michael@0 760
michael@0 761 /* and away we go */
michael@0 762 execvp(argv[0], argv);
michael@0 763 exit(127);
michael@0 764 break;
michael@0 765
michael@0 766 default:
michael@0 767 close(p[1]);
michael@0 768 break;
michael@0 769 }
michael@0 770
michael@0 771 /* non-zero means there's a cmd running */
michael@0 772 safe_popen_pid = pid;
michael@0 773 return fp;
michael@0 774 }
michael@0 775
michael@0 776 static int
michael@0 777 safe_pclose(FILE *fp)
michael@0 778 {
michael@0 779 pid_t pid;
michael@0 780 int status = -1, rv;
michael@0 781
michael@0 782 if ((pid = safe_popen_pid) == 0)
michael@0 783 return -1;
michael@0 784 safe_popen_pid = 0;
michael@0 785
michael@0 786 fclose(fp);
michael@0 787
michael@0 788 /* yield the processor so the child gets some time to exit normally */
michael@0 789 PR_Sleep(PR_INTERVAL_NO_WAIT);
michael@0 790
michael@0 791 /* if the child hasn't exited, kill it -- we're done with its output */
michael@0 792 while ((rv = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR)
michael@0 793 ;
michael@0 794 if (rv == 0) {
michael@0 795 kill(pid, SIGKILL);
michael@0 796 while ((rv = waitpid(pid, &status, 0)) == -1 && errno == EINTR)
michael@0 797 ;
michael@0 798 }
michael@0 799
michael@0 800 /* Reset SIGCHLD signal hander before returning */
michael@0 801 sigaction(SIGCHLD, &oldact, NULL);
michael@0 802
michael@0 803 return status;
michael@0 804 }
michael@0 805
michael@0 806 #ifdef DARWIN
michael@0 807 #include <TargetConditionals.h>
michael@0 808 #if !TARGET_OS_IPHONE
michael@0 809 #include <crt_externs.h>
michael@0 810 #endif
michael@0 811 #endif
michael@0 812
michael@0 813 /* Fork netstat to collect its output by default. Do not unset this unless
michael@0 814 * another source of entropy is available
michael@0 815 */
michael@0 816 #define DO_NETSTAT 1
michael@0 817
michael@0 818 void RNG_SystemInfoForRNG(void)
michael@0 819 {
michael@0 820 FILE *fp;
michael@0 821 char buf[BUFSIZ];
michael@0 822 size_t bytes;
michael@0 823 const char * const *cp;
michael@0 824 char *randfile;
michael@0 825 #ifdef DARWIN
michael@0 826 #if TARGET_OS_IPHONE
michael@0 827 /* iOS does not expose a way to access environ. */
michael@0 828 char **environ = NULL;
michael@0 829 #else
michael@0 830 char **environ = *_NSGetEnviron();
michael@0 831 #endif
michael@0 832 #else
michael@0 833 extern char **environ;
michael@0 834 #endif
michael@0 835 #ifdef BEOS
michael@0 836 static const char * const files[] = {
michael@0 837 "/boot/var/swap",
michael@0 838 "/boot/var/log/syslog",
michael@0 839 "/boot/var/tmp",
michael@0 840 "/boot/home/config/settings",
michael@0 841 "/boot/home",
michael@0 842 0
michael@0 843 };
michael@0 844 #else
michael@0 845 static const char * const files[] = {
michael@0 846 "/etc/passwd",
michael@0 847 "/etc/utmp",
michael@0 848 "/tmp",
michael@0 849 "/var/tmp",
michael@0 850 "/usr/tmp",
michael@0 851 0
michael@0 852 };
michael@0 853 #endif
michael@0 854
michael@0 855 #if defined(BSDI)
michael@0 856 static char netstat_ni_cmd[] = "netstat -nis";
michael@0 857 #else
michael@0 858 static char netstat_ni_cmd[] = "netstat -ni";
michael@0 859 #endif
michael@0 860
michael@0 861 GiveSystemInfo();
michael@0 862
michael@0 863 bytes = RNG_GetNoise(buf, sizeof(buf));
michael@0 864 RNG_RandomUpdate(buf, bytes);
michael@0 865
michael@0 866 /*
michael@0 867 * Pass the C environment and the addresses of the pointers to the
michael@0 868 * hash function. This makes the random number function depend on the
michael@0 869 * execution environment of the user and on the platform the program
michael@0 870 * is running on.
michael@0 871 */
michael@0 872 if (environ != NULL) {
michael@0 873 cp = (const char * const *) environ;
michael@0 874 while (*cp) {
michael@0 875 RNG_RandomUpdate(*cp, strlen(*cp));
michael@0 876 cp++;
michael@0 877 }
michael@0 878 RNG_RandomUpdate(environ, (char*)cp - (char*)environ);
michael@0 879 }
michael@0 880
michael@0 881 /* Give in system information */
michael@0 882 if (gethostname(buf, sizeof(buf)) == 0) {
michael@0 883 RNG_RandomUpdate(buf, strlen(buf));
michael@0 884 }
michael@0 885 GiveSystemInfo();
michael@0 886
michael@0 887 /* grab some data from system's PRNG before any other files. */
michael@0 888 bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT);
michael@0 889
michael@0 890 /* If the user points us to a random file, pass it through the rng */
michael@0 891 randfile = getenv("NSRANDFILE");
michael@0 892 if ( ( randfile != NULL ) && ( randfile[0] != '\0') ) {
michael@0 893 char *randCountString = getenv("NSRANDCOUNT");
michael@0 894 int randCount = randCountString ? atoi(randCountString) : 0;
michael@0 895 if (randCount != 0) {
michael@0 896 RNG_FileUpdate(randfile, randCount);
michael@0 897 } else {
michael@0 898 RNG_FileForRNG(randfile);
michael@0 899 }
michael@0 900 }
michael@0 901
michael@0 902 /* pass other files through */
michael@0 903 for (cp = files; *cp; cp++)
michael@0 904 RNG_FileForRNG(*cp);
michael@0 905
michael@0 906 /*
michael@0 907 * Bug 100447: On BSD/OS 4.2 and 4.3, we have problem calling safe_popen
michael@0 908 * in a pthreads environment. Therefore, we call safe_popen last and on
michael@0 909 * BSD/OS we do not call safe_popen when we succeeded in getting data
michael@0 910 * from /dev/urandom.
michael@0 911 *
michael@0 912 * Bug 174993: On platforms providing /dev/urandom, don't fork netstat
michael@0 913 * either, if data has been gathered successfully.
michael@0 914 */
michael@0 915
michael@0 916 #if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) \
michael@0 917 || defined(OPENBSD) || defined(DARWIN) || defined(LINUX) \
michael@0 918 || defined(HPUX)
michael@0 919 if (bytes)
michael@0 920 return;
michael@0 921 #endif
michael@0 922
michael@0 923 #ifdef SOLARIS
michael@0 924
michael@0 925 /*
michael@0 926 * On Solaris, NSS may be initialized automatically from libldap in
michael@0 927 * applications that are unaware of the use of NSS. safe_popen forks, and
michael@0 928 * sometimes creates issues with some applications' pthread_atfork handlers.
michael@0 929 * We always have /dev/urandom on Solaris 9 and above as an entropy source,
michael@0 930 * and for Solaris 8 we have the libkstat interface, so we don't need to
michael@0 931 * fork netstat.
michael@0 932 */
michael@0 933
michael@0 934 #undef DO_NETSTAT
michael@0 935 if (!bytes) {
michael@0 936 /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */
michael@0 937 PRUint32 kstat_bytes = 0;
michael@0 938 if (SECSuccess != RNG_kstat(&kstat_bytes)) {
michael@0 939 PORT_Assert(0);
michael@0 940 }
michael@0 941 bytes += kstat_bytes;
michael@0 942 PORT_Assert(bytes);
michael@0 943 }
michael@0 944 #endif
michael@0 945
michael@0 946 #ifdef DO_NETSTAT
michael@0 947 fp = safe_popen(netstat_ni_cmd);
michael@0 948 if (fp != NULL) {
michael@0 949 while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0)
michael@0 950 RNG_RandomUpdate(buf, bytes);
michael@0 951 safe_pclose(fp);
michael@0 952 }
michael@0 953 #endif
michael@0 954
michael@0 955 }
michael@0 956
michael@0 957 #define TOTAL_FILE_LIMIT 1000000 /* one million */
michael@0 958
michael@0 959 size_t RNG_FileUpdate(const char *fileName, size_t limit)
michael@0 960 {
michael@0 961 FILE * file;
michael@0 962 int fd;
michael@0 963 int bytes;
michael@0 964 size_t fileBytes = 0;
michael@0 965 struct stat stat_buf;
michael@0 966 unsigned char buffer[BUFSIZ];
michael@0 967 static size_t totalFileBytes = 0;
michael@0 968
michael@0 969 /* suppress valgrind warnings due to holes in struct stat */
michael@0 970 memset(&stat_buf, 0, sizeof(stat_buf));
michael@0 971
michael@0 972 if (stat((char *)fileName, &stat_buf) < 0)
michael@0 973 return fileBytes;
michael@0 974 RNG_RandomUpdate(&stat_buf, sizeof(stat_buf));
michael@0 975
michael@0 976 file = fopen(fileName, "r");
michael@0 977 if (file != NULL) {
michael@0 978 /* Read from the underlying file descriptor directly to bypass stdio
michael@0 979 * buffering and avoid reading more bytes than we need from
michael@0 980 * /dev/urandom. NOTE: we can't use fread with unbuffered I/O because
michael@0 981 * fread may return EOF in unbuffered I/O mode on Android.
michael@0 982 *
michael@0 983 * Moreover, we read into a buffer of size BUFSIZ, so buffered I/O
michael@0 984 * has no performance advantage. */
michael@0 985 fd = fileno(file);
michael@0 986 /* 'file' was just opened, so this should not fail. */
michael@0 987 PORT_Assert(fd != -1);
michael@0 988 while (limit > fileBytes) {
michael@0 989 bytes = PR_MIN(sizeof buffer, limit - fileBytes);
michael@0 990 bytes = read(fd, buffer, bytes);
michael@0 991 if (bytes <= 0)
michael@0 992 break;
michael@0 993 RNG_RandomUpdate(buffer, bytes);
michael@0 994 fileBytes += bytes;
michael@0 995 totalFileBytes += bytes;
michael@0 996 /* after TOTAL_FILE_LIMIT has been reached, only read in first
michael@0 997 ** buffer of data from each subsequent file.
michael@0 998 */
michael@0 999 if (totalFileBytes > TOTAL_FILE_LIMIT)
michael@0 1000 break;
michael@0 1001 }
michael@0 1002 fclose(file);
michael@0 1003 }
michael@0 1004 /*
michael@0 1005 * Pass yet another snapshot of our highest resolution clock into
michael@0 1006 * the hash function.
michael@0 1007 */
michael@0 1008 bytes = RNG_GetNoise(buffer, sizeof(buffer));
michael@0 1009 RNG_RandomUpdate(buffer, bytes);
michael@0 1010 return fileBytes;
michael@0 1011 }
michael@0 1012
michael@0 1013 void RNG_FileForRNG(const char *fileName)
michael@0 1014 {
michael@0 1015 RNG_FileUpdate(fileName, TOTAL_FILE_LIMIT);
michael@0 1016 }
michael@0 1017
michael@0 1018 void ReadSingleFile(const char *fileName)
michael@0 1019 {
michael@0 1020 FILE * file;
michael@0 1021 unsigned char buffer[BUFSIZ];
michael@0 1022
michael@0 1023 file = fopen(fileName, "rb");
michael@0 1024 if (file != NULL) {
michael@0 1025 while (fread(buffer, 1, sizeof(buffer), file) > 0)
michael@0 1026 ;
michael@0 1027 fclose(file);
michael@0 1028 }
michael@0 1029 }
michael@0 1030
michael@0 1031 #define _POSIX_PTHREAD_SEMANTICS
michael@0 1032 #include <dirent.h>
michael@0 1033
michael@0 1034 PRBool
michael@0 1035 ReadFileOK(char *dir, char *file)
michael@0 1036 {
michael@0 1037 struct stat stat_buf;
michael@0 1038 char filename[PATH_MAX];
michael@0 1039 int count = snprintf(filename, sizeof filename, "%s/%s",dir, file);
michael@0 1040
michael@0 1041 if (count <= 0) {
michael@0 1042 return PR_FALSE; /* name too long, can't read it anyway */
michael@0 1043 }
michael@0 1044
michael@0 1045 if (stat(filename, &stat_buf) < 0)
michael@0 1046 return PR_FALSE; /* can't stat, probably can't read it then as well */
michael@0 1047 return S_ISREG(stat_buf.st_mode) ? PR_TRUE : PR_FALSE;
michael@0 1048 }
michael@0 1049
michael@0 1050 /*
michael@0 1051 * read one file out of either /etc or the user's home directory.
michael@0 1052 * fileToRead tells which file to read.
michael@0 1053 *
michael@0 1054 * return 1 if it's time to reset the fileToRead (no more files to read).
michael@0 1055 */
michael@0 1056 int ReadOneFile(int fileToRead)
michael@0 1057 {
michael@0 1058 char *dir = "/etc";
michael@0 1059 DIR *fd = opendir(dir);
michael@0 1060 int resetCount = 0;
michael@0 1061 #ifdef SOLARIS
michael@0 1062 /* grumble, Solaris does not define struct dirent to be the full length */
michael@0 1063 typedef union {
michael@0 1064 unsigned char space[sizeof(struct dirent) + MAXNAMELEN];
michael@0 1065 struct dirent dir;
michael@0 1066 } dirent_hack;
michael@0 1067 dirent_hack entry, firstEntry;
michael@0 1068
michael@0 1069 #define entry_dir entry.dir
michael@0 1070 #else
michael@0 1071 struct dirent entry, firstEntry;
michael@0 1072 #define entry_dir entry
michael@0 1073 #endif
michael@0 1074
michael@0 1075 int i, error = -1;
michael@0 1076
michael@0 1077 if (fd == NULL) {
michael@0 1078 dir = getenv("HOME");
michael@0 1079 if (dir) {
michael@0 1080 fd = opendir(dir);
michael@0 1081 }
michael@0 1082 }
michael@0 1083 if (fd == NULL) {
michael@0 1084 return 1;
michael@0 1085 }
michael@0 1086
michael@0 1087 for (i=0; i <= fileToRead; i++) {
michael@0 1088 struct dirent *result = NULL;
michael@0 1089 do {
michael@0 1090 error = readdir_r(fd, &entry_dir, &result);
michael@0 1091 } while (error == 0 && result != NULL &&
michael@0 1092 !ReadFileOK(dir,&result->d_name[0]));
michael@0 1093 if (error != 0 || result == NULL) {
michael@0 1094 resetCount = 1; /* read to the end, start again at the beginning */
michael@0 1095 if (i != 0) {
michael@0 1096 /* ran out of entries in the directory, use the first one */
michael@0 1097 entry = firstEntry;
michael@0 1098 error = 0;
michael@0 1099 break;
michael@0 1100 }
michael@0 1101 /* if i== 0, there were no readable entries in the directory */
michael@0 1102 break;
michael@0 1103 }
michael@0 1104 if (i==0) {
michael@0 1105 /* save the first entry in case we run out of entries */
michael@0 1106 firstEntry = entry;
michael@0 1107 }
michael@0 1108 }
michael@0 1109
michael@0 1110 if (error == 0) {
michael@0 1111 char filename[PATH_MAX];
michael@0 1112 int count = snprintf(filename, sizeof filename,
michael@0 1113 "%s/%s",dir, &entry_dir.d_name[0]);
michael@0 1114 if (count >= 1) {
michael@0 1115 ReadSingleFile(filename);
michael@0 1116 }
michael@0 1117 }
michael@0 1118
michael@0 1119 closedir(fd);
michael@0 1120 return resetCount;
michael@0 1121 }
michael@0 1122
michael@0 1123 /*
michael@0 1124 * do something to try to introduce more noise into the 'GetNoise' call
michael@0 1125 */
michael@0 1126 static void rng_systemJitter(void)
michael@0 1127 {
michael@0 1128 static int fileToRead = 1;
michael@0 1129
michael@0 1130 if (ReadOneFile(fileToRead)) {
michael@0 1131 fileToRead = 1;
michael@0 1132 } else {
michael@0 1133 fileToRead++;
michael@0 1134 }
michael@0 1135 }
michael@0 1136
michael@0 1137 size_t RNG_SystemRNG(void *dest, size_t maxLen)
michael@0 1138 {
michael@0 1139 FILE *file;
michael@0 1140 int fd;
michael@0 1141 int bytes;
michael@0 1142 size_t fileBytes = 0;
michael@0 1143 unsigned char *buffer = dest;
michael@0 1144
michael@0 1145 file = fopen("/dev/urandom", "r");
michael@0 1146 if (file == NULL) {
michael@0 1147 return rng_systemFromNoise(dest, maxLen);
michael@0 1148 }
michael@0 1149 /* Read from the underlying file descriptor directly to bypass stdio
michael@0 1150 * buffering and avoid reading more bytes than we need from /dev/urandom.
michael@0 1151 * NOTE: we can't use fread with unbuffered I/O because fread may return
michael@0 1152 * EOF in unbuffered I/O mode on Android.
michael@0 1153 */
michael@0 1154 fd = fileno(file);
michael@0 1155 /* 'file' was just opened, so this should not fail. */
michael@0 1156 PORT_Assert(fd != -1);
michael@0 1157 while (maxLen > fileBytes) {
michael@0 1158 bytes = maxLen - fileBytes;
michael@0 1159 bytes = read(fd, buffer, bytes);
michael@0 1160 if (bytes <= 0)
michael@0 1161 break;
michael@0 1162 fileBytes += bytes;
michael@0 1163 buffer += bytes;
michael@0 1164 }
michael@0 1165 fclose(file);
michael@0 1166 if (fileBytes != maxLen) {
michael@0 1167 PORT_SetError(SEC_ERROR_NEED_RANDOM); /* system RNG failed */
michael@0 1168 fileBytes = 0;
michael@0 1169 }
michael@0 1170 return fileBytes;
michael@0 1171 }

mercurial