summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwtchang%redhat.com <devnull@localhost>2006-10-12 02:18:38 +0000
committerwtchang%redhat.com <devnull@localhost>2006-10-12 02:18:38 +0000
commita17d2794b63e4f34072e6f6daac33a6e9674e911 (patch)
treef785b2c125384b5473e032df2808ff6e0a79e672
parente08628135f8f10b276b326135a657158b03902c7 (diff)
downloadnss-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.c9
-rw-r--r--security/nss/lib/freebl/prng_fips1861.c28
-rw-r--r--security/nss/lib/freebl/secrng.h18
-rw-r--r--security/nss/lib/freebl/unix_rand.c33
-rw-r--r--security/nss/lib/freebl/win_rand.c94
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 */