~ubuntu-branches/ubuntu/trusty/xulrunner/trusty

« back to all changes in this revision

Viewing changes to security/nss-fips/lib/freebl/unix_rand.c

  • Committer: Bazaar Package Importer
  • Author(s): Devid Antonio Filoni
  • Date: 2008-08-25 13:04:18 UTC
  • mfrom: (1.1.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20080825130418-ck1i2ms384tzb9m0
Tags: 1.8.1.16+nobinonly-0ubuntu1
* New upstream release (taken from upstream CVS), LP: #254618.
* Fix MFSA 2008-35, MFSA 2008-34, MFSA 2008-33, MFSA 2008-32, MFSA 2008-31,
  MFSA 2008-30, MFSA 2008-29, MFSA 2008-28, MFSA 2008-27, MFSA 2008-25,
  MFSA 2008-24, MFSA 2008-23, MFSA 2008-22, MFSA 2008-21, MFSA 2008-26 also
  known as CVE-2008-2933, CVE-2008-2785, CVE-2008-2811, CVE-2008-2810,
  CVE-2008-2809, CVE-2008-2808, CVE-2008-2807, CVE-2008-2806, CVE-2008-2805,
  CVE-2008-2803, CVE-2008-2802, CVE-2008-2801, CVE-2008-2800, CVE-2008-2798.
* Drop 89_bz419350_attachment_306066 patch, merged upstream.
* Bump Standards-Version to 3.8.0.

Show diffs side-by-side

added added

removed removed

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