]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Added --prng option to control PRNG (pseudo-random
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Tue, 18 Nov 2008 01:25:05 +0000 (01:25 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Tue, 18 Nov 2008 01:25:05 +0000 (01:25 +0000)
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

crypto.c
crypto.h
errlevel.h
init.c
openvpn.8
options.c
options.h
ps.c
version.m4

index 7c2a9bbaffac5af69d2241271a0bc063ca101333..d813f031d170027b58e9b31d6fc2b887156bbae5 100644 (file)
--- 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 */
index 448e8ad8ffc5a96ecf0615c13b2bab35bb4104a4..9a677d0fc6b7e1a8cb72fcc2cfcee40d52e6d364 100644 (file)
--- 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);
 
index fc05fe63476cbc0c977b65e162cdea16c19882a9..2c27af4eb6ba328860cacab26b3eb088d54dbed2 100644 (file)
 #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 */
 
 #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 455712a772d2732d32bb7df7f4d57fe0847850de..903fda46a9aaa602e93cedfe9e94dd6d4390b704 100644 (file)
--- 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)
        {
index c45f83962dc6fb961486bff0eb554a76870c92d2..bbec35433d3d0ba07b35c63fffe5c809ebd902fd 100644 (file)
--- 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.
 
index 50f69821dee82ce7a2e1c4c93c8ca1ee615f9d23..5a78c705d571f9730adc330137e41b387140cf29 100644 (file)
--- 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);
index c6d4e470f292f539e0964556d5486424cc627fc3..7ea4191ffe93577b7eac5826486204cb10caaf4f 100644 (file)
--- 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 2268b72bbd893b6d477bce3333004d3b2f086d1a..f4290a53ca814346da556abc235c9203656d6bc9 100644 (file)
--- 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]);
index c230d71e410eab61948f5cbab54d00e6e90720b0..c224b6f87ef1d9de04f2ec0305df55ca2ea939a1 100644 (file)
@@ -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])