~ubuntu-branches/ubuntu/lucid/seamonkey/lucid-security

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Fabien Tassin
  • Date: 2008-07-29 21:29:02 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080729212902-spm9kpvchp9udwbw
Tags: 1.1.11+nobinonly-0ubuntu1
* New security upstream release: 1.1.11 (LP: #218534)
  Fixes USN-602-1, USN-619-1, USN-623-1 and USN-629-1
* Refresh diverged patch:
  - update debian/patches/80_security_build.patch
* Fix FTBFS with missing -lfontconfig
  - add debian/patches/11_fix_ftbfs_with_fontconfig.patch
  - update debian/patches/series
* Build with default gcc (hardy: 4.2, intrepid: 4.3)
  - update debian/rules
  - update debian/control

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 "secrng.h"
 
38
#include "secerr.h"
 
39
#ifdef XP_WIN
 
40
#include <windows.h>
 
41
 
 
42
#if defined(_WIN32_WCE)
 
43
#include <stdlib.h>     /* Win CE puts lots of stuff here. */
 
44
#include "prprf.h"      /* for PR_snprintf */
 
45
#else
 
46
#include <time.h>
 
47
#include <io.h>
 
48
#include <sys/types.h>
 
49
#include <sys/stat.h>
 
50
#endif
 
51
#include <stdio.h>
 
52
 
 
53
#ifndef _WIN32
 
54
#define VTD_Device_ID   5
 
55
#define OP_OVERRIDE     _asm _emit 0x66
 
56
#include <dos.h>
 
57
#endif
 
58
 
 
59
#include "prio.h"
 
60
#include "prerror.h"
 
61
 
 
62
static PRInt32  filesToRead;
 
63
static DWORD    totalFileBytes;
 
64
static DWORD    maxFileBytes    = 250000;       /* 250 thousand */
 
65
static DWORD    dwNumFiles, dwReadEvery;
 
66
 
 
67
static BOOL
 
68
CurrentClockTickTime(LPDWORD lpdwHigh, LPDWORD lpdwLow)
 
69
{
 
70
#ifdef _WIN32
 
71
    LARGE_INTEGER   liCount;
 
72
 
 
73
    if (!QueryPerformanceCounter(&liCount))
 
74
        return FALSE;
 
75
 
 
76
    *lpdwHigh = liCount.u.HighPart;
 
77
    *lpdwLow = liCount.u.LowPart;
 
78
    return TRUE;
 
79
 
 
80
#else   /* is WIN16 */
 
81
    BOOL    bRetVal;
 
82
    FARPROC lpAPI;
 
83
    WORD    w1, w2, w3, w4;
 
84
 
 
85
    // Get direct access to the VTD and query the current clock tick time
 
86
    _asm {
 
87
        xor   di, di
 
88
        mov   es, di
 
89
        mov   ax, 1684h
 
90
        mov   bx, VTD_Device_ID
 
91
        int   2fh
 
92
        mov   ax, es
 
93
        or    ax, di
 
94
        jz    EnumerateFailed
 
95
 
 
96
        ; VTD API is available. First store the API address (the address actually
 
97
        ; contains an instruction that causes a fault, the fault handler then
 
98
        ; makes the ring transition and calls the API in the VxD)
 
99
        mov   word ptr lpAPI, di
 
100
        mov   word ptr lpAPI+2, es
 
101
        mov   ax, 100h      ; API function to VTD_Get_Real_Time
 
102
;       call  dword ptr [lpAPI]
 
103
        call  [lpAPI]
 
104
 
 
105
        ; Result is in EDX:EAX which we will get 16-bits at a time
 
106
        mov   w2, dx
 
107
        OP_OVERRIDE
 
108
        shr   dx,10h        ; really "shr edx, 16"
 
109
        mov   w1, dx
 
110
 
 
111
        mov   w4, ax
 
112
        OP_OVERRIDE
 
113
        shr   ax,10h        ; really "shr eax, 16"
 
114
        mov   w3, ax
 
115
 
 
116
        mov   bRetVal, 1    ; return TRUE
 
117
        jmp   EnumerateExit
 
118
 
 
119
      EnumerateFailed:
 
120
        mov   bRetVal, 0    ; return FALSE
 
121
 
 
122
      EnumerateExit:
 
123
    }
 
124
 
 
125
    *lpdwHigh = MAKELONG(w2, w1);
 
126
    *lpdwLow = MAKELONG(w4, w3);
 
127
 
 
128
    return bRetVal;
 
129
#endif  /* is WIN16 */
 
130
}
 
131
 
 
132
size_t RNG_GetNoise(void *buf, size_t maxbuf)
 
133
{
 
134
    DWORD   dwHigh, dwLow, dwVal;
 
135
    int     n = 0;
 
136
    int     nBytes;
 
137
 
 
138
    if (maxbuf <= 0)
 
139
        return 0;
 
140
 
 
141
    CurrentClockTickTime(&dwHigh, &dwLow);
 
142
 
 
143
    // get the maximally changing bits first
 
144
    nBytes = sizeof(dwLow) > maxbuf ? maxbuf : sizeof(dwLow);
 
145
    memcpy((char *)buf, &dwLow, nBytes);
 
146
    n += nBytes;
 
147
    maxbuf -= nBytes;
 
148
 
 
149
    if (maxbuf <= 0)
 
150
        return n;
 
151
 
 
152
    nBytes = sizeof(dwHigh) > maxbuf ? maxbuf : sizeof(dwHigh);
 
153
    memcpy(((char *)buf) + n, &dwHigh, nBytes);
 
154
    n += nBytes;
 
155
    maxbuf -= nBytes;
 
156
 
 
157
    if (maxbuf <= 0)
 
158
        return n;
 
159
 
 
160
    // get the number of milliseconds that have elapsed since Windows started
 
161
    dwVal = GetTickCount();
 
162
 
 
163
    nBytes = sizeof(dwVal) > maxbuf ? maxbuf : sizeof(dwVal);
 
164
    memcpy(((char *)buf) + n, &dwVal, nBytes);
 
165
    n += nBytes;
 
166
    maxbuf -= nBytes;
 
167
 
 
168
    if (maxbuf <= 0)
 
169
        return n;
 
170
 
 
171
#if defined(_WIN32_WCE)
 
172
    {
 
173
    // get the number of milliseconds elapsed since Windows CE was started. 
 
174
    DWORD  tickCount = GetTickCount();
 
175
    nBytes = (sizeof tickCount) > maxbuf ? maxbuf : (sizeof tickCount);
 
176
    memcpy(((char *)buf) + n, &tickCount, nBytes);
 
177
    n += nBytes;
 
178
    }
 
179
#else
 
180
    {
 
181
    time_t  sTime;
 
182
    // get the time in seconds since midnight Jan 1, 1970
 
183
    time(&sTime);
 
184
    nBytes = sizeof(sTime) > maxbuf ? maxbuf : sizeof(sTime);
 
185
    memcpy(((char *)buf) + n, &sTime, nBytes);
 
186
    n += nBytes;
 
187
    }
 
188
#endif
 
189
 
 
190
    return n;
 
191
}
 
192
 
 
193
#if defined(_WIN32_WCE)
 
194
static BOOL
 
195
EnumSystemFilesWithNSPR(const char * dirName, 
 
196
                        BOOL recursive,
 
197
                        PRInt32 (*func)(const char *))
 
198
{
 
199
    PRDir *      pDir;
 
200
    PRDirEntry * pEntry;
 
201
    BOOL         rv             = FALSE;
 
202
 
 
203
    pDir = PR_OpenDir(dirName);
 
204
    if (!pDir)
 
205
        return rv;
 
206
    while ((pEntry = PR_ReadDir(pDir, PR_SKIP_BOTH|PR_SKIP_HIDDEN)) != NULL) {
 
207
        PRStatus    status;
 
208
        PRInt32     count;
 
209
        PRInt32     stop;
 
210
        PRFileInfo  fileInfo;
 
211
        char        szFileName[_MAX_PATH];
 
212
 
 
213
        count = (PRInt32)PR_snprintf(szFileName, sizeof szFileName, "%s\\%s", 
 
214
                                     dirName, PR_DirName(pEntry));
 
215
        if (count < 1)
 
216
            continue;
 
217
        status = PR_GetFileInfo(szFileName, &fileInfo);
 
218
        if (status != PR_SUCCESS)
 
219
            continue;
 
220
        if (fileInfo.type == PR_FILE_FILE) {
 
221
            stop = (*func)(szFileName);
 
222
            rv = TRUE;
 
223
            if (stop)
 
224
                break;
 
225
            continue;
 
226
        }
 
227
        if (recursive && fileInfo.type == PR_FILE_DIRECTORY) {
 
228
            rv |= EnumSystemFilesWithNSPR(szFileName, recursive, func);
 
229
        }
 
230
    }
 
231
    PR_CloseDir(pDir);
 
232
    return rv;
 
233
}
 
234
#endif
 
235
 
 
236
static BOOL
 
237
EnumSystemFiles(PRInt32 (*func)(const char *))
 
238
{
 
239
#if defined(_WIN32_WCE)
 
240
    BOOL rv = FALSE;
 
241
    rv |= EnumSystemFilesWithNSPR("\\Windows\\Temporary Internet Files", TRUE, func);
 
242
    rv |= EnumSystemFilesWithNSPR("\\Temp",    FALSE, func);
 
243
    rv |= EnumSystemFilesWithNSPR("\\Windows", FALSE, func);
 
244
    return rv;
 
245
#else
 
246
    int                 iStatus;
 
247
    char                szSysDir[_MAX_PATH];
 
248
    char                szFileName[_MAX_PATH];
 
249
#ifdef _WIN32
 
250
    struct _finddata_t  fdData;
 
251
    long                lFindHandle;
 
252
#else
 
253
    struct _find_t  fdData;
 
254
#endif
 
255
 
 
256
    if (!GetSystemDirectory(szSysDir, sizeof(szSysDir)))
 
257
        return FALSE;
 
258
 
 
259
    // tack *.* on the end so we actually look for files. this will
 
260
    // not overflow
 
261
    strcpy(szFileName, szSysDir);
 
262
    strcat(szFileName, "\\*.*");
 
263
 
 
264
#ifdef _WIN32
 
265
    lFindHandle = _findfirst(szFileName, &fdData);
 
266
    if (lFindHandle == -1)
 
267
        return FALSE;
 
268
#else
 
269
    if (_dos_findfirst(szFileName, _A_NORMAL | _A_RDONLY | _A_ARCH | _A_SUBDIR, &fdData) != 0)
 
270
        return FALSE;
 
271
#endif
 
272
 
 
273
    do {
 
274
        // pass the full pathname to the callback
 
275
        sprintf(szFileName, "%s\\%s", szSysDir, fdData.name);
 
276
        (*func)(szFileName);
 
277
 
 
278
#ifdef _WIN32
 
279
        iStatus = _findnext(lFindHandle, &fdData);
 
280
#else
 
281
        iStatus = _dos_findnext(&fdData);
 
282
#endif
 
283
    } while (iStatus == 0);
 
284
 
 
285
#ifdef _WIN32
 
286
    _findclose(lFindHandle);
 
287
#endif
 
288
 
 
289
    return TRUE;
 
290
#endif
 
291
}
 
292
 
 
293
static PRInt32
 
294
CountFiles(const char *file)
 
295
{
 
296
    dwNumFiles++;
 
297
    return 0;
 
298
}
 
299
 
 
300
static PRInt32
 
301
ReadFiles(const char *file)
 
302
{
 
303
    if ((dwNumFiles % dwReadEvery) == 0) {
 
304
        ++filesToRead;
 
305
    }
 
306
    if (filesToRead) {
 
307
        DWORD    prevFileBytes = totalFileBytes;
 
308
        RNG_FileForRNG(file);
 
309
        if (prevFileBytes < totalFileBytes) {
 
310
            --filesToRead;
 
311
        }
 
312
    }
 
313
    dwNumFiles++;
 
314
    return (totalFileBytes >= maxFileBytes);
 
315
}
 
316
 
 
317
static void
 
318
ReadSystemFiles()
 
319
{
 
320
    // first count the number of files
 
321
    dwNumFiles = 0;
 
322
    if (!EnumSystemFiles(CountFiles))
 
323
        return;
 
324
 
 
325
    RNG_RandomUpdate(&dwNumFiles, sizeof(dwNumFiles));
 
326
 
 
327
    // now read 10 files
 
328
    filesToRead = 10;
 
329
    if (dwNumFiles == 0)
 
330
        return;
 
331
 
 
332
    dwReadEvery = dwNumFiles / 10;
 
333
    if (dwReadEvery == 0)
 
334
        dwReadEvery = 1;  // less than 10 files
 
335
 
 
336
    dwNumFiles = 0;
 
337
    EnumSystemFiles(ReadFiles);
 
338
}
 
339
 
 
340
void RNG_SystemInfoForRNG(void)
 
341
{
 
342
    DWORD           dwVal;
 
343
    char            buffer[256];
 
344
    int             nBytes;
 
345
#ifdef _WIN32
 
346
    MEMORYSTATUS    sMem;
 
347
    HANDLE          hVal;
 
348
#if !defined(_WIN32_WCE)
 
349
    DWORD           dwSerialNum;
 
350
    DWORD           dwComponentLen;
 
351
    DWORD           dwSysFlags;
 
352
    char            volName[128];
 
353
    DWORD           dwSectors, dwBytes, dwFreeClusters, dwNumClusters;
 
354
#endif
 
355
#else
 
356
    int             iVal;
 
357
    HTASK           hTask;
 
358
    WORD            wDS, wCS;
 
359
    LPSTR           lpszEnv;
 
360
#endif
 
361
 
 
362
    nBytes = RNG_GetNoise(buffer, 20);  // get up to 20 bytes
 
363
    RNG_RandomUpdate(buffer, nBytes);
 
364
 
 
365
#ifdef _WIN32
 
366
    sMem.dwLength = sizeof(sMem);
 
367
    GlobalMemoryStatus(&sMem);                // assorted memory stats
 
368
    RNG_RandomUpdate(&sMem, sizeof(sMem));
 
369
#if !defined(_WIN32_WCE)
 
370
    dwVal = GetLogicalDrives();
 
371
    RNG_RandomUpdate(&dwVal, sizeof(dwVal));  // bitfields in bits 0-25
 
372
#endif
 
373
#else
 
374
    dwVal = GetFreeSpace(0);
 
375
    RNG_RandomUpdate(&dwVal, sizeof(dwVal));
 
376
 
 
377
    _asm    mov wDS, ds;
 
378
    _asm    mov wCS, cs;
 
379
    RNG_RandomUpdate(&wDS, sizeof(wDS));
 
380
    RNG_RandomUpdate(&wCS, sizeof(wCS));
 
381
#endif
 
382
 
 
383
#ifdef _WIN32
 
384
#if !defined(_WIN32_WCE)
 
385
    dwVal = sizeof(buffer);
 
386
    if (GetComputerName(buffer, &dwVal))
 
387
        RNG_RandomUpdate(buffer, dwVal);
 
388
#endif
 
389
/* XXX This is code that got yanked because of NSPR20.  We should put it
 
390
 * back someday.
 
391
 */
 
392
#ifdef notdef
 
393
    {
 
394
    POINT ptVal;
 
395
    GetCursorPos(&ptVal);
 
396
    RNG_RandomUpdate(&ptVal, sizeof(ptVal));
 
397
    }
 
398
 
 
399
    dwVal = GetQueueStatus(QS_ALLINPUT);      // high and low significant
 
400
    RNG_RandomUpdate(&dwVal, sizeof(dwVal));
 
401
 
 
402
    {
 
403
    HWND hWnd;
 
404
    hWnd = GetClipboardOwner();               // 2 or 4 bytes
 
405
    RNG_RandomUpdate((void *)&hWnd, sizeof(hWnd));
 
406
    }
 
407
 
 
408
    {
 
409
    UUID sUuid;
 
410
    UuidCreate(&sUuid);                       // this will fail on machines with no ethernet
 
411
    RNG_RandomUpdate(&sUuid, sizeof(sUuid));  // boards. shove the bits in regardless
 
412
    }
 
413
#endif
 
414
 
 
415
    hVal = GetCurrentProcess();               // 4 byte handle of current task
 
416
    RNG_RandomUpdate(&hVal, sizeof(hVal));
 
417
 
 
418
    dwVal = GetCurrentProcessId();            // process ID (4 bytes)
 
419
    RNG_RandomUpdate(&dwVal, sizeof(dwVal));
 
420
 
 
421
#if !defined(_WIN32_WCE)
 
422
    volName[0] = '\0';
 
423
    buffer[0] = '\0';
 
424
    GetVolumeInformation(NULL,
 
425
                         volName,
 
426
                         sizeof(volName),
 
427
                         &dwSerialNum,
 
428
                         &dwComponentLen,
 
429
                         &dwSysFlags,
 
430
                         buffer,
 
431
                         sizeof(buffer));
 
432
 
 
433
    RNG_RandomUpdate(volName,         strlen(volName));
 
434
    RNG_RandomUpdate(&dwSerialNum,    sizeof(dwSerialNum));
 
435
    RNG_RandomUpdate(&dwComponentLen, sizeof(dwComponentLen));
 
436
    RNG_RandomUpdate(&dwSysFlags,     sizeof(dwSysFlags));
 
437
    RNG_RandomUpdate(buffer,          strlen(buffer));
 
438
 
 
439
    if (GetDiskFreeSpace(NULL, &dwSectors, &dwBytes, &dwFreeClusters, &dwNumClusters)) {
 
440
        RNG_RandomUpdate(&dwSectors,      sizeof(dwSectors));
 
441
        RNG_RandomUpdate(&dwBytes,        sizeof(dwBytes));
 
442
        RNG_RandomUpdate(&dwFreeClusters, sizeof(dwFreeClusters));
 
443
        RNG_RandomUpdate(&dwNumClusters,  sizeof(dwNumClusters));
 
444
    }
 
445
#endif
 
446
#else   /* is WIN16 */
 
447
    hTask = GetCurrentTask();
 
448
    RNG_RandomUpdate((void *)&hTask, sizeof(hTask));
 
449
 
 
450
    iVal = GetNumTasks();
 
451
    RNG_RandomUpdate(&iVal, sizeof(iVal));      // number of running tasks
 
452
 
 
453
    lpszEnv = GetDOSEnvironment();
 
454
    while (*lpszEnv != '\0') {
 
455
        RNG_RandomUpdate(lpszEnv, strlen(lpszEnv));
 
456
 
 
457
        lpszEnv += strlen(lpszEnv) + 1;
 
458
    }
 
459
#endif  /* is WIN16 */
 
460
 
 
461
    // now let's do some files
 
462
    ReadSystemFiles();
 
463
 
 
464
    nBytes = RNG_GetNoise(buffer, 20);  // get up to 20 bytes
 
465
    RNG_RandomUpdate(buffer, nBytes);
 
466
}
 
467
 
 
468
#if defined(_WIN32_WCE)
 
469
void RNG_FileForRNG(const char *filename)
 
470
{
 
471
    PRFileDesc *    file;
 
472
    int             nBytes;
 
473
    PRFileInfo      infoBuf;
 
474
    unsigned char   buffer[1024];
 
475
 
 
476
    /* windows doesn't initialize all the bytes in the stat buf,
 
477
     * so initialize them all here to avoid UMRs.
 
478
     */
 
479
    memset(&infoBuf, 0, sizeof infoBuf);
 
480
 
 
481
    if (PR_GetFileInfo(filename, &infoBuf) < 0)
 
482
        return;
 
483
 
 
484
    RNG_RandomUpdate((unsigned char*)&infoBuf, sizeof(infoBuf));
 
485
 
 
486
    file = PR_Open(filename, PR_RDONLY, 0);
 
487
    if (file != NULL) {
 
488
        for (;;) {
 
489
            PRInt32 bytes = PR_Read(file, buffer, sizeof buffer);
 
490
 
 
491
            if (bytes <= 0)
 
492
                break;
 
493
 
 
494
            RNG_RandomUpdate(buffer, bytes);
 
495
            totalFileBytes += bytes;
 
496
            if (totalFileBytes > maxFileBytes)
 
497
                break;
 
498
        }
 
499
 
 
500
        PR_Close(file);
 
501
    }
 
502
 
 
503
    nBytes = RNG_GetNoise(buffer, 20);  // get up to 20 bytes
 
504
    RNG_RandomUpdate(buffer, nBytes);
 
505
}
 
506
 
 
507
#else /* not WinCE */
 
508
 
 
509
void RNG_FileForRNG(const char *filename)
 
510
{
 
511
    FILE*           file;
 
512
    int             nBytes;
 
513
    struct stat     stat_buf;
 
514
    unsigned char   buffer[1024];
 
515
 
 
516
   /* static DWORD    totalFileBytes = 0; */
 
517
 
 
518
    /* windows doesn't initialize all the bytes in the stat buf,
 
519
     * so initialize them all here to avoid UMRs.
 
520
     */
 
521
    memset(&stat_buf, 0, sizeof stat_buf);
 
522
 
 
523
    if (stat((char *)filename, &stat_buf) < 0)
 
524
        return;
 
525
 
 
526
    RNG_RandomUpdate((unsigned char*)&stat_buf, sizeof(stat_buf));
 
527
 
 
528
    file = fopen((char *)filename, "r");
 
529
    if (file != NULL) {
 
530
        for (;;) {
 
531
            size_t  bytes = fread(buffer, 1, sizeof(buffer), file);
 
532
 
 
533
            if (bytes == 0)
 
534
                break;
 
535
 
 
536
            RNG_RandomUpdate(buffer, bytes);
 
537
            totalFileBytes += bytes;
 
538
            if (totalFileBytes > maxFileBytes)
 
539
                break;
 
540
        }
 
541
 
 
542
        fclose(file);
 
543
    }
 
544
 
 
545
    nBytes = RNG_GetNoise(buffer, 20);  // get up to 20 bytes
 
546
    RNG_RandomUpdate(buffer, nBytes);
 
547
}
 
548
 
 
549
#endif  /* not WinCE */
 
550
 
 
551
/*
 
552
 * CryptoAPI requires Windows NT 4.0 or Windows 95 OSR2 and later.
 
553
 * Until we drop support for Windows 95, we need to emulate some
 
554
 * definitions and declarations in <wincrypt.h> and look up the
 
555
 * functions in advapi32.dll at run time.
 
556
 */
 
557
 
 
558
typedef unsigned long HCRYPTPROV;
 
559
 
 
560
#define CRYPT_VERIFYCONTEXT 0xF0000000
 
561
 
 
562
#define PROV_RSA_FULL 1
 
563
 
 
564
typedef BOOL
 
565
(WINAPI *CryptAcquireContextAFn)(
 
566
    HCRYPTPROV *phProv,
 
567
    LPCSTR pszContainer,
 
568
    LPCSTR pszProvider,
 
569
    DWORD dwProvType,
 
570
    DWORD dwFlags);
 
571
 
 
572
typedef BOOL
 
573
(WINAPI *CryptReleaseContextFn)(
 
574
    HCRYPTPROV hProv,
 
575
    DWORD dwFlags);
 
576
 
 
577
typedef BOOL
 
578
(WINAPI *CryptGenRandomFn)(
 
579
    HCRYPTPROV hProv,
 
580
    DWORD dwLen,
 
581
    BYTE *pbBuffer);
 
582
 
 
583
/*
 
584
 * Windows XP and Windows Server 2003 and later have RtlGenRandom,
 
585
 * which must be looked up by the name SystemFunction036.
 
586
 */
 
587
typedef BOOLEAN
 
588
(APIENTRY *RtlGenRandomFn)(
 
589
    PVOID RandomBuffer,
 
590
    ULONG RandomBufferLength);
 
591
 
 
592
size_t RNG_SystemRNG(void *dest, size_t maxLen)
 
593
{
 
594
    HMODULE hModule;
 
595
    RtlGenRandomFn pRtlGenRandom;
 
596
    CryptAcquireContextAFn pCryptAcquireContextA;
 
597
    CryptReleaseContextFn pCryptReleaseContext;
 
598
    CryptGenRandomFn pCryptGenRandom;
 
599
    HCRYPTPROV hCryptProv;
 
600
    size_t bytes = 0;
 
601
 
 
602
    hModule = LoadLibrary("advapi32.dll");
 
603
    if (hModule == NULL) {
 
604
        PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
 
605
        return 0;
 
606
    }
 
607
    pRtlGenRandom = (RtlGenRandomFn)
 
608
        GetProcAddress(hModule, "SystemFunction036");
 
609
    if (pRtlGenRandom) {
 
610
        if (pRtlGenRandom(dest, maxLen)) {
 
611
            bytes = maxLen;
 
612
        } else {
 
613
            PORT_SetError(SEC_ERROR_NEED_RANDOM);  /* system RNG failed */
 
614
        }
 
615
        goto done;
 
616
    }
 
617
    pCryptAcquireContextA = (CryptAcquireContextAFn)
 
618
        GetProcAddress(hModule, "CryptAcquireContextA");
 
619
    pCryptReleaseContext = (CryptReleaseContextFn)
 
620
        GetProcAddress(hModule, "CryptReleaseContext");
 
621
    pCryptGenRandom = (CryptGenRandomFn)
 
622
        GetProcAddress(hModule, "CryptGenRandom");
 
623
    if (!pCryptAcquireContextA || !pCryptReleaseContext || !pCryptGenRandom) {
 
624
        PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
 
625
        goto done;
 
626
    }
 
627
    if (pCryptAcquireContextA(&hCryptProv, NULL, NULL,
 
628
        PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
 
629
        if (pCryptGenRandom(hCryptProv, maxLen, dest)) {
 
630
            bytes = maxLen;
 
631
        }
 
632
        pCryptReleaseContext(hCryptProv, 0);
 
633
    }
 
634
    if (bytes == 0) {
 
635
        PORT_SetError(SEC_ERROR_NEED_RANDOM);  /* system RNG failed */
 
636
    }
 
637
done:
 
638
    FreeLibrary(hModule);
 
639
    return bytes;
 
640
}
 
641
 
 
642
#endif  /* is XP_WIN */