Home
Reading
Searching
Subscribe
Sponsors
Statistics
Posting
Contact
Spam
Lists
Links
About
Hosting
Filtering
Features Download
Marketing
Archives
FAQ
Blog
 
Gmane

From: Steffan Karger <steffan <at> karger.me>
Subject: [PATCHv2 5/5] Add server-side support for cipher negotiation
Newsgroups: gmane.network.openvpn.devel
Date: Wednesday 8th June 2016 18:39:01 UTC (over 2 years ago)
Pushes AES-256-GCM when a connection client advertises IV_NCP=2, and
supports serving connections to clients with different data channel
cipher configuration simultaneously.

v2:
 * Update manpage
 * Add Changes.rst entry

Signed-off-by: Steffan Karger 
---
 Changes.rst              | 11 +++++++++++
 doc/openvpn.8            |  4 ++++
 src/openvpn/init.c       |  5 +++--
 src/openvpn/push.c       | 25 ++++++++++++++++++++++---
 src/openvpn/ssl.c        | 23 +++++++++++++----------
 src/openvpn/ssl_common.h |  1 +
 6 files changed, 54 insertions(+), 15 deletions(-)

diff --git a/Changes.rst b/Changes.rst
index 1ac3c2b..eb6018f 100644
--- a/Changes.rst
+++ b/Changes.rst
@@ -51,6 +51,13 @@ AEAD (GCM) data channel cipher support
     bytes per packet for AES-128-GCM instead of 36 bytes per packet for
     AES-128-CBC + HMAC-SHA1).
 
+Cipher negotiation
+    Data channel ciphers are now by default negotiated.  If a client
advertises
+    support for Negotiable Crypto Parameters (NCP), the server will choose
a
+    cipher (by default AES-256-GCM) for the data channel, and tell the
client
+    to use that cipher.  Data channel cipher negotiation can be controlled
+    using --ncp-ciphers and --ncp-disable.
+
 
 User-visible Changes
 --------------------
@@ -106,6 +113,10 @@ User-visible Changes
 - mbed TLS builds: minimum RSA key size is now 2048 bits.  Shorter keys
will
   not be accepted, both local and from the peer.
 
+- Data channel cipher negotiation (see New features section) can override
+  ciphers configured in the config file.  Use --ncp-disable if you don't
want
+  that.
+
 
 Maintainer-visible changes
 --------------------------
diff --git a/doc/openvpn.8 b/doc/openvpn.8
index e349b77..5cb2885 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -4134,6 +4134,10 @@ Restrict the allowed ciphers to be negotiated to the
ciphers in
 .B cipher_list
 is a colon-separated list of ciphers, and defaults to
 "AES-256-GCM:AES-128-GCM".
+
+For servers, the first cipher from
+.B cipher_list
+will be pushed to clients that support cipher negotiation.
 .\"*********************************************************
 .TP
 .B \-\-ncp\-disable
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index c2e3b2e..5ed3f3c 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -2312,8 +2312,8 @@ do_init_crypto_tls (struct context *c, const unsigned
int flags)
   /* In short form, unique datagram identifier is 32 bits, in long form 64
bits */
   packet_id_long_form = cipher_kt_mode_ofb_cfb (c->c1.ks.key_type.cipher);
 
-  /* Compute MTU parameters (postpone if we pull options) */
-  if (c->options.pull)
+  /* Compute MTU parameters (postpone if we push/pull options) */
+  if (c->options.pull || c->options.mode == MODE_SERVER)
     {
       /* Account for worst-case crypto overhead before allocating buffers
*/
       frame_add_to_extra_frame (&c->c2.frame, crypto_max_overhead());
@@ -2357,6 +2357,7 @@ do_init_crypto_tls (struct context *c, const unsigned
int flags)
   to.renegotiate_packets = options->renegotiate_packets;
   to.renegotiate_seconds = options->renegotiate_seconds;
   to.single_session = options->single_session;
+  to.mode = options->mode;
   to.pull = options->pull;
 #ifdef ENABLE_PUSH_PEER_INFO
   if (options->push_peer_info)		/* all there is */
diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index 4239e3e..f763e65 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -245,13 +245,28 @@ incoming_push_message (struct context *c, const
struct buffer *buffer)
 	  if (!do_up (c, true, c->options.push_option_types_found))
 	    {
 	      msg (D_PUSH_ERRORS, "Failed to open tun/tap interface");
-	      register_signal (c, SIGUSR1, "do_up-failed");
-	      goto cleanup;
+	      goto error;
 	    }
 	}
       event_timeout_clear (&c->c2.push_request_interval);
     }
