diff --git a/mozilla/security/nss/lib/freebl/os2_rand.c b/mozilla/security/nss/lib/freebl/os2_rand.c index 8138d30ae6f..467774b8b54 100644 --- a/mozilla/security/nss/lib/freebl/os2_rand.c +++ b/mozilla/security/nss/lib/freebl/os2_rand.c @@ -37,7 +37,8 @@ #define INCL_DOS #define INCL_DOSERRORS #include -#include +#include "secrng.h" +#include "prerror.h" #include #include #include @@ -331,3 +332,9 @@ void RNG_FileForRNG(const char *filename) nBytes = RNG_GetNoise(buffer, 20); RNG_RandomUpdate(buffer, nBytes); } + +size_t RNG_SystemRNG(void *dest, size_t maxLen) +{ + PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); + return 0; +} diff --git a/mozilla/security/nss/lib/freebl/prng_fips1861.c b/mozilla/security/nss/lib/freebl/prng_fips1861.c index f841a21c832..dad533f1cef 100644 --- a/mozilla/security/nss/lib/freebl/prng_fips1861.c +++ b/mozilla/security/nss/lib/freebl/prng_fips1861.c @@ -35,7 +35,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: prng_fips1861.c,v 1.25 2006-09-26 22:20:18 julien.pierre.bugs%sun.com Exp $ */ +/* $Id: prng_fips1861.c,v 1.26 2006-10-12 02:23:49 wtchang%redhat.com Exp $ */ #include "prerr.h" #include "secerr.h" @@ -347,7 +347,7 @@ static const PRCallOnceType pristineCallOnce; static PRCallOnceType coRNGInit; static PRStatus rng_init(void) { - unsigned char bytes[120]; + unsigned char bytes[SYSTEM_RNG_SEED_COUNT]; unsigned int numBytes; if (globalrng == NULL) { /* create a new global RNG context */ @@ -362,7 +362,31 @@ static PRStatus rng_init(void) } /* the RNG is in a valid state */ globalrng->isValid = PR_TRUE; - /* Try to get some seed data for the RNG */ + /* + * Try to get some seed data for the RNG. + * + * The very first RNG_RandomUpdate call initializes all FIPS_B + * bits of the RNG's seed-key. Subsequent RNG_RandomUpdate calls + * only modify the low FIPS_G bits of the seed-key. So it's + * important to pass high entropy to the first RNG_RandomUpdate + * call. + * + * RNG_GetNoise only reads the high-resolution clocks, which + * have low entropy. So if RNG_SystemRNG fails, the RNG will + * have at most slightly more than FIPS_G bits of entropy. + */ + numBytes = RNG_SystemRNG(bytes, sizeof bytes); + PORT_Assert(numBytes == 0 || numBytes == sizeof bytes); + if (numBytes != 0) { + RNG_RandomUpdate(bytes, numBytes); + memset(bytes, 0, numBytes); + } else if (PORT_GetError() != PR_NOT_IMPLEMENTED_ERROR) { + PZ_DestroyLock(globalrng->lock); + globalrng->lock = NULL; + globalrng->isValid = PR_FALSE; + globalrng = NULL; + return PR_FAILURE; + } numBytes = RNG_GetNoise(bytes, sizeof bytes); RNG_RandomUpdate(bytes, numBytes); } diff --git a/mozilla/security/nss/lib/freebl/secrng.h b/mozilla/security/nss/lib/freebl/secrng.h index ab07116a365..427cab888c9 100644 --- a/mozilla/security/nss/lib/freebl/secrng.h +++ b/mozilla/security/nss/lib/freebl/secrng.h @@ -40,7 +40,7 @@ * secrng.h - public data structures and prototypes for the secure random * number generator * - * $Id: secrng.h,v 1.5 2004-04-25 15:03:08 gerv%gerv.net Exp $ + * $Id: secrng.h,v 1.6 2006-10-12 02:23:49 wtchang%redhat.com Exp $ */ /******************************************/ @@ -51,11 +51,14 @@ #include "blapi.h" +/* the number of bytes to read from the system random number generator */ +#define SYSTEM_RNG_SEED_COUNT 1024 + SEC_BEGIN_PROTOS /* -** The following 3 functions are provided by the security library -** but are differently implemented for the UNIX, Mac and Win +** The following functions are provided by the security library +** but are differently implemented for the UNIX, Win, and OS/2 ** versions */ @@ -80,6 +83,17 @@ extern void RNG_SystemInfoForRNG(void); */ extern void RNG_FileForRNG(const char *filename); +/* +** Get maxbytes bytes of random data from the system random number +** generator. +** Returns the number of bytes copied into buf -- maxbytes if success +** or zero if error. +** Errors: +** PR_NOT_IMPLEMENTED_ERROR There is no system RNG on the platform. +** SEC_ERROR_NEED_RANDOM The system RNG failed. +*/ +extern size_t RNG_SystemRNG(void *buf, size_t maxbytes); + SEC_END_PROTOS #endif /* _SECRNG_H_ */ diff --git a/mozilla/security/nss/lib/freebl/unix_rand.c b/mozilla/security/nss/lib/freebl/unix_rand.c index a3afe5da919..883d2663e36 100644 --- a/mozilla/security/nss/lib/freebl/unix_rand.c +++ b/mozilla/security/nss/lib/freebl/unix_rand.c @@ -43,8 +43,9 @@ #include #include #include -#include #include "secrng.h" +#include "secerr.h" +#include "prerror.h" size_t RNG_FileUpdate(const char *fileName, size_t limit); @@ -955,7 +956,7 @@ for the small amount of entropy it provides. GiveSystemInfo(); /* grab some data from system's PRNG before any other files. */ - bytes = RNG_FileUpdate("/dev/urandom", 1024); + bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT); /* If the user points us to a random file, pass it through the rng */ randfile = getenv("NSRANDFILE"); @@ -1130,3 +1131,31 @@ void RNG_FileForRNG(const char *fileName) { RNG_FileUpdate(fileName, TOTAL_FILE_LIMIT); } + +size_t RNG_SystemRNG(void *dest, size_t maxLen) +{ + FILE *file; + size_t bytes; + size_t fileBytes = 0; + unsigned char *buffer = dest; + + file = fopen("/dev/urandom", "r"); + if (file == NULL) { + PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); + return fileBytes; + } + while (maxLen > fileBytes) { + bytes = maxLen - fileBytes; + bytes = fread(buffer, 1, bytes, file); + if (bytes == 0) + break; + fileBytes += bytes; + buffer += bytes; + } + fclose(file); + if (fileBytes != maxLen) { + PORT_SetError(SEC_ERROR_NEED_RANDOM); /* system RNG failed */ + fileBytes = 0; + } + return fileBytes; +} diff --git a/mozilla/security/nss/lib/freebl/win_rand.c b/mozilla/security/nss/lib/freebl/win_rand.c index 040ae036d11..5c0eff41b85 100644 --- a/mozilla/security/nss/lib/freebl/win_rand.c +++ b/mozilla/security/nss/lib/freebl/win_rand.c @@ -35,6 +35,7 @@ * ***** END LICENSE BLOCK ***** */ #include "secrng.h" +#include "secerr.h" #ifdef XP_WIN #include @@ -56,6 +57,7 @@ #endif #include "prio.h" +#include "prerror.h" static PRInt32 filesToRead; static DWORD totalFileBytes; @@ -544,4 +546,96 @@ void RNG_FileForRNG(const char *filename) } #endif /* not WinCE */ + +/* + * CryptoAPI requires Windows NT 4.0 or Windows 95 OSR2 and later. + * Until we drop support for Windows 95, we need to emulate some + * definitions and declarations in and look up the + * functions in advapi32.dll at run time. + */ + +typedef unsigned long HCRYPTPROV; + +#define CRYPT_VERIFYCONTEXT 0xF0000000 + +#define PROV_RSA_FULL 1 + +typedef BOOL +(WINAPI *CryptAcquireContextAFn)( + HCRYPTPROV *phProv, + LPCSTR pszContainer, + LPCSTR pszProvider, + DWORD dwProvType, + DWORD dwFlags); + +typedef BOOL +(WINAPI *CryptReleaseContextFn)( + HCRYPTPROV hProv, + DWORD dwFlags); + +typedef BOOL +(WINAPI *CryptGenRandomFn)( + HCRYPTPROV hProv, + DWORD dwLen, + BYTE *pbBuffer); + +/* + * Windows XP and Windows Server 2003 and later have RtlGenRandom, + * which must be looked up by the name SystemFunction036. + */ +typedef BOOLEAN +(APIENTRY *RtlGenRandomFn)( + PVOID RandomBuffer, + ULONG RandomBufferLength); + +size_t RNG_SystemRNG(void *dest, size_t maxLen) +{ + HMODULE hModule; + RtlGenRandomFn pRtlGenRandom; + CryptAcquireContextAFn pCryptAcquireContextA; + CryptReleaseContextFn pCryptReleaseContext; + CryptGenRandomFn pCryptGenRandom; + HCRYPTPROV hCryptProv; + size_t bytes = 0; + + hModule = LoadLibrary("advapi32.dll"); + if (hModule == NULL) { + PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); + return 0; + } + pRtlGenRandom = (RtlGenRandomFn) + GetProcAddress(hModule, "SystemFunction036"); + if (pRtlGenRandom) { + if (pRtlGenRandom(dest, maxLen)) { + bytes = maxLen; + } else { + PORT_SetError(SEC_ERROR_NEED_RANDOM); /* system RNG failed */ + } + goto done; + } + pCryptAcquireContextA = (CryptAcquireContextAFn) + GetProcAddress(hModule, "CryptAcquireContextA"); + pCryptReleaseContext = (CryptReleaseContextFn) + GetProcAddress(hModule, "CryptReleaseContext"); + pCryptGenRandom = (CryptGenRandomFn) + GetProcAddress(hModule, "CryptGenRandom"); + if (!pCryptAcquireContextA || !pCryptReleaseContext || !pCryptGenRandom) { + PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); + goto done; + } + if (pCryptAcquireContextA(&hCryptProv, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + if (pCryptGenRandom(hCryptProv, maxLen, dest)) { + bytes = maxLen; + } + pCryptReleaseContext(hCryptProv, 0); + } + if (bytes == 0) { + PORT_SetError(SEC_ERROR_NEED_RANDOM); /* system RNG failed */ + } +done: + FreeLibrary(hModule); + return bytes; +} + #endif /* is XP_WIN */