aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2008-11-18 01:25:05 +0000
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2008-11-18 01:25:05 +0000
commit03bfb228ffd95c37e135bb9a5a37160c247e28a9 (patch)
tree62fe17de8cce142be0749cf4a07509246b02f48b
parentVersion 2.1_rc14 (diff)
downloadopenvpn-03bfb228ffd95c37e135bb9a5a37160c247e28a9.tar.xz
Added --prng option to control PRNG (pseudo-random
number generator) parameters. In previous OpenVPN versions, the PRNG was hardcoded to use the SHA1 hash. Now any OpenSSL hash may be used. This is part of an effort to remove hardcoded references to a specific cipher or cryptographic hash algorithm. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@3503 e7ae566f-a301-0410-adde-c780ea21d3b5
-rw-r--r--crypto.c73
-rw-r--r--crypto.h5
-rw-r--r--errlevel.h2
-rw-r--r--init.c28
-rw-r--r--openvpn.815
-rw-r--r--options.c28
-rw-r--r--options.h2
-rw-r--r--ps.c2
-rw-r--r--version.m42
9 files changed, 136 insertions, 21 deletions
diff --git a/crypto.c b/crypto.c
index 7c2a9bb..d813f03 100644
--- a/crypto.c
+++ b/crypto.c
@@ -1640,6 +1640,7 @@ void uninit_crypto_lib ()
engine_initialized = false;
}
#endif
+ prng_uninit ();
}
/*
@@ -1649,33 +1650,73 @@ void uninit_crypto_lib ()
* IV values and a number of other miscellaneous tasks.
*/
-#define NONCE_SECRET_LEN 16
+static uint8_t *nonce_data; /* GLOBAL */
+static const EVP_MD *nonce_md = NULL; /* GLOBAL */
+static int nonce_secret_len; /* GLOBAL */
-static uint8_t nonce_data [SHA_DIGEST_LENGTH + NONCE_SECRET_LEN]; /* GLOBAL */
+void
+prng_init (const char *md_name, const int nonce_secret_len_parm)
+{
+ prng_uninit ();
+ nonce_md = md_name ? get_md (md_name) : NULL;
+ if (nonce_md)
+ {
+ ASSERT (nonce_secret_len_parm >= NONCE_SECRET_LEN_MIN && nonce_secret_len_parm <= NONCE_SECRET_LEN_MAX);
+ nonce_secret_len = nonce_secret_len_parm;
+ {
+ const int size = EVP_MD_size (nonce_md) + nonce_secret_len;
+ dmsg (D_CRYPTO_DEBUG, "PRNG init md=%s size=%d", EVP_MD_name (nonce_md), size);
+ nonce_data = (uint8_t*) malloc (size);
+ check_malloc_return (nonce_data);
+#if 1 /* Must be 1 for real usage */
+ if (!RAND_bytes (nonce_data, size))
+ msg (M_FATAL, "ERROR: Random number generator cannot obtain entropy for PRNG");
+#else
+ /* Only for testing -- will cause a predictable PRNG sequence */
+ {
+ int i;
+ for (i = 0; i < size; ++i)
+ nonce_data[i] = (uint8_t) i;
+ }
+#endif
+ }
+ }
+}
void
-prng_init (void)
+prng_uninit (void)
{
- if (!RAND_bytes (nonce_data, sizeof(nonce_data)))
- msg (M_FATAL, "ERROR: Random number generator cannot obtain entropy for PRNG");
+ free (nonce_data);
+ nonce_data = NULL;
+ nonce_md = NULL;
+ nonce_secret_len = 0;
}
void
prng_bytes (uint8_t *output, int len)
{
- SHA_CTX ctx;
- mutex_lock_static (L_PRNG);
- while (len > 0)
+ if (nonce_md)
{
- const int blen = min_int (len, SHA_DIGEST_LENGTH);
- SHA1_Init (&ctx);
- SHA1_Update (&ctx, nonce_data, sizeof (nonce_data));
- SHA1_Final (nonce_data, &ctx);
- memcpy (output, nonce_data, blen);
- output += blen;
- len -= blen;
+ EVP_MD_CTX ctx;
+ const int md_size = EVP_MD_size (nonce_md);
+ mutex_lock_static (L_PRNG);
+ while (len > 0)
+ {
+ unsigned int outlen = 0;
+ const int blen = min_int (len, md_size);
+ EVP_DigestInit (&ctx, nonce_md);
+ EVP_DigestUpdate (&ctx, nonce_data, md_size + nonce_secret_len);
+ EVP_DigestFinal (&ctx, nonce_data, &outlen);
+ ASSERT (outlen == md_size);
+ EVP_MD_CTX_cleanup (&ctx);
+ memcpy (output, nonce_data, blen);
+ output += blen;
+ len -= blen;
+ }
+ mutex_unlock_static (L_PRNG);
}
- mutex_unlock_static (L_PRNG);
+ else
+ RAND_bytes (output, len);
}
/* an analogue to the random() function, but use prng_bytes */
diff --git a/crypto.h b/crypto.h
index 448e8ad..9a677d0 100644
--- a/crypto.h
+++ b/crypto.h
@@ -329,8 +329,11 @@ void crypto_adjust_frame_parameters(struct frame *frame,
bool packet_id,
bool packet_id_long_form);
-void prng_init (void);
+#define NONCE_SECRET_LEN_MIN 16
+#define NONCE_SECRET_LEN_MAX 64
+void prng_init (const char *md_name, const int nonce_secret_len_parm);
void prng_bytes (uint8_t *output, int len);
+void prng_uninit ();
void test_crypto (const struct crypto_options *co, struct frame* f);
diff --git a/errlevel.h b/errlevel.h
index fc05fe6..2c27af4 100644
--- a/errlevel.h
+++ b/errlevel.h
@@ -140,6 +140,7 @@
#define D_AUTO_USERID LOGLEV(7, 70, M_DEBUG) /* AUTO_USERID debugging */
#define D_TLS_KEYSELECT LOGLEV(7, 70, M_DEBUG) /* show information on key selection for data channel */
#define D_ARGV_PARSE_CMD LOGLEV(7, 70, M_DEBUG) /* show parse_line() errors in argv_printf %sc */
+#define D_CRYPTO_DEBUG LOGLEV(7, 70, M_DEBUG) /* show detailed info from crypto.c routines */
#define D_PF_DROPPED_BCAST LOGLEV(7, 71, M_DEBUG) /* packet filter dropped a broadcast packet */
#define D_PF_DEBUG LOGLEV(7, 72, M_DEBUG) /* packet filter debugging, must also define PF_DEBUG in pf.h */
@@ -153,7 +154,6 @@
#define D_MULTI_TCP LOGLEV(8, 70, M_DEBUG) /* show debug info from mtcp.c */
#define D_TLS_DEBUG LOGLEV(9, 70, M_DEBUG) /* show detailed info from TLS routines */
-#define D_CRYPTO_DEBUG LOGLEV(9, 70, M_DEBUG) /* show detailed info from crypto.c routines */
#define D_COMP LOGLEV(9, 70, M_DEBUG) /* show compression info */
#define D_READ_WRITE LOGLEV(9, 70, M_DEBUG) /* show all tun/tcp/udp reads/writes/opens */
#define D_PACKET_CONTENT LOGLEV(9, 70, M_DEBUG) /* show before/after encryption packet content */
diff --git a/init.c b/init.c
index 455712a..903fda4 100644
--- a/init.c
+++ b/init.c
@@ -401,7 +401,7 @@ init_static (void)
/* init PRNG used for IV generation */
/* When forking, copy this to more places in the code to avoid fork
random-state predictability */
- prng_init ();
+ prng_init (NULL, 0);
#endif
#ifdef PID_TEST
@@ -473,6 +473,29 @@ init_static (void)
}
#endif
+#ifdef PRNG_TEST
+ {
+ struct gc_arena gc = gc_new ();
+ uint8_t rndbuf[8];
+ int i;
+ prng_init ("sha1", 16);
+ //prng_init (NULL, 0);
+ const int factor = 1;
+ for (i = 0; i < factor * 8; ++i)
+ {
+#if 1
+ prng_bytes (rndbuf, sizeof (rndbuf));
+#else
+ ASSERT(RAND_bytes (rndbuf, sizeof (rndbuf)));
+#endif
+ printf ("[%d] %s\n", i, format_hex (rndbuf, sizeof (rndbuf), 0, &gc));
+ }
+ gc_free (&gc);
+ prng_uninit ();
+ return false;
+ }
+#endif
+
return true;
}
@@ -1634,6 +1657,9 @@ do_init_crypto_tls_c1 (struct context *c)
options->ciphername_defined, options->authname,
options->authname_defined, options->keysize, true, true);
+ /* Initialize PRNG with config-specified digest */
+ prng_init (options->prng_hash, options->prng_nonce_secret_len);
+
/* TLS handshake authentication (--tls-auth) */
if (options->tls_auth_file)
{
diff --git a/openvpn.8 b/openvpn.8
index c45f839..bbec354 100644
--- a/openvpn.8
+++ b/openvpn.8
@@ -3616,6 +3616,21 @@ larger key may offer no real guarantee of greater
security, or may even reduce security.
.\"*********************************************************
.TP
+.B --prng alg [nsl]
+(Advanced) For PRNG (Pseudo-random number generator),
+use digest algorithm
+.B alg
+(default=sha1), and set
+.B nsl
+(default=16)
+to the size in bytes of the nonce secret length (between 16 and 64).
+
+Set
+.B alg=none
+to disable the PRNG and use the OpenSSL RAND_bytes function
+instead for all of OpenVPN's pseudo-random number needs.
+.\"*********************************************************
+.TP
.B --engine [engine-name]
Enable OpenSSL hardware-based crypto engine functionality.
diff --git a/options.c b/options.c
index 50f6982..5a78c70 100644
--- a/options.c
+++ b/options.c
@@ -442,6 +442,8 @@ static const char usage_message[] =
"--cipher alg : Encrypt packets with cipher algorithm alg\n"
" (default=%s).\n"
" Set alg=none to disable encryption.\n"
+ "--prng alg [nsl] : For PRNG, use digest algorithm alg, and\n"
+ " nonce_secret_len=nsl. Set alg=none to disable PRNG.\n"
#ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH
"--keysize n : Size of cipher key in bits (optional).\n"
" If unspecified, defaults to cipher-specific default.\n"
@@ -717,6 +719,8 @@ init_options (struct options *o, const bool init_gc)
o->ciphername_defined = true;
o->authname = "SHA1";
o->authname_defined = true;
+ o->prng_hash = "SHA1";
+ o->prng_nonce_secret_len = 16;
o->replay = true;
o->replay_window = DEFAULT_SEQ_BACKTRACK;
o->replay_time = DEFAULT_TIME_BACKTRACK;
@@ -1272,6 +1276,8 @@ show_settings (const struct options *o)
SHOW_STR (ciphername);
SHOW_BOOL (authname_defined);
SHOW_STR (authname);
+ SHOW_STR (prng_hash);
+ SHOW_INT (prng_nonce_secret_len);
SHOW_INT (keysize);
SHOW_BOOL (engine);
SHOW_BOOL (replay);
@@ -5158,6 +5164,28 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_CRYPTO);
options->ciphername_defined = true;
}
+ else if (streq (p[0], "prng") && p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_CRYPTO);
+ if (streq (p[1], "none"))
+ options->prng_hash = NULL;
+ else
+ options->prng_hash = p[1];
+ if (p[2])
+ {
+ const int sl = atoi (p[2]);
+ if (sl >= NONCE_SECRET_LEN_MIN && sl <= NONCE_SECRET_LEN_MAX)
+ {
+ options->prng_nonce_secret_len = sl;
+ }
+ else
+ {
+ msg (msglevel, "prng parameter nonce_secret_len must be between %d and %d",
+ NONCE_SECRET_LEN_MIN, NONCE_SECRET_LEN_MAX);
+ goto err;
+ }
+ }
+ }
else if (streq (p[0], "no-replay"))
{
VERIFY_PERMISSION (OPT_P_CRYPTO);
diff --git a/options.h b/options.h
index c6d4e47..7ea4191 100644
--- a/options.h
+++ b/options.h
@@ -418,6 +418,8 @@ struct options
bool authname_defined;
const char *authname;
int keysize;
+ const char *prng_hash;
+ int prng_nonce_secret_len;
const char *engine;
bool replay;
bool mute_replay_warnings;
diff --git a/ps.c b/ps.c
index 2268b72..f4290a5 100644
--- a/ps.c
+++ b/ps.c
@@ -793,7 +793,7 @@ port_share_open (const char *host, const int port)
set_nonblock (fd[1]);
/* initialize prng */
- prng_init ();
+ prng_init (NULL, 0);
/* execute the event loop */
port_share_proxy (hostaddr, port, fd[1]);
diff --git a/version.m4 b/version.m4
index c230d71..c224b6f 100644
--- a/version.m4
+++ b/version.m4
@@ -1,5 +1,5 @@
dnl define the OpenVPN version
-define(PRODUCT_VERSION,[2.1_rc14])
+define(PRODUCT_VERSION,[2.1_rc14a])
dnl define the TAP version
define(PRODUCT_TAP_ID,[tap0901])
define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])