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