diff options
-rw-r--r-- | crypto.c | 73 | ||||
-rw-r--r-- | crypto.h | 5 | ||||
-rw-r--r-- | errlevel.h | 2 | ||||
-rw-r--r-- | init.c | 28 | ||||
-rw-r--r-- | openvpn.8 | 15 | ||||
-rw-r--r-- | options.c | 28 | ||||
-rw-r--r-- | options.h | 2 | ||||
-rw-r--r-- | ps.c | 2 | ||||
-rw-r--r-- | version.m4 | 2 |
9 files changed, 136 insertions, 21 deletions
@@ -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 */ @@ -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); @@ -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 */ @@ -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) { @@ -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. @@ -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); @@ -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; @@ -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]); @@ -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]) |