+  else if (status == PUSH_MSG_REQUEST)
+    {
+      if (c->options.mode == MODE_SERVER)
+	{
+	  struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE];
+	  if (!tls_session_update_crypto_params (session, &c->options,
+	      &c->c2.frame))
+	    {
+	      msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion
failed");
+	      goto error;
+	    }
+	}
+    }
 
+  goto cleanup;
+error:
+  register_signal (c, SIGUSR1, "process-push-msg-failed");
 cleanup:
   gc_free (&gc);
 }
@@ -303,12 +318,16 @@ prepare_push_reply (struct options *o, struct
tls_multi *tls_multi)
 
   /* Push cipher if client supports Negotiable Crypto Parameters */
   optstr = peer_info ? strstr(peer_info, "IV_NCP=") : NULL;
-  if (optstr)
+  if (optstr && o->ncp_enabled)
     {
       int ncp = 0;
       int r = sscanf(optstr, "IV_NCP=%d", &ncp);
       if ((r == 1) && (ncp == 2))
 	{
+	  /* Push the first cipher from --ncp-ciphers to the client.
+	   * TODO: actual negotiation, instead of server dictatorship. */
+	  char *push_cipher = string_alloc(o->ncp_ciphers, &o->gc);
+	  o->ciphername = strtok (push_cipher, ":");
 	  push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername);
 	}
     }
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index 7ced41d..d5b52d7 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -1661,10 +1661,10 @@ tls_session_update_crypto_params(struct tls_session
*session,
   bool ret = false;
   struct key_state *ks = &session->key[KS_PRIMARY];	/* primary key */
 
-  ASSERT (!session->opt->server);
   ASSERT (ks->authenticated);
 
-  if (0 != strcmp(options->ciphername, session->opt->config_ciphername) &&
+  if (!session->opt->server &&
+      0 != strcmp(options->ciphername, session->opt->config_ciphername) &&
       !item_in_list(options->ciphername, options->ncp_ciphers))
     {
       msg (D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s
or %s",
@@ -1691,12 +1691,13 @@ tls_session_update_crypto_params(struct tls_session
*session,
       options->ce.tun_mtu_defined, options->ce.tun_mtu);
   frame_print (frame, D_MTU_INFO, "Data Channel MTU parms");
 
+  const struct session_id *client_sid = session->opt->server ?
+      &ks->session_id_remote : &session->session_id;
+  const struct session_id *server_sid = !session->opt->server ?
+      &ks->session_id_remote : &session->session_id;
   if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi,
-			       &session->opt->key_type,
-			       ks->key_src,
-			       &session->session_id,
-			       &ks->session_id_remote,
-			       false))
+      &session->opt->key_type, ks->key_src, client_sid, server_sid,
+      session->opt->server))
     {
       msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion
failed");
       goto cleanup;
@@ -2057,10 +2058,12 @@ key_method_2_write (struct buffer *buf, struct
tls_session *session)
   if (!push_peer_info (buf, session))
     goto error;
 
-  /*
-   * generate tunnel keys if server
+  /* Generate tunnel keys if we're a TLS server.
+   * If we're a p2mp server, the first key generation is postponed until
after
+   * the pull/push, so we can process pushed cipher directives.
    */
-  if (session->opt->server)
+  if (session->opt->server &&
+      (session->opt->mode != MODE_SERVER || ks->key_id > 0))
     {
       if (ks->authenticated)
 	{
diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h
index 6bfde6b..eb2ad6f 100644
--- a/src/openvpn/ssl_common.h
+++ b/src/openvpn/ssl_common.h
@@ -236,6 +236,7 @@ struct tls_options
 #ifdef ENABLE_OCC
   bool disable_occ;
 #endif
+  int mode;
   bool pull;
 #ifdef ENABLE_PUSH_PEER_INFO
   int push_peer_info_detail;
-- 
2.7.4


------------------------------------------------------------------------------
What NetFlow Analyzer can do for you? Monitors network bandwidth and
traffic
patterns at an interface-level. Reveals which users, apps, and protocols
are 
consuming the most bandwidth. Provides multi-vendor support for NetFlow, 
J-Flow, sFlow and other flows. Make informed decisions using capacity 
planning reports. https://ad.doubleclick.net/ddm/clk/305295220;132659582;e
 
CD: 9ms