diff options
author | rcritten <> | 2005-10-03 14:59:26 +0000 |
---|---|---|
committer | rcritten <> | 2005-10-03 14:59:26 +0000 |
commit | 252fddba6cd7431db7cbd8a677bb52860ef5ba0a (patch) | |
tree | 61870bc9bc6ff42f336a757fcffc4767627bd4b2 | |
parent | 98c66d1255fdb2fc60defa96a8eeaa7085c6f467 (diff) | |
download | mod_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.am | 2 | ||||
-rw-r--r-- | Makefile.in | 6 | ||||
-rw-r--r-- | docs/mod_nss.html | 30 | ||||
-rw-r--r-- | mod_nss.c | 3 | ||||
-rw-r--r-- | mod_nss.h | 23 | ||||
-rw-r--r-- | nss.conf.in | 14 | ||||
-rw-r--r-- | nss_engine_config.c | 89 | ||||
-rw-r--r-- | nss_engine_init.c | 10 | ||||
-rw-r--r-- | nss_engine_rand.c | 151 |
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. 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 @@ -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 @@ -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; +} |