summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrcritten <>2005-10-03 14:59:26 +0000
committerrcritten <>2005-10-03 14:59:26 +0000
commit252fddba6cd7431db7cbd8a677bb52860ef5ba0a (patch)
tree61870bc9bc6ff42f336a757fcffc4767627bd4b2
parent98c66d1255fdb2fc60defa96a8eeaa7085c6f467 (diff)
downloadmod_nss-252fddba6cd7431db7cbd8a677bb52860ef5ba0a.tar.gz
mod_nss-252fddba6cd7431db7cbd8a677bb52860ef5ba0a.tar.xz
mod_nss-252fddba6cd7431db7cbd8a677bb52860ef5ba0a.zip
Add support for seeding the NSS Random Number Generator. This adds
a new directive, NSSRandomSeed based on the mod_ssl SSLRandomSeed directive.
-rw-r--r--Makefile.am2
-rw-r--r--Makefile.in6
-rw-r--r--docs/mod_nss.html30
-rw-r--r--mod_nss.c3
-rw-r--r--mod_nss.h23
-rw-r--r--nss.conf.in14
-rw-r--r--nss_engine_config.c89
-rw-r--r--nss_engine_init.c10
-rw-r--r--nss_engine_rand.c151
9 files changed, 322 insertions, 6 deletions
diff --git a/Makefile.am b/Makefile.am
index cfd6c2b..06486dc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,7 +6,7 @@ bin_PROGRAMS = nss_pcache
nss_pcache_SOURCES = nss_pcache.c
## Define the source file for the module
-libmodnss_la_SOURCES = mod_nss.c nss_engine_config.c nss_engine_init.c nss_engine_io.c nss_engine_kernel.c nss_engine_log.c nss_engine_pphrase.c nss_engine_vars.c nss_expr.c nss_expr_eval.c nss_expr_parse.y nss_expr_scan.l nss_util.c
+libmodnss_la_SOURCES = mod_nss.c nss_engine_config.c nss_engine_init.c nss_engine_io.c nss_engine_kernel.c nss_engine_log.c nss_engine_pphrase.c nss_engine_vars.c nss_expr.c nss_expr_eval.c nss_expr_parse.y nss_expr_scan.l nss_util.c nss_engine_rand.c
## Set the includes and libraries needed
INCLUDES = -I@apache_inc@ @nspr_inc@ @nss_inc@ @apr_inc@
diff --git a/Makefile.in b/Makefile.in
index 9a61632..c57d232 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -107,7 +107,7 @@ bin_PROGRAMS = nss_pcache
nss_pcache_SOURCES = nss_pcache.c
-libmodnss_la_SOURCES = mod_nss.c nss_engine_config.c nss_engine_init.c nss_engine_io.c nss_engine_kernel.c nss_engine_log.c nss_engine_pphrase.c nss_engine_vars.c nss_expr.c nss_expr_eval.c nss_expr_parse.y nss_expr_scan.l nss_util.c
+libmodnss_la_SOURCES = mod_nss.c nss_engine_config.c nss_engine_init.c nss_engine_io.c nss_engine_kernel.c nss_engine_log.c nss_engine_pphrase.c nss_engine_vars.c nss_expr.c nss_expr_eval.c nss_expr_parse.y nss_expr_scan.l nss_util.c nss_engine_rand.c
INCLUDES = -I@apache_inc@ @nspr_inc@ @nss_inc@ @apr_inc@
LIBS = @nspr_lib@ @nss_lib@ -lssl3 -lsmime3 -lnss3 -lsoftokn3 -lplc4 -lplds4 -lnspr4
@@ -133,7 +133,7 @@ am_libmodnss_la_OBJECTS = mod_nss.lo nss_engine_config.lo \
nss_engine_init.lo nss_engine_io.lo nss_engine_kernel.lo \
nss_engine_log.lo nss_engine_pphrase.lo nss_engine_vars.lo \
nss_expr.lo nss_expr_eval.lo nss_expr_parse.lo nss_expr_scan.lo \
- nss_util.lo
+ nss_util.lo nss_engine_rand.lo
libmodnss_la_OBJECTS = $(am_libmodnss_la_OBJECTS)
bin_PROGRAMS = nss_pcache$(EXEEXT)
PROGRAMS = $(bin_PROGRAMS)
@@ -157,6 +157,7 @@ am__depfiles_maybe = depfiles
@AMDEP_TRUE@ ./$(DEPDIR)/nss_engine_kernel.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/nss_engine_log.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/nss_engine_pphrase.Plo \
+@AMDEP_TRUE@ ./$(DEPDIR)/nss_engine_rand.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/nss_engine_vars.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/nss_expr.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/nss_expr_eval.Plo \
@@ -256,6 +257,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nss_engine_kernel.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nss_engine_log.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nss_engine_pphrase.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nss_engine_rand.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nss_engine_vars.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nss_expr.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nss_expr_eval.Plo@am__quote@
diff --git a/docs/mod_nss.html b/docs/mod_nss.html
index 7d6f5f1..71d1ada 100644
--- a/docs/mod_nss.html
+++ b/docs/mod_nss.html
@@ -249,7 +249,6 @@ to verify that the migration was successful.<br>
<h1><a name="Directives"></a>Configuration Directives</h1>
The following mod_ssl Directives are not applicable to mod_nss:<br>
<ul>
- <li>SSLRandomSeed</li>
<li>SSLSessionCache</li>
<li>SSLMutex</li>
<li>SSLCertificateChainFile</li>
@@ -371,6 +370,35 @@ The default value is 86400 (24 hours).<br>
<br>
<code>NSSSession3CacheTimeout 86400</code><br>
<br>
+<big><big>NSSRandomSeed</big></big><br>
+<br>
+Configures sources to seed the NSS Random Number Generator (RNG) at
+startup.&nbsp; Currently this only supports seeding the RNG at startup.
+<br>
+<br>
+The following sources are available:<br>
+<ul>
+ <li><code>builtin:</code> Combines the current system time, the
+current process id
+and a randomly choosen 128-byte extract of the process stack. This is
+not a particularly strong source of entropy.</li>
+ <li><code>file:/path/to/source:</code> Reads from the specified file.
+If the number of bytes to read is specified it just reads that amount.
+Be aware that some operating systems block on /dev/random if not enough
+entropy is available. This means that the server will wait until that
+data is available to continue startup. These systems generally offer a
+non-blocking device as well, /dev/urandom.</li>
+ <li><code>exec:/path/to/program: Executes the given program and takes
+the stdout of it as the entryop. If the bytes argument is included it
+reads that many bytes, otherwise it reads until the program exits.</code><br>
+ </li>
+</ul>
+<span style="font-weight: bold;">Example</span><br>
+<br>
+<code>NSSRandomSeed startup builtin<br>
+NSSRandomSeed startup /dev/urandom 512<br>
+NSSRandomSeed startup /usr/bin/makerandom</code><br>
+<br>
<big><big>NSSEngine</big></big><br>
<br>
Enables or disables the SSL protocol. This is usually used within a
diff --git a/mod_nss.c b/mod_nss.c
index 2dd2f3c..b1f8721 100644
--- a/mod_nss.c
+++ b/mod_nss.c
@@ -63,6 +63,9 @@ static const command_rec nss_config_cmds[] = {
SSL_CMD_SRV(OCSP, FLAG,
"OCSP (Online Certificate Status Protocol)"
"(`on', `off')")
+ SSL_CMD_SRV(RandomSeed, TAKE23,
+ "SSL Pseudo Random Number Generator (PRNG) seeding source "
+ "(`startup builtin|file:/path|exec:/path [bytes]')")
/*
* Per-server context configuration directives
diff --git a/mod_nss.h b/mod_nss.h
index a2a4bef..029ce41 100644
--- a/mod_nss.h
+++ b/mod_nss.h
@@ -163,6 +163,26 @@ typedef struct {
} nss_require_t;
/*
+ * Define the SSL random number generator seeding source. The CONNECT
+ * method is not currently used.
+ */
+typedef enum {
+ SSL_RSCTX_STARTUP = 1,
+ SSL_RSCTX_CONNECT = 2
+} ssl_rsctx_t;
+typedef enum {
+ SSL_RSSRC_BUILTIN = 1,
+ SSL_RSSRC_FILE = 2,
+ SSL_RSSRC_EXEC = 3
+} ssl_rssrc_t;
+typedef struct {
+ ssl_rsctx_t nCtx;
+ ssl_rssrc_t nSrc;
+ char *cpPath;
+ int nBytes;
+} ssl_randseed_t;
+
+/*
* Define the SSL verify levels
*/
typedef enum {
@@ -217,6 +237,8 @@ typedef struct {
apr_proc_t proc;
apr_procattr_t *procattr;
+ apr_array_header_t *aRandSeed;
+
struct {
void *pV1, *pV2, *pV3, *pV4, *pV5, *pV6, *pV7, *pV8, *pV9, *pV10;
} rCtx;
@@ -328,6 +350,7 @@ const char *nss_cmd_NSSSession3CacheTimeout(cmd_parms *cmd, void *dcfg, const ch
const char *nss_cmd_NSSSessionCacheSize(cmd_parms *cmd, void *dcfg, const char *arg);
const char *nss_cmd_NSSPassPhraseDialog(cmd_parms *cmd, void *dcfg, const char *arg);
const char *nss_cmd_NSSPassPhraseHelper(cmd_parms *cmd, void *dcfg, const char *arg);
+const char *nss_cmd_NSSRandomSeed(cmd_parms *, void *, const char *, const char *, const char *);
const char *nss_cmd_NSSUserName(cmd_parms *cmd, void *dcfg, const char *arg);
const char *nss_cmd_NSSOptions(cmd_parms *, void *, const char *);
const char *nss_cmd_NSSRequireSSL(cmd_parms *cmd, void *dcfg);
diff --git a/nss.conf.in b/nss.conf.in
index db9fe3e..88787a7 100644
--- a/nss.conf.in
+++ b/nss.conf.in
@@ -50,6 +50,20 @@ NSSSessionCacheSize 10000
NSSSessionCacheTimeout 100
NSSSession3CacheTimeout 86400
+#
+# Pseudo Random Number Generator (PRNG):
+# Configure one or more sources to seed the PRNG of the SSL library.
+# The seed data should be of good random quality.
+# WARNING! On some platforms /dev/random blocks if not enough entropy
+# is available. Those platforms usually also provide a non-blocking
+# device, /dev/urandom, which may be used instead.
+#
+# This does not support seeding the RNG with each connection.
+
+NSSRandomSeed startup builtin
+#NSSRandomSeed startup file:/dev/random 512
+#NSSRandomSeed startup file:/dev/urandom 512
+
##
## SSL Virtual Host Context
##
diff --git a/nss_engine_config.c b/nss_engine_config.c
index a13cdab..bd067c3 100644
--- a/nss_engine_config.c
+++ b/nss_engine_config.c
@@ -51,6 +51,8 @@ SSLModConfigRec *nss_config_global_create(server_rec *s)
mc->ssl3_session_cache_timeout = UNSET;
mc->pphrase_dialog_helper = NULL;
mc->pphrase_dialog_path = NULL;
+ mc->aRandSeed = apr_array_make(pool, 4,
+ sizeof(ssl_randseed_t));
apr_pool_userdata_set(mc, SSL_MOD_CONFIG_KEY,
apr_pool_cleanup_null,
@@ -561,6 +563,93 @@ const char *nss_cmd_NSSPassPhraseHelper(cmd_parms *cmd,
return NULL;
}
+const char *nss_cmd_NSSRandomSeed(cmd_parms *cmd,
+ void *dcfg,
+ const char *arg1,
+ const char *arg2,
+ const char *arg3)
+{
+ SSLModConfigRec *mc = myModConfig(cmd->server);
+ const char *err;
+ ssl_randseed_t *seed;
+ int arg2len = strlen(arg2);
+
+ if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+ return err;
+ }
+
+ /* Only run through this once. Otherwise the random seed sources are
+ * pushed into the array for each server start (and we are guaranteed 2) */
+ if (mc->nInitCount >= 1) {
+ return NULL;
+ }
+
+ seed = apr_array_push(mc->aRandSeed);
+
+ if (strcEQ(arg1, "startup")) {
+ seed->nCtx = SSL_RSCTX_STARTUP;
+ }
+ else if (strcEQ(arg1, "connect")) {
+ return apr_pstrcat(cmd->pool, "NSSRandomSeed: "
+ "mod_nss doesn't do per-connection random seeding",
+ NULL);
+ }
+ else {
+ return apr_pstrcat(cmd->pool, "NSSRandomSeed: "
+ "invalid context: `", arg1, "'",
+ NULL);
+ }
+
+ if ((arg2len > 5) && strEQn(arg2, "file:", 5)) {
+ seed->nSrc = SSL_RSSRC_FILE;
+ seed->cpPath = ap_server_root_relative(mc->pPool, arg2+5);
+ }
+ else if ((arg2len > 5) && strEQn(arg2, "exec:", 5)) {
+ seed->nSrc = SSL_RSSRC_EXEC;
+ seed->cpPath = ap_server_root_relative(mc->pPool, arg2+5);
+ }
+ else if (strcEQ(arg2, "builtin")) {
+ seed->nSrc = SSL_RSSRC_BUILTIN;
+ seed->cpPath = NULL;
+ }
+ else {
+ seed->nSrc = SSL_RSSRC_FILE;
+ seed->cpPath = ap_server_root_relative(mc->pPool, arg2);
+ }
+
+ if (seed->nSrc != SSL_RSSRC_BUILTIN) {
+ apr_finfo_t finfo;
+ if (!seed->cpPath) {
+ return apr_pstrcat(cmd->pool,
+ "Invalid NSSRandomSeed path ",
+ arg2, NULL);
+ }
+ if (apr_stat(&finfo, seed->cpPath, APR_FINFO_TYPE|APR_FINFO_SIZE, cmd->pool) != 0) {
+ return apr_pstrcat(cmd->pool,
+ "NSSRandomSeed: source path '",
+ seed->cpPath, "' does not exist", NULL);
+ }
+ }
+
+ if (!arg3) {
+ seed->nBytes = 0; /* read whole file */
+ }
+ else {
+ if (seed->nSrc == SSL_RSSRC_BUILTIN) {
+ return "NSSRandomSeed: byte specification not "
+ "allowed for builtin seed source";
+ }
+
+ seed->nBytes = atoi(arg3);
+
+ if (seed->nBytes < 0) {
+ return "NSSRandomSeed: invalid number of bytes specified";
+ }
+ }
+
+ return NULL;
+}
+
const char *nss_cmd_NSSUserName(cmd_parms *cmd, void *dcfg,
const char *arg)
{
diff --git a/nss_engine_init.c b/nss_engine_init.c
index 7eda971..a9ae8d0 100644
--- a/nss_engine_init.c
+++ b/nss_engine_init.c
@@ -348,8 +348,14 @@ int nss_init_Module(apr_pool_t *p, apr_pool_t *plog,
/* Load our layer */
nss_io_layer_init();
- ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
- "done layer");
+
+ /*
+ * Seed the Pseudo Random Number Generator (PRNG)
+ * only need ptemp here; nothing inside allocated from the pool
+ * needs to live once we return from nss_rand_seed().
+ */
+ if (mc->nInitCount > 1)
+ nss_rand_seed(base_server, ptemp, SSL_RSCTX_STARTUP, "Init: ");
/*
* initialize servers
diff --git a/nss_engine_rand.c b/nss_engine_rand.c
new file mode 100644
index 0000000..cf0b66c
--- /dev/null
+++ b/nss_engine_rand.c
@@ -0,0 +1,151 @@
+/* Copyright 2001-2005 The Apache Software Foundation or its licensors, as
+ * applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mod_nss.h"
+
+/* _________________________________________________________________
+**
+** Support for better seeding of SSL library's RNG
+** _________________________________________________________________
+*/
+
+static int nss_rand_choosenum(int, int);
+static int nss_rand_feedfp(apr_pool_t *, apr_file_t *, int);
+
+int nss_rand_seed(server_rec *s, apr_pool_t *p, ssl_rsctx_t nCtx, char *prefix)
+{
+ SSLModConfigRec *mc;
+ apr_array_header_t *apRandSeed;
+ ssl_randseed_t *pRandSeeds;
+ ssl_randseed_t *pRandSeed;
+ unsigned char stackdata[256];
+ int nReq, nDone;
+ apr_file_t *fp;
+ int i, n, l;
+
+ mc = myModConfig(s);
+ nReq = 0;
+ nDone = 0;
+ apRandSeed = mc->aRandSeed;
+ pRandSeeds = (ssl_randseed_t *)apRandSeed->elts;
+ for (i = 0; i < apRandSeed->nelts; i++) {
+ pRandSeed = &pRandSeeds[i];
+ if (pRandSeed->nCtx == nCtx) {
+ nReq += pRandSeed->nBytes;
+ if (pRandSeed->nSrc == SSL_RSSRC_FILE) {
+ /*
+ * seed in contents of an external file
+ */
+ if (apr_file_open(&fp, pRandSeed->cpPath,
+ APR_READ, APR_OS_DEFAULT, p) != APR_SUCCESS)
+ continue;
+ nDone += nss_rand_feedfp(p, fp, pRandSeed->nBytes);
+ apr_file_close(fp);
+ }
+ else if (pRandSeed->nSrc == SSL_RSSRC_EXEC) {
+ const char *cmd = pRandSeed->cpPath;
+ const char **argv = apr_palloc(p, sizeof(char *) * 3);
+ /*
+ * seed in contents generated by an external program
+ */
+ argv[0] = cmd;
+ argv[1] = apr_itoa(p, pRandSeed->nBytes);
+ argv[2] = NULL;
+
+ if ((fp = nss_util_ppopen(s, p, cmd, argv)) == NULL)
+ continue;
+ nDone += nss_rand_feedfp(p, fp, pRandSeed->nBytes);
+ nss_util_ppclose(s, p, fp);
+ }
+ else if (pRandSeed->nSrc == SSL_RSSRC_BUILTIN) {
+ struct {
+ time_t t;
+ pid_t pid;
+ } my_seed;
+
+ /*
+ * seed in the current time (usually just 4 bytes)
+ */
+ my_seed.t = time(NULL);
+
+ /*
+ * seed in the current process id (usually just 4 bytes)
+ */
+ my_seed.pid = mc->pid;
+
+ l = sizeof(my_seed);
+ PK11_RandomUpdate((unsigned char *)&my_seed, l);
+ nDone += l;
+
+ /*
+ * seed in some current state of the run-time stack (128 bytes)
+ */
+ n = nss_rand_choosenum(0, sizeof(stackdata)-128-1);
+ PK11_RandomUpdate(stackdata+n, 128);
+ nDone += 128;
+
+ }
+ }
+ }
+ if (nDone > 0)
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
+ "%sSeeding PRNG with %d bytes of entropy", prefix, nDone);
+
+ return nDone;
+}
+
+#define BUFSIZE 8192
+
+static int nss_rand_feedfp(apr_pool_t *p, apr_file_t *fp, int nReq)
+{
+ apr_size_t nDone;
+ unsigned char caBuf[BUFSIZE];
+ apr_size_t nBuf;
+ apr_size_t nRead;
+ apr_size_t nTodo;
+
+ nDone = 0;
+ nRead = BUFSIZE;
+ nTodo = nReq;
+ while (1) {
+ if (nReq > 0)
+ nRead = (nTodo < BUFSIZE ? nTodo : BUFSIZE);
+ nBuf = nRead;
+ if (apr_file_read(fp, caBuf, &nBuf) != APR_SUCCESS)
+ break;
+ PK11_RandomUpdate(caBuf, nBuf);
+ nDone += nBuf;
+ if (nReq > 0) {
+ nTodo -= nBuf;
+ if (nTodo <= 0)
+ break;
+ }
+ }
+ return nDone;
+}
+
+static int nss_rand_choosenum(int l, int h)
+{
+ int i;
+ char buf[50];
+
+ apr_snprintf(buf, sizeof(buf), "%.0f",
+ (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l)));
+ i = atoi(buf)+1;
+ if (i < l) i = l;
+ if (i > h) i = h;
+ return i;
+}