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