aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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])