1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/freebl/unix_rand.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1171 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include <stdio.h> 1.9 +#include <string.h> 1.10 +#include <signal.h> 1.11 +#include <unistd.h> 1.12 +#include <limits.h> 1.13 +#include <errno.h> 1.14 +#include <stdlib.h> 1.15 +#include <sys/time.h> 1.16 +#include <sys/wait.h> 1.17 +#include <sys/stat.h> 1.18 +#include "secrng.h" 1.19 +#include "secerr.h" 1.20 +#include "prerror.h" 1.21 +#include "prthread.h" 1.22 +#include "prprf.h" 1.23 + 1.24 +size_t RNG_FileUpdate(const char *fileName, size_t limit); 1.25 + 1.26 +/* 1.27 + * When copying data to the buffer we want the least signicant bytes 1.28 + * from the input since those bits are changing the fastest. The address 1.29 + * of least significant byte depends upon whether we are running on 1.30 + * a big-endian or little-endian machine. 1.31 + * 1.32 + * Does this mean the least signicant bytes are the most significant 1.33 + * to us? :-) 1.34 + */ 1.35 + 1.36 +static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen) 1.37 +{ 1.38 + union endianness { 1.39 + PRInt32 i; 1.40 + char c[4]; 1.41 + } u; 1.42 + 1.43 + if (srclen <= dstlen) { 1.44 + memcpy(dst, src, srclen); 1.45 + return srclen; 1.46 + } 1.47 + u.i = 0x01020304; 1.48 + if (u.c[0] == 0x01) { 1.49 + /* big-endian case */ 1.50 + memcpy(dst, (char*)src + (srclen - dstlen), dstlen); 1.51 + } else { 1.52 + /* little-endian case */ 1.53 + memcpy(dst, src, dstlen); 1.54 + } 1.55 + return dstlen; 1.56 +} 1.57 + 1.58 +#ifdef SOLARIS 1.59 + 1.60 +#include <kstat.h> 1.61 + 1.62 +static const PRUint32 entropy_buf_len = 4096; /* buffer up to 4 KB */ 1.63 + 1.64 +/* Buffer entropy data, and feed it to the RNG, entropy_buf_len bytes at a time. 1.65 + * Returns error if RNG_RandomUpdate fails. Also increments *total_fed 1.66 + * by the number of bytes successfully buffered. 1.67 + */ 1.68 +static SECStatus BufferEntropy(char* inbuf, PRUint32 inlen, 1.69 + char* entropy_buf, PRUint32* entropy_buffered, 1.70 + PRUint32* total_fed) 1.71 +{ 1.72 + PRUint32 tocopy = 0; 1.73 + PRUint32 avail = 0; 1.74 + SECStatus rv = SECSuccess; 1.75 + 1.76 + while (inlen) { 1.77 + avail = entropy_buf_len - *entropy_buffered; 1.78 + if (!avail) { 1.79 + /* Buffer is full, time to feed it to the RNG. */ 1.80 + rv = RNG_RandomUpdate(entropy_buf, entropy_buf_len); 1.81 + if (SECSuccess != rv) { 1.82 + break; 1.83 + } 1.84 + *entropy_buffered = 0; 1.85 + avail = entropy_buf_len; 1.86 + } 1.87 + tocopy = PR_MIN(avail, inlen); 1.88 + memcpy(entropy_buf + *entropy_buffered, inbuf, tocopy); 1.89 + *entropy_buffered += tocopy; 1.90 + inlen -= tocopy; 1.91 + inbuf += tocopy; 1.92 + *total_fed += tocopy; 1.93 + } 1.94 + return rv; 1.95 +} 1.96 + 1.97 +/* Feed kernel statistics structures and ks_data field to the RNG. 1.98 + * Returns status as well as the number of bytes successfully fed to the RNG. 1.99 + */ 1.100 +static SECStatus RNG_kstat(PRUint32* fed) 1.101 +{ 1.102 + kstat_ctl_t* kc = NULL; 1.103 + kstat_t* ksp = NULL; 1.104 + PRUint32 entropy_buffered = 0; 1.105 + char* entropy_buf = NULL; 1.106 + SECStatus rv = SECSuccess; 1.107 + 1.108 + PORT_Assert(fed); 1.109 + if (!fed) { 1.110 + return SECFailure; 1.111 + } 1.112 + *fed = 0; 1.113 + 1.114 + kc = kstat_open(); 1.115 + PORT_Assert(kc); 1.116 + if (!kc) { 1.117 + return SECFailure; 1.118 + } 1.119 + entropy_buf = (char*) PORT_Alloc(entropy_buf_len); 1.120 + PORT_Assert(entropy_buf); 1.121 + if (entropy_buf) { 1.122 + for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 1.123 + if (-1 == kstat_read(kc, ksp, NULL)) { 1.124 + /* missing data from a single kstat shouldn't be fatal */ 1.125 + continue; 1.126 + } 1.127 + rv = BufferEntropy((char*)ksp, sizeof(kstat_t), 1.128 + entropy_buf, &entropy_buffered, 1.129 + fed); 1.130 + if (SECSuccess != rv) { 1.131 + break; 1.132 + } 1.133 + 1.134 + if (ksp->ks_data && ksp->ks_data_size>0 && ksp->ks_ndata>0) { 1.135 + rv = BufferEntropy((char*)ksp->ks_data, ksp->ks_data_size, 1.136 + entropy_buf, &entropy_buffered, 1.137 + fed); 1.138 + if (SECSuccess != rv) { 1.139 + break; 1.140 + } 1.141 + } 1.142 + } 1.143 + if (SECSuccess == rv && entropy_buffered) { 1.144 + /* Buffer is not empty, time to feed it to the RNG */ 1.145 + rv = RNG_RandomUpdate(entropy_buf, entropy_buffered); 1.146 + } 1.147 + PORT_Free(entropy_buf); 1.148 + } else { 1.149 + rv = SECFailure; 1.150 + } 1.151 + if (kstat_close(kc)) { 1.152 + PORT_Assert(0); 1.153 + rv = SECFailure; 1.154 + } 1.155 + return rv; 1.156 +} 1.157 + 1.158 +#endif 1.159 + 1.160 +#if defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(FREEBSD) \ 1.161 + || defined(NETBSD) || defined(DARWIN) || defined(OPENBSD) \ 1.162 + || defined(NTO) || defined(__riscos__) 1.163 +#include <sys/times.h> 1.164 + 1.165 +#define getdtablesize() sysconf(_SC_OPEN_MAX) 1.166 + 1.167 +static size_t 1.168 +GetHighResClock(void *buf, size_t maxbytes) 1.169 +{ 1.170 + int ticks; 1.171 + struct tms buffer; 1.172 + 1.173 + ticks=times(&buffer); 1.174 + return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); 1.175 +} 1.176 + 1.177 +static void 1.178 +GiveSystemInfo(void) 1.179 +{ 1.180 + long si; 1.181 + 1.182 + /* 1.183 + * Is this really necessary? Why not use rand48 or something? 1.184 + */ 1.185 + si = sysconf(_SC_CHILD_MAX); 1.186 + RNG_RandomUpdate(&si, sizeof(si)); 1.187 + 1.188 + si = sysconf(_SC_STREAM_MAX); 1.189 + RNG_RandomUpdate(&si, sizeof(si)); 1.190 + 1.191 + si = sysconf(_SC_OPEN_MAX); 1.192 + RNG_RandomUpdate(&si, sizeof(si)); 1.193 +} 1.194 +#endif 1.195 + 1.196 +#if defined(__sun) 1.197 +#if defined(__svr4) || defined(SVR4) 1.198 +#include <sys/systeminfo.h> 1.199 + 1.200 +#define getdtablesize() sysconf(_SC_OPEN_MAX) 1.201 + 1.202 +static void 1.203 +GiveSystemInfo(void) 1.204 +{ 1.205 + int rv; 1.206 + char buf[2000]; 1.207 + 1.208 + rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); 1.209 + if (rv > 0) { 1.210 + RNG_RandomUpdate(buf, rv); 1.211 + } 1.212 + rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); 1.213 + if (rv > 0) { 1.214 + RNG_RandomUpdate(buf, rv); 1.215 + } 1.216 + rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); 1.217 + if (rv > 0) { 1.218 + RNG_RandomUpdate(buf, rv); 1.219 + } 1.220 +} 1.221 + 1.222 +static size_t 1.223 +GetHighResClock(void *buf, size_t maxbytes) 1.224 +{ 1.225 + hrtime_t t; 1.226 + t = gethrtime(); 1.227 + if (t) { 1.228 + return CopyLowBits(buf, maxbytes, &t, sizeof(t)); 1.229 + } 1.230 + return 0; 1.231 +} 1.232 +#else /* SunOS (Sun, but not SVR4) */ 1.233 + 1.234 +extern long sysconf(int name); 1.235 + 1.236 +static size_t 1.237 +GetHighResClock(void *buf, size_t maxbytes) 1.238 +{ 1.239 + return 0; 1.240 +} 1.241 + 1.242 +static void 1.243 +GiveSystemInfo(void) 1.244 +{ 1.245 + long si; 1.246 + 1.247 + /* This is not very good */ 1.248 + si = sysconf(_SC_CHILD_MAX); 1.249 + RNG_RandomUpdate(&si, sizeof(si)); 1.250 +} 1.251 +#endif 1.252 +#endif /* Sun */ 1.253 + 1.254 +#if defined(__hpux) 1.255 +#include <sys/unistd.h> 1.256 + 1.257 +#define getdtablesize() sysconf(_SC_OPEN_MAX) 1.258 + 1.259 +#if defined(__ia64) 1.260 +#include <ia64/sys/inline.h> 1.261 + 1.262 +static size_t 1.263 +GetHighResClock(void *buf, size_t maxbytes) 1.264 +{ 1.265 + PRUint64 t; 1.266 + 1.267 + t = _Asm_mov_from_ar(_AREG44); 1.268 + return CopyLowBits(buf, maxbytes, &t, sizeof(t)); 1.269 +} 1.270 +#else 1.271 +static size_t 1.272 +GetHighResClock(void *buf, size_t maxbytes) 1.273 +{ 1.274 + extern int ret_cr16(); 1.275 + int cr16val; 1.276 + 1.277 + cr16val = ret_cr16(); 1.278 + return CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val)); 1.279 +} 1.280 +#endif 1.281 + 1.282 +static void 1.283 +GiveSystemInfo(void) 1.284 +{ 1.285 + long si; 1.286 + 1.287 + /* This is not very good */ 1.288 + si = sysconf(_AES_OS_VERSION); 1.289 + RNG_RandomUpdate(&si, sizeof(si)); 1.290 + si = sysconf(_SC_CPU_VERSION); 1.291 + RNG_RandomUpdate(&si, sizeof(si)); 1.292 +} 1.293 +#endif /* HPUX */ 1.294 + 1.295 +#if defined(OSF1) 1.296 +#include <sys/types.h> 1.297 +#include <sys/sysinfo.h> 1.298 +#include <sys/systeminfo.h> 1.299 +#include <c_asm.h> 1.300 + 1.301 +static void 1.302 +GiveSystemInfo(void) 1.303 +{ 1.304 + char buf[BUFSIZ]; 1.305 + int rv; 1.306 + int off = 0; 1.307 + 1.308 + rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); 1.309 + if (rv > 0) { 1.310 + RNG_RandomUpdate(buf, rv); 1.311 + } 1.312 + rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); 1.313 + if (rv > 0) { 1.314 + RNG_RandomUpdate(buf, rv); 1.315 + } 1.316 + rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); 1.317 + if (rv > 0) { 1.318 + RNG_RandomUpdate(buf, rv); 1.319 + } 1.320 +} 1.321 + 1.322 +/* 1.323 + * Use the "get the cycle counter" instruction on the alpha. 1.324 + * The low 32 bits completely turn over in less than a minute. 1.325 + * The high 32 bits are some non-counter gunk that changes sometimes. 1.326 + */ 1.327 +static size_t 1.328 +GetHighResClock(void *buf, size_t maxbytes) 1.329 +{ 1.330 + unsigned long t; 1.331 + 1.332 + t = asm("rpcc %v0"); 1.333 + return CopyLowBits(buf, maxbytes, &t, sizeof(t)); 1.334 +} 1.335 + 1.336 +#endif /* Alpha */ 1.337 + 1.338 +#if defined(_IBMR2) 1.339 +static size_t 1.340 +GetHighResClock(void *buf, size_t maxbytes) 1.341 +{ 1.342 + return 0; 1.343 +} 1.344 + 1.345 +static void 1.346 +GiveSystemInfo(void) 1.347 +{ 1.348 + /* XXX haven't found any yet! */ 1.349 +} 1.350 +#endif /* IBM R2 */ 1.351 + 1.352 +#if defined(LINUX) 1.353 +#include <sys/sysinfo.h> 1.354 + 1.355 +static size_t 1.356 +GetHighResClock(void *buf, size_t maxbytes) 1.357 +{ 1.358 + return 0; 1.359 +} 1.360 + 1.361 +static void 1.362 +GiveSystemInfo(void) 1.363 +{ 1.364 +#ifndef NO_SYSINFO 1.365 + struct sysinfo si; 1.366 + if (sysinfo(&si) == 0) { 1.367 + RNG_RandomUpdate(&si, sizeof(si)); 1.368 + } 1.369 +#endif 1.370 +} 1.371 +#endif /* LINUX */ 1.372 + 1.373 +#if defined(NCR) 1.374 + 1.375 +#include <sys/utsname.h> 1.376 +#include <sys/systeminfo.h> 1.377 + 1.378 +#define getdtablesize() sysconf(_SC_OPEN_MAX) 1.379 + 1.380 +static size_t 1.381 +GetHighResClock(void *buf, size_t maxbytes) 1.382 +{ 1.383 + return 0; 1.384 +} 1.385 + 1.386 +static void 1.387 +GiveSystemInfo(void) 1.388 +{ 1.389 + int rv; 1.390 + char buf[2000]; 1.391 + 1.392 + rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); 1.393 + if (rv > 0) { 1.394 + RNG_RandomUpdate(buf, rv); 1.395 + } 1.396 + rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); 1.397 + if (rv > 0) { 1.398 + RNG_RandomUpdate(buf, rv); 1.399 + } 1.400 + rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); 1.401 + if (rv > 0) { 1.402 + RNG_RandomUpdate(buf, rv); 1.403 + } 1.404 +} 1.405 + 1.406 +#endif /* NCR */ 1.407 + 1.408 +#if defined(sgi) 1.409 +#include <fcntl.h> 1.410 +#undef PRIVATE 1.411 +#include <sys/mman.h> 1.412 +#include <sys/syssgi.h> 1.413 +#include <sys/immu.h> 1.414 +#include <sys/systeminfo.h> 1.415 +#include <sys/utsname.h> 1.416 +#include <wait.h> 1.417 + 1.418 +static void 1.419 +GiveSystemInfo(void) 1.420 +{ 1.421 + int rv; 1.422 + char buf[4096]; 1.423 + 1.424 + rv = syssgi(SGI_SYSID, &buf[0]); 1.425 + if (rv > 0) { 1.426 + RNG_RandomUpdate(buf, MAXSYSIDSIZE); 1.427 + } 1.428 +#ifdef SGI_RDUBLK 1.429 + rv = syssgi(SGI_RDUBLK, getpid(), &buf[0], sizeof(buf)); 1.430 + if (rv > 0) { 1.431 + RNG_RandomUpdate(buf, sizeof(buf)); 1.432 + } 1.433 +#endif /* SGI_RDUBLK */ 1.434 + rv = syssgi(SGI_INVENT, SGI_INV_READ, buf, sizeof(buf)); 1.435 + if (rv > 0) { 1.436 + RNG_RandomUpdate(buf, sizeof(buf)); 1.437 + } 1.438 + rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); 1.439 + if (rv > 0) { 1.440 + RNG_RandomUpdate(buf, rv); 1.441 + } 1.442 + rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); 1.443 + if (rv > 0) { 1.444 + RNG_RandomUpdate(buf, rv); 1.445 + } 1.446 + rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); 1.447 + if (rv > 0) { 1.448 + RNG_RandomUpdate(buf, rv); 1.449 + } 1.450 +} 1.451 + 1.452 +static size_t GetHighResClock(void *buf, size_t maxbuf) 1.453 +{ 1.454 + unsigned phys_addr, raddr, cycleval; 1.455 + static volatile unsigned *iotimer_addr = NULL; 1.456 + static int tries = 0; 1.457 + static int cntr_size; 1.458 + int mfd; 1.459 + long s0[2]; 1.460 + struct timeval tv; 1.461 + 1.462 +#ifndef SGI_CYCLECNTR_SIZE 1.463 +#define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */ 1.464 +#endif 1.465 + 1.466 + if (iotimer_addr == NULL) { 1.467 + if (tries++ > 1) { 1.468 + /* Don't keep trying if it didn't work */ 1.469 + return 0; 1.470 + } 1.471 + 1.472 + /* 1.473 + ** For SGI machines we can use the cycle counter, if it has one, 1.474 + ** to generate some truly random numbers 1.475 + */ 1.476 + phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval); 1.477 + if (phys_addr) { 1.478 + int pgsz = getpagesize(); 1.479 + int pgoffmask = pgsz - 1; 1.480 + 1.481 + raddr = phys_addr & ~pgoffmask; 1.482 + mfd = open("/dev/mmem", O_RDONLY); 1.483 + if (mfd < 0) { 1.484 + return 0; 1.485 + } 1.486 + iotimer_addr = (unsigned *) 1.487 + mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr); 1.488 + if (iotimer_addr == (void*)-1) { 1.489 + close(mfd); 1.490 + iotimer_addr = NULL; 1.491 + return 0; 1.492 + } 1.493 + iotimer_addr = (unsigned*) 1.494 + ((__psint_t)iotimer_addr | (phys_addr & pgoffmask)); 1.495 + /* 1.496 + * The file 'mfd' is purposefully not closed. 1.497 + */ 1.498 + cntr_size = syssgi(SGI_CYCLECNTR_SIZE); 1.499 + if (cntr_size < 0) { 1.500 + struct utsname utsinfo; 1.501 + 1.502 + /* 1.503 + * We must be executing on a 6.0 or earlier system, since the 1.504 + * SGI_CYCLECNTR_SIZE call is not supported. 1.505 + * 1.506 + * The only pre-6.1 platforms with 64-bit counters are 1.507 + * IP19 and IP21 (Challenge, PowerChallenge, Onyx). 1.508 + */ 1.509 + uname(&utsinfo); 1.510 + if (!strncmp(utsinfo.machine, "IP19", 4) || 1.511 + !strncmp(utsinfo.machine, "IP21", 4)) 1.512 + cntr_size = 64; 1.513 + else 1.514 + cntr_size = 32; 1.515 + } 1.516 + cntr_size /= 8; /* Convert from bits to bytes */ 1.517 + } 1.518 + } 1.519 + 1.520 + s0[0] = *iotimer_addr; 1.521 + if (cntr_size > 4) 1.522 + s0[1] = *(iotimer_addr + 1); 1.523 + memcpy(buf, (char *)&s0[0], cntr_size); 1.524 + return CopyLowBits(buf, maxbuf, &s0, cntr_size); 1.525 +} 1.526 +#endif 1.527 + 1.528 +#if defined(sony) 1.529 +#include <sys/systeminfo.h> 1.530 + 1.531 +#define getdtablesize() sysconf(_SC_OPEN_MAX) 1.532 + 1.533 +static size_t 1.534 +GetHighResClock(void *buf, size_t maxbytes) 1.535 +{ 1.536 + return 0; 1.537 +} 1.538 + 1.539 +static void 1.540 +GiveSystemInfo(void) 1.541 +{ 1.542 + int rv; 1.543 + char buf[2000]; 1.544 + 1.545 + rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); 1.546 + if (rv > 0) { 1.547 + RNG_RandomUpdate(buf, rv); 1.548 + } 1.549 + rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); 1.550 + if (rv > 0) { 1.551 + RNG_RandomUpdate(buf, rv); 1.552 + } 1.553 + rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); 1.554 + if (rv > 0) { 1.555 + RNG_RandomUpdate(buf, rv); 1.556 + } 1.557 +} 1.558 +#endif /* sony */ 1.559 + 1.560 +#if defined(sinix) 1.561 +#include <sys/systeminfo.h> 1.562 +#include <sys/times.h> 1.563 + 1.564 +int gettimeofday(struct timeval *, struct timezone *); 1.565 +int gethostname(char *, int); 1.566 + 1.567 +#define getdtablesize() sysconf(_SC_OPEN_MAX) 1.568 + 1.569 +static size_t 1.570 +GetHighResClock(void *buf, size_t maxbytes) 1.571 +{ 1.572 + int ticks; 1.573 + struct tms buffer; 1.574 + 1.575 + ticks=times(&buffer); 1.576 + return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); 1.577 +} 1.578 + 1.579 +static void 1.580 +GiveSystemInfo(void) 1.581 +{ 1.582 + int rv; 1.583 + char buf[2000]; 1.584 + 1.585 + rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); 1.586 + if (rv > 0) { 1.587 + RNG_RandomUpdate(buf, rv); 1.588 + } 1.589 + rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); 1.590 + if (rv > 0) { 1.591 + RNG_RandomUpdate(buf, rv); 1.592 + } 1.593 + rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); 1.594 + if (rv > 0) { 1.595 + RNG_RandomUpdate(buf, rv); 1.596 + } 1.597 +} 1.598 +#endif /* sinix */ 1.599 + 1.600 + 1.601 +#ifdef BEOS 1.602 +#include <be/kernel/OS.h> 1.603 + 1.604 +static size_t 1.605 +GetHighResClock(void *buf, size_t maxbytes) 1.606 +{ 1.607 + bigtime_t bigtime; /* Actually a int64 */ 1.608 + 1.609 + bigtime = real_time_clock_usecs(); 1.610 + return CopyLowBits(buf, maxbytes, &bigtime, sizeof(bigtime)); 1.611 +} 1.612 + 1.613 +static void 1.614 +GiveSystemInfo(void) 1.615 +{ 1.616 + system_info *info = NULL; 1.617 + PRInt32 val; 1.618 + get_system_info(info); 1.619 + if (info) { 1.620 + val = info->boot_time; 1.621 + RNG_RandomUpdate(&val, sizeof(val)); 1.622 + val = info->used_pages; 1.623 + RNG_RandomUpdate(&val, sizeof(val)); 1.624 + val = info->used_ports; 1.625 + RNG_RandomUpdate(&val, sizeof(val)); 1.626 + val = info->used_threads; 1.627 + RNG_RandomUpdate(&val, sizeof(val)); 1.628 + val = info->used_teams; 1.629 + RNG_RandomUpdate(&val, sizeof(val)); 1.630 + } 1.631 +} 1.632 +#endif /* BEOS */ 1.633 + 1.634 +#if defined(nec_ews) 1.635 +#include <sys/systeminfo.h> 1.636 + 1.637 +#define getdtablesize() sysconf(_SC_OPEN_MAX) 1.638 + 1.639 +static size_t 1.640 +GetHighResClock(void *buf, size_t maxbytes) 1.641 +{ 1.642 + return 0; 1.643 +} 1.644 + 1.645 +static void 1.646 +GiveSystemInfo(void) 1.647 +{ 1.648 + int rv; 1.649 + char buf[2000]; 1.650 + 1.651 + rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); 1.652 + if (rv > 0) { 1.653 + RNG_RandomUpdate(buf, rv); 1.654 + } 1.655 + rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); 1.656 + if (rv > 0) { 1.657 + RNG_RandomUpdate(buf, rv); 1.658 + } 1.659 + rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); 1.660 + if (rv > 0) { 1.661 + RNG_RandomUpdate(buf, rv); 1.662 + } 1.663 +} 1.664 +#endif /* nec_ews */ 1.665 + 1.666 +size_t RNG_GetNoise(void *buf, size_t maxbytes) 1.667 +{ 1.668 + struct timeval tv; 1.669 + int n = 0; 1.670 + int c; 1.671 + 1.672 + n = GetHighResClock(buf, maxbytes); 1.673 + maxbytes -= n; 1.674 + 1.675 + (void)gettimeofday(&tv, 0); 1.676 + c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_usec, sizeof(tv.tv_usec)); 1.677 + n += c; 1.678 + maxbytes -= c; 1.679 + c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_sec, sizeof(tv.tv_sec)); 1.680 + n += c; 1.681 + return n; 1.682 +} 1.683 + 1.684 +#define SAFE_POPEN_MAXARGS 10 /* must be at least 2 */ 1.685 + 1.686 +/* 1.687 + * safe_popen is static to this module and we know what arguments it is 1.688 + * called with. Note that this version only supports a single open child 1.689 + * process at any time. 1.690 + */ 1.691 +static pid_t safe_popen_pid; 1.692 +static struct sigaction oldact; 1.693 + 1.694 +static FILE * 1.695 +safe_popen(char *cmd) 1.696 +{ 1.697 + int p[2], fd, argc; 1.698 + pid_t pid; 1.699 + char *argv[SAFE_POPEN_MAXARGS + 1]; 1.700 + FILE *fp; 1.701 + static char blank[] = " \t"; 1.702 + static struct sigaction newact; 1.703 + 1.704 + if (pipe(p) < 0) 1.705 + return 0; 1.706 + 1.707 + fp = fdopen(p[0], "r"); 1.708 + if (fp == 0) { 1.709 + close(p[0]); 1.710 + close(p[1]); 1.711 + return 0; 1.712 + } 1.713 + 1.714 + /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */ 1.715 + newact.sa_handler = SIG_DFL; 1.716 + newact.sa_flags = 0; 1.717 + sigfillset(&newact.sa_mask); 1.718 + sigaction (SIGCHLD, &newact, &oldact); 1.719 + 1.720 + pid = fork(); 1.721 + switch (pid) { 1.722 + int ndesc; 1.723 + 1.724 + case -1: 1.725 + fclose(fp); /* this closes p[0], the fd associated with fp */ 1.726 + close(p[1]); 1.727 + sigaction (SIGCHLD, &oldact, NULL); 1.728 + return 0; 1.729 + 1.730 + case 0: 1.731 + /* dup write-side of pipe to stderr and stdout */ 1.732 + if (p[1] != 1) dup2(p[1], 1); 1.733 + if (p[1] != 2) dup2(p[1], 2); 1.734 + 1.735 + /* 1.736 + * close the other file descriptors, except stdin which we 1.737 + * try reassociating with /dev/null, first (bug 174993) 1.738 + */ 1.739 + if (!freopen("/dev/null", "r", stdin)) 1.740 + close(0); 1.741 + ndesc = getdtablesize(); 1.742 + for (fd = PR_MIN(65536, ndesc); --fd > 2; close(fd)); 1.743 + 1.744 + /* clean up environment in the child process */ 1.745 + putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc"); 1.746 + putenv("SHELL=/bin/sh"); 1.747 + putenv("IFS= \t"); 1.748 + 1.749 + /* 1.750 + * The caller may have passed us a string that is in text 1.751 + * space. It may be illegal to modify the string 1.752 + */ 1.753 + cmd = strdup(cmd); 1.754 + /* format argv */ 1.755 + argv[0] = strtok(cmd, blank); 1.756 + argc = 1; 1.757 + while ((argv[argc] = strtok(0, blank)) != 0) { 1.758 + if (++argc == SAFE_POPEN_MAXARGS) { 1.759 + argv[argc] = 0; 1.760 + break; 1.761 + } 1.762 + } 1.763 + 1.764 + /* and away we go */ 1.765 + execvp(argv[0], argv); 1.766 + exit(127); 1.767 + break; 1.768 + 1.769 + default: 1.770 + close(p[1]); 1.771 + break; 1.772 + } 1.773 + 1.774 + /* non-zero means there's a cmd running */ 1.775 + safe_popen_pid = pid; 1.776 + return fp; 1.777 +} 1.778 + 1.779 +static int 1.780 +safe_pclose(FILE *fp) 1.781 +{ 1.782 + pid_t pid; 1.783 + int status = -1, rv; 1.784 + 1.785 + if ((pid = safe_popen_pid) == 0) 1.786 + return -1; 1.787 + safe_popen_pid = 0; 1.788 + 1.789 + fclose(fp); 1.790 + 1.791 + /* yield the processor so the child gets some time to exit normally */ 1.792 + PR_Sleep(PR_INTERVAL_NO_WAIT); 1.793 + 1.794 + /* if the child hasn't exited, kill it -- we're done with its output */ 1.795 + while ((rv = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR) 1.796 + ; 1.797 + if (rv == 0) { 1.798 + kill(pid, SIGKILL); 1.799 + while ((rv = waitpid(pid, &status, 0)) == -1 && errno == EINTR) 1.800 + ; 1.801 + } 1.802 + 1.803 + /* Reset SIGCHLD signal hander before returning */ 1.804 + sigaction(SIGCHLD, &oldact, NULL); 1.805 + 1.806 + return status; 1.807 +} 1.808 + 1.809 +#ifdef DARWIN 1.810 +#include <TargetConditionals.h> 1.811 +#if !TARGET_OS_IPHONE 1.812 +#include <crt_externs.h> 1.813 +#endif 1.814 +#endif 1.815 + 1.816 +/* Fork netstat to collect its output by default. Do not unset this unless 1.817 + * another source of entropy is available 1.818 + */ 1.819 +#define DO_NETSTAT 1 1.820 + 1.821 +void RNG_SystemInfoForRNG(void) 1.822 +{ 1.823 + FILE *fp; 1.824 + char buf[BUFSIZ]; 1.825 + size_t bytes; 1.826 + const char * const *cp; 1.827 + char *randfile; 1.828 +#ifdef DARWIN 1.829 +#if TARGET_OS_IPHONE 1.830 + /* iOS does not expose a way to access environ. */ 1.831 + char **environ = NULL; 1.832 +#else 1.833 + char **environ = *_NSGetEnviron(); 1.834 +#endif 1.835 +#else 1.836 + extern char **environ; 1.837 +#endif 1.838 +#ifdef BEOS 1.839 + static const char * const files[] = { 1.840 + "/boot/var/swap", 1.841 + "/boot/var/log/syslog", 1.842 + "/boot/var/tmp", 1.843 + "/boot/home/config/settings", 1.844 + "/boot/home", 1.845 + 0 1.846 + }; 1.847 +#else 1.848 + static const char * const files[] = { 1.849 + "/etc/passwd", 1.850 + "/etc/utmp", 1.851 + "/tmp", 1.852 + "/var/tmp", 1.853 + "/usr/tmp", 1.854 + 0 1.855 + }; 1.856 +#endif 1.857 + 1.858 +#if defined(BSDI) 1.859 + static char netstat_ni_cmd[] = "netstat -nis"; 1.860 +#else 1.861 + static char netstat_ni_cmd[] = "netstat -ni"; 1.862 +#endif 1.863 + 1.864 + GiveSystemInfo(); 1.865 + 1.866 + bytes = RNG_GetNoise(buf, sizeof(buf)); 1.867 + RNG_RandomUpdate(buf, bytes); 1.868 + 1.869 + /* 1.870 + * Pass the C environment and the addresses of the pointers to the 1.871 + * hash function. This makes the random number function depend on the 1.872 + * execution environment of the user and on the platform the program 1.873 + * is running on. 1.874 + */ 1.875 + if (environ != NULL) { 1.876 + cp = (const char * const *) environ; 1.877 + while (*cp) { 1.878 + RNG_RandomUpdate(*cp, strlen(*cp)); 1.879 + cp++; 1.880 + } 1.881 + RNG_RandomUpdate(environ, (char*)cp - (char*)environ); 1.882 + } 1.883 + 1.884 + /* Give in system information */ 1.885 + if (gethostname(buf, sizeof(buf)) == 0) { 1.886 + RNG_RandomUpdate(buf, strlen(buf)); 1.887 + } 1.888 + GiveSystemInfo(); 1.889 + 1.890 + /* grab some data from system's PRNG before any other files. */ 1.891 + bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT); 1.892 + 1.893 + /* If the user points us to a random file, pass it through the rng */ 1.894 + randfile = getenv("NSRANDFILE"); 1.895 + if ( ( randfile != NULL ) && ( randfile[0] != '\0') ) { 1.896 + char *randCountString = getenv("NSRANDCOUNT"); 1.897 + int randCount = randCountString ? atoi(randCountString) : 0; 1.898 + if (randCount != 0) { 1.899 + RNG_FileUpdate(randfile, randCount); 1.900 + } else { 1.901 + RNG_FileForRNG(randfile); 1.902 + } 1.903 + } 1.904 + 1.905 + /* pass other files through */ 1.906 + for (cp = files; *cp; cp++) 1.907 + RNG_FileForRNG(*cp); 1.908 + 1.909 +/* 1.910 + * Bug 100447: On BSD/OS 4.2 and 4.3, we have problem calling safe_popen 1.911 + * in a pthreads environment. Therefore, we call safe_popen last and on 1.912 + * BSD/OS we do not call safe_popen when we succeeded in getting data 1.913 + * from /dev/urandom. 1.914 + * 1.915 + * Bug 174993: On platforms providing /dev/urandom, don't fork netstat 1.916 + * either, if data has been gathered successfully. 1.917 + */ 1.918 + 1.919 +#if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) \ 1.920 + || defined(OPENBSD) || defined(DARWIN) || defined(LINUX) \ 1.921 + || defined(HPUX) 1.922 + if (bytes) 1.923 + return; 1.924 +#endif 1.925 + 1.926 +#ifdef SOLARIS 1.927 + 1.928 +/* 1.929 + * On Solaris, NSS may be initialized automatically from libldap in 1.930 + * applications that are unaware of the use of NSS. safe_popen forks, and 1.931 + * sometimes creates issues with some applications' pthread_atfork handlers. 1.932 + * We always have /dev/urandom on Solaris 9 and above as an entropy source, 1.933 + * and for Solaris 8 we have the libkstat interface, so we don't need to 1.934 + * fork netstat. 1.935 + */ 1.936 + 1.937 +#undef DO_NETSTAT 1.938 + if (!bytes) { 1.939 + /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */ 1.940 + PRUint32 kstat_bytes = 0; 1.941 + if (SECSuccess != RNG_kstat(&kstat_bytes)) { 1.942 + PORT_Assert(0); 1.943 + } 1.944 + bytes += kstat_bytes; 1.945 + PORT_Assert(bytes); 1.946 + } 1.947 +#endif 1.948 + 1.949 +#ifdef DO_NETSTAT 1.950 + fp = safe_popen(netstat_ni_cmd); 1.951 + if (fp != NULL) { 1.952 + while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0) 1.953 + RNG_RandomUpdate(buf, bytes); 1.954 + safe_pclose(fp); 1.955 + } 1.956 +#endif 1.957 + 1.958 +} 1.959 + 1.960 +#define TOTAL_FILE_LIMIT 1000000 /* one million */ 1.961 + 1.962 +size_t RNG_FileUpdate(const char *fileName, size_t limit) 1.963 +{ 1.964 + FILE * file; 1.965 + int fd; 1.966 + int bytes; 1.967 + size_t fileBytes = 0; 1.968 + struct stat stat_buf; 1.969 + unsigned char buffer[BUFSIZ]; 1.970 + static size_t totalFileBytes = 0; 1.971 + 1.972 + /* suppress valgrind warnings due to holes in struct stat */ 1.973 + memset(&stat_buf, 0, sizeof(stat_buf)); 1.974 + 1.975 + if (stat((char *)fileName, &stat_buf) < 0) 1.976 + return fileBytes; 1.977 + RNG_RandomUpdate(&stat_buf, sizeof(stat_buf)); 1.978 + 1.979 + file = fopen(fileName, "r"); 1.980 + if (file != NULL) { 1.981 + /* Read from the underlying file descriptor directly to bypass stdio 1.982 + * buffering and avoid reading more bytes than we need from 1.983 + * /dev/urandom. NOTE: we can't use fread with unbuffered I/O because 1.984 + * fread may return EOF in unbuffered I/O mode on Android. 1.985 + * 1.986 + * Moreover, we read into a buffer of size BUFSIZ, so buffered I/O 1.987 + * has no performance advantage. */ 1.988 + fd = fileno(file); 1.989 + /* 'file' was just opened, so this should not fail. */ 1.990 + PORT_Assert(fd != -1); 1.991 + while (limit > fileBytes) { 1.992 + bytes = PR_MIN(sizeof buffer, limit - fileBytes); 1.993 + bytes = read(fd, buffer, bytes); 1.994 + if (bytes <= 0) 1.995 + break; 1.996 + RNG_RandomUpdate(buffer, bytes); 1.997 + fileBytes += bytes; 1.998 + totalFileBytes += bytes; 1.999 + /* after TOTAL_FILE_LIMIT has been reached, only read in first 1.1000 + ** buffer of data from each subsequent file. 1.1001 + */ 1.1002 + if (totalFileBytes > TOTAL_FILE_LIMIT) 1.1003 + break; 1.1004 + } 1.1005 + fclose(file); 1.1006 + } 1.1007 + /* 1.1008 + * Pass yet another snapshot of our highest resolution clock into 1.1009 + * the hash function. 1.1010 + */ 1.1011 + bytes = RNG_GetNoise(buffer, sizeof(buffer)); 1.1012 + RNG_RandomUpdate(buffer, bytes); 1.1013 + return fileBytes; 1.1014 +} 1.1015 + 1.1016 +void RNG_FileForRNG(const char *fileName) 1.1017 +{ 1.1018 + RNG_FileUpdate(fileName, TOTAL_FILE_LIMIT); 1.1019 +} 1.1020 + 1.1021 +void ReadSingleFile(const char *fileName) 1.1022 +{ 1.1023 + FILE * file; 1.1024 + unsigned char buffer[BUFSIZ]; 1.1025 + 1.1026 + file = fopen(fileName, "rb"); 1.1027 + if (file != NULL) { 1.1028 + while (fread(buffer, 1, sizeof(buffer), file) > 0) 1.1029 + ; 1.1030 + fclose(file); 1.1031 + } 1.1032 +} 1.1033 + 1.1034 +#define _POSIX_PTHREAD_SEMANTICS 1.1035 +#include <dirent.h> 1.1036 + 1.1037 +PRBool 1.1038 +ReadFileOK(char *dir, char *file) 1.1039 +{ 1.1040 + struct stat stat_buf; 1.1041 + char filename[PATH_MAX]; 1.1042 + int count = snprintf(filename, sizeof filename, "%s/%s",dir, file); 1.1043 + 1.1044 + if (count <= 0) { 1.1045 + return PR_FALSE; /* name too long, can't read it anyway */ 1.1046 + } 1.1047 + 1.1048 + if (stat(filename, &stat_buf) < 0) 1.1049 + return PR_FALSE; /* can't stat, probably can't read it then as well */ 1.1050 + return S_ISREG(stat_buf.st_mode) ? PR_TRUE : PR_FALSE; 1.1051 +} 1.1052 + 1.1053 +/* 1.1054 + * read one file out of either /etc or the user's home directory. 1.1055 + * fileToRead tells which file to read. 1.1056 + * 1.1057 + * return 1 if it's time to reset the fileToRead (no more files to read). 1.1058 + */ 1.1059 +int ReadOneFile(int fileToRead) 1.1060 +{ 1.1061 + char *dir = "/etc"; 1.1062 + DIR *fd = opendir(dir); 1.1063 + int resetCount = 0; 1.1064 +#ifdef SOLARIS 1.1065 + /* grumble, Solaris does not define struct dirent to be the full length */ 1.1066 + typedef union { 1.1067 + unsigned char space[sizeof(struct dirent) + MAXNAMELEN]; 1.1068 + struct dirent dir; 1.1069 + } dirent_hack; 1.1070 + dirent_hack entry, firstEntry; 1.1071 + 1.1072 +#define entry_dir entry.dir 1.1073 +#else 1.1074 + struct dirent entry, firstEntry; 1.1075 +#define entry_dir entry 1.1076 +#endif 1.1077 + 1.1078 + int i, error = -1; 1.1079 + 1.1080 + if (fd == NULL) { 1.1081 + dir = getenv("HOME"); 1.1082 + if (dir) { 1.1083 + fd = opendir(dir); 1.1084 + } 1.1085 + } 1.1086 + if (fd == NULL) { 1.1087 + return 1; 1.1088 + } 1.1089 + 1.1090 + for (i=0; i <= fileToRead; i++) { 1.1091 + struct dirent *result = NULL; 1.1092 + do { 1.1093 + error = readdir_r(fd, &entry_dir, &result); 1.1094 + } while (error == 0 && result != NULL && 1.1095 + !ReadFileOK(dir,&result->d_name[0])); 1.1096 + if (error != 0 || result == NULL) { 1.1097 + resetCount = 1; /* read to the end, start again at the beginning */ 1.1098 + if (i != 0) { 1.1099 + /* ran out of entries in the directory, use the first one */ 1.1100 + entry = firstEntry; 1.1101 + error = 0; 1.1102 + break; 1.1103 + } 1.1104 + /* if i== 0, there were no readable entries in the directory */ 1.1105 + break; 1.1106 + } 1.1107 + if (i==0) { 1.1108 + /* save the first entry in case we run out of entries */ 1.1109 + firstEntry = entry; 1.1110 + } 1.1111 + } 1.1112 + 1.1113 + if (error == 0) { 1.1114 + char filename[PATH_MAX]; 1.1115 + int count = snprintf(filename, sizeof filename, 1.1116 + "%s/%s",dir, &entry_dir.d_name[0]); 1.1117 + if (count >= 1) { 1.1118 + ReadSingleFile(filename); 1.1119 + } 1.1120 + } 1.1121 + 1.1122 + closedir(fd); 1.1123 + return resetCount; 1.1124 +} 1.1125 + 1.1126 +/* 1.1127 + * do something to try to introduce more noise into the 'GetNoise' call 1.1128 + */ 1.1129 +static void rng_systemJitter(void) 1.1130 +{ 1.1131 + static int fileToRead = 1; 1.1132 + 1.1133 + if (ReadOneFile(fileToRead)) { 1.1134 + fileToRead = 1; 1.1135 + } else { 1.1136 + fileToRead++; 1.1137 + } 1.1138 +} 1.1139 + 1.1140 +size_t RNG_SystemRNG(void *dest, size_t maxLen) 1.1141 +{ 1.1142 + FILE *file; 1.1143 + int fd; 1.1144 + int bytes; 1.1145 + size_t fileBytes = 0; 1.1146 + unsigned char *buffer = dest; 1.1147 + 1.1148 + file = fopen("/dev/urandom", "r"); 1.1149 + if (file == NULL) { 1.1150 + return rng_systemFromNoise(dest, maxLen); 1.1151 + } 1.1152 + /* Read from the underlying file descriptor directly to bypass stdio 1.1153 + * buffering and avoid reading more bytes than we need from /dev/urandom. 1.1154 + * NOTE: we can't use fread with unbuffered I/O because fread may return 1.1155 + * EOF in unbuffered I/O mode on Android. 1.1156 + */ 1.1157 + fd = fileno(file); 1.1158 + /* 'file' was just opened, so this should not fail. */ 1.1159 + PORT_Assert(fd != -1); 1.1160 + while (maxLen > fileBytes) { 1.1161 + bytes = maxLen - fileBytes; 1.1162 + bytes = read(fd, buffer, bytes); 1.1163 + if (bytes <= 0) 1.1164 + break; 1.1165 + fileBytes += bytes; 1.1166 + buffer += bytes; 1.1167 + } 1.1168 + fclose(file); 1.1169 + if (fileBytes != maxLen) { 1.1170 + PORT_SetError(SEC_ERROR_NEED_RANDOM); /* system RNG failed */ 1.1171 + fileBytes = 0; 1.1172 + } 1.1173 + return fileBytes; 1.1174 +}