diff options
author | wtchang%redhat.com <devnull@localhost> | 2006-10-12 02:18:38 +0000 |
---|---|---|
committer | wtchang%redhat.com <devnull@localhost> | 2006-10-12 02:18:38 +0000 |
commit | a17d2794b63e4f34072e6f6daac33a6e9674e911 (patch) | |
tree | f785b2c125384b5473e032df2808ff6e0a79e672 | |
parent | e08628135f8f10b276b326135a657158b03902c7 (diff) | |
download | nss-hg-a17d2794b63e4f34072e6f6daac33a6e9674e911.tar.gz |
Bugzilla Bug 355297: added new function RNG_SystemRNG, which gets random
bits from the system RNG, and use it for the very first RNG_RandomUpdate
call in rng_init so that we initialize the RNG's XKEY with high quality
entropy. r=jpierre,relyea.
Modified Files:
Tag: NSS_3_11_BRANCH
os2_rand.c prng_fips1861.c secrng.h unix_rand.c win_rand.c
-rw-r--r-- | security/nss/lib/freebl/os2_rand.c | 9 | ||||
-rw-r--r-- | security/nss/lib/freebl/prng_fips1861.c | 28 | ||||
-rw-r--r-- | security/nss/lib/freebl/secrng.h | 18 | ||||
-rw-r--r-- | security/nss/lib/freebl/unix_rand.c | 33 | ||||
-rw-r--r-- | security/nss/lib/freebl/win_rand.c | 94 |
5 files changed, 175 insertions, 7 deletions
diff --git a/security/nss/lib/freebl/os2_rand.c b/security/nss/lib/freebl/os2_rand.c index 8138d30ae..467774b8b 100644 --- a/security/nss/lib/freebl/os2_rand.c +++ b/security/nss/lib/freebl/os2_rand.c @@ -37,7 +37,8 @@ #define INCL_DOS #define INCL_DOSERRORS #include <os2.h> -#include <secrng.h> +#include "secrng.h" +#include "prerror.h" #include <stdlib.h> #include <time.h> #include <stdio.h> @@ -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/security/nss/lib/freebl/prng_fips1861.c b/security/nss/lib/freebl/prng_fips1861.c index 734ae4d38..c06d32d07 100644 --- a/security/nss/lib/freebl/prng_fips1861.c +++ b/security/nss/lib/freebl/prng_fips1861.c @@ -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/security/nss/lib/freebl/secrng.h b/security/nss/lib/freebl/secrng.h index d3e97c927..036a3f71a 100644 --- a/security/nss/lib/freebl/secrng.h +++ b/security/nss/lib/freebl/secrng.h @@ -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/security/nss/lib/freebl/unix_rand.c b/security/nss/lib/freebl/unix_rand.c index a3afe5da9..883d2663e 100644 --- a/security/nss/lib/freebl/unix_rand.c +++ b/security/nss/lib/freebl/unix_rand.c @@ -43,8 +43,9 @@ #include <sys/time.h> #include <sys/wait.h> #include <sys/stat.h> -#include <assert.h> #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/security/nss/lib/freebl/win_rand.c b/security/nss/lib/freebl/win_rand.c index 20218b967..286ad3522 100644 --- a/security/nss/lib/freebl/win_rand.c +++ b/security/nss/lib/freebl/win_rand.c @@ -35,6 +35,7 @@ * ***** END LICENSE BLOCK ***** */ #include "secrng.h" +#include "secerr.h" #ifdef XP_WIN #include <windows.h> @@ -56,6 +57,7 @@ #endif #include "prio.h" +#include "prerror.h" static PRInt32 filesToRead; static DWORD totalFileBytes; @@ -545,4 +547,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 <wincrypt.h> 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 */ |