Browse code

Add server-side support for cipher negotiation

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

v3:
* Do not regenerate keys if the client sends a second pull request
* Don't postpone key generation if client has no IV_NCP support

v4:
* rebase on client-side NCP v4

Signed-off-by: Steffan Karger <steffan@karger.me>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <1467149771-10374-1-git-send-email-steffan@karger.me>
URL: http://article.gmane.org/gmane.network.openvpn.devel/12009
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Steffan Karger authored on 2016/06/29 06:36:11
Showing 7 changed files
... ...
@@ -55,6 +55,13 @@ Http proxy password inside config file
55 55
 	Http proxy passwords can be specified with the inline file option
56 56
     http-proxy-user-pass
57 57
 
58
+Cipher negotiation
59
+    Data channel ciphers are now by default negotiated.  If a client advertises
60
+    support for Negotiable Crypto Parameters (NCP), the server will choose a
61
+    cipher (by default AES-256-GCM) for the data channel, and tell the client
62
+    to use that cipher.  Data channel cipher negotiation can be controlled
63
+    using --ncp-ciphers and --ncp-disable.
64
+
58 65
 
59 66
 User-visible Changes
60 67
 --------------------
... ...
@@ -124,6 +131,11 @@ User-visible Changes
124 124
   time in seconds to wait between reconnection attempts when an exponential
125 125
   backoff is triggered due to repeated retries. Default = 300 seconds.
126 126
 
127
+- Data channel cipher negotiation (see New features section) can override
128
+  ciphers configured in the config file.  Use --ncp-disable if you don't want
129
+  that.
130
+
131
+
127 132
 Maintainer-visible changes
128 133
 --------------------------
129 134
 - OpenVPN no longer supports building with crypto support, but without TLS
... ...
@@ -4137,6 +4137,10 @@ Restrict the allowed ciphers to be negotiated to the ciphers in
4137 4137
 .B cipher_list
4138 4138
 is a colon-separated list of ciphers, and defaults to
4139 4139
 "AES-256-GCM:AES-128-GCM".
4140
+
4141
+For servers, the first cipher from
4142
+.B cipher_list
4143
+will be pushed to clients that support cipher negotiation.
4140 4144
 .\"*********************************************************
4141 4145
 .TP
4142 4146
 .B \-\-ncp\-disable
... ...
@@ -2330,8 +2330,8 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
2330 2330
   /* In short form, unique datagram identifier is 32 bits, in long form 64 bits */
2331 2331
   packet_id_long_form = cipher_kt_mode_ofb_cfb (c->c1.ks.key_type.cipher);
2332 2332
 
2333
-  /* Compute MTU parameters (postpone if we pull options) */
2334
-  if (c->options.pull)
2333
+  /* Compute MTU parameters (postpone if we push/pull options) */
2334
+  if (c->options.pull || c->options.mode == MODE_SERVER)
2335 2335
     {
2336 2336
       /* Account for worst-case crypto overhead before allocating buffers */
2337 2337
       frame_add_to_extra_frame (&c->c2.frame, crypto_max_overhead());
... ...
@@ -2375,6 +2375,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
2375 2375
   to.renegotiate_packets = options->renegotiate_packets;
2376 2376
   to.renegotiate_seconds = options->renegotiate_seconds;
2377 2377
   to.single_session = options->single_session;
2378
+  to.mode = options->mode;
2378 2379
   to.pull = options->pull;
2379 2380
 #ifdef ENABLE_PUSH_PEER_INFO
2380 2381
   if (options->push_peer_info)		/* all there is */
... ...
@@ -245,13 +245,30 @@ incoming_push_message (struct context *c, const struct buffer *buffer)
245 245
 	  if (!do_up (c, true, c->options.push_option_types_found))
246 246
 	    {
247 247
 	      msg (D_PUSH_ERRORS, "Failed to open tun/tap interface");
248
-	      register_signal (c, SIGUSR1, "do_up-failed");
249
-	      goto cleanup;
248
+	      goto error;
250 249
 	    }
251 250
 	}
252 251
       event_timeout_clear (&c->c2.push_request_interval);
253 252
     }
253
+  else if (status == PUSH_MSG_REQUEST)
254
+    {
255
+      if (c->options.mode == MODE_SERVER)
256
+	{
257
+	  struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE];
258
+	  /* Do not regenerate keys if client send a second push request */
259
+	  if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized &&
260
+	      !tls_session_update_crypto_params (session, &c->options,
261
+		  &c->c2.frame))
262
+	    {
263
+	      msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed");
264
+	      goto error;
265
+	    }
266
+	}
267
+    }
254 268
 
269
+  goto cleanup;
270
+error:
271
+  register_signal (c, SIGUSR1, "process-push-msg-failed");
255 272
 cleanup:
256 273
   gc_free (&gc);
257 274
 }
... ...
@@ -302,15 +319,13 @@ prepare_push_reply (struct options *o, struct tls_multi *tls_multi)
302 302
     }
303 303
 
304 304
   /* Push cipher if client supports Negotiable Crypto Parameters */
305
-  optstr = peer_info ? strstr(peer_info, "IV_NCP=") : NULL;
306
-  if (optstr)
305
+  if (tls_peer_info_ncp_ver (peer_info) >= 2 && o->ncp_enabled)
307 306
     {
308
-      int ncp = 0;
309
-      int r = sscanf(optstr, "IV_NCP=%d", &ncp);
310
-      if ((r == 1) && (ncp == 2))
311
-	{
312
-	  push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername);
313
-	}
307
+      /* Push the first cipher from --ncp-ciphers to the client.
308
+       * TODO: actual negotiation, instead of server dictatorship. */
309
+      char *push_cipher = string_alloc(o->ncp_ciphers, &o->gc);
310
+      o->ciphername = strtok (push_cipher, ":");
311
+      push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername);
314 312
     }
315 313
   return true;
316 314
 }
... ...
@@ -1665,10 +1665,10 @@ tls_session_update_crypto_params(struct tls_session *session,
1665 1665
   bool ret = false;
1666 1666
   struct key_state *ks = &session->key[KS_PRIMARY];	/* primary key */
1667 1667
 
1668
-  ASSERT (!session->opt->server);
1669 1668
   ASSERT (ks->authenticated);
1670 1669
 
1671
-  if (0 != strcmp(options->ciphername, session->opt->config_ciphername) &&
1670
+  if (!session->opt->server &&
1671
+      0 != strcmp(options->ciphername, session->opt->config_ciphername) &&
1672 1672
       !item_in_list(options->ciphername, options->ncp_ciphers))
1673 1673
     {
1674 1674
       msg (D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s or %s",
... ...
@@ -1695,12 +1695,13 @@ tls_session_update_crypto_params(struct tls_session *session,
1695 1695
       options->ce.tun_mtu_defined, options->ce.tun_mtu);
1696 1696
   frame_print (frame, D_MTU_INFO, "Data Channel MTU parms");
1697 1697
 
1698
+  const struct session_id *client_sid = session->opt->server ?
1699
+      &ks->session_id_remote : &session->session_id;
1700
+  const struct session_id *server_sid = !session->opt->server ?
1701
+      &ks->session_id_remote : &session->session_id;
1698 1702
   if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi,
1699
-			       &session->opt->key_type,
1700
-			       ks->key_src,
1701
-			       &session->session_id,
1702
-			       &ks->session_id_remote,
1703
-			       false))
1703
+      &session->opt->key_type, ks->key_src, client_sid, server_sid,
1704
+      session->opt->server))
1704 1705
     {
1705 1706
       msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed");
1706 1707
       goto cleanup;
... ...
@@ -1958,8 +1959,11 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
1958 1958
       buf_printf(&out, "IV_PROTO=2\n");
1959 1959
 
1960 1960
       /* support for Negotiable Crypto Paramters */
1961
-      if (session->opt->ncp_enabled && session->opt->pull)
1962
-	buf_printf(&out, "IV_NCP=2\n");
1961
+      if (session->opt->ncp_enabled &&
1962
+	  (session->opt->mode == MODE_SERVER || session->opt->pull))
1963
+	{
1964
+	  buf_printf(&out, "IV_NCP=2\n");
1965
+	}
1963 1966
 
1964 1967
       /* push compression status */
1965 1968
 #ifdef USE_COMP
... ...
@@ -2063,10 +2067,13 @@ key_method_2_write (struct buffer *buf, struct tls_session *session)
2063 2063
   if (!push_peer_info (buf, session))
2064 2064
     goto error;
2065 2065
 
2066
-  /*
2067
-   * generate tunnel keys if server
2066
+  /* Generate tunnel keys if we're a TLS server.
2067
+   * If we're a p2mp server and IV_NCP >= 2 is negotiated, the first key
2068
+   * generation is postponed until after the pull/push, so we can process pushed
2069
+   * cipher directives.
2068 2070
    */
2069
-  if (session->opt->server)
2071
+  if (session->opt->server && !(session->opt->ncp_enabled &&
2072
+	session->opt->mode == MODE_SERVER && ks->key_id <= 0))
2070 2073
     {
2071 2074
       if (ks->authenticated)
2072 2075
 	{
... ...
@@ -2218,6 +2225,12 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
2218 2218
   multi->peer_info = read_string_alloc (buf);
2219 2219
   if ( multi->peer_info )
2220 2220
       output_peer_info_env (session->opt->es, multi->peer_info);
2221
+
2222
+  if (tls_peer_info_ncp_ver (multi->peer_info) < 2)
2223
+    {
2224
+      /* Peer does not support NCP */
2225
+      session->opt->ncp_enabled = false;
2226
+    }
2221 2227
 #endif
2222 2228
 
2223 2229
   if (tls_session_user_pass_enabled(session))
... ...
@@ -3689,6 +3702,20 @@ tls_update_remote_addr (struct tls_multi *multi, const struct link_socket_actual
3689 3689
   gc_free (&gc);
3690 3690
 }
3691 3691
 
3692
+int
3693
+tls_peer_info_ncp_ver(const char *peer_info)
3694
+{
3695
+  const char *ncpstr = peer_info ? strstr (peer_info, "IV_NCP=") : NULL;
3696
+  if (ncpstr)
3697
+    {
3698
+      int ncp = 0;
3699
+      int r = sscanf(ncpstr, "IV_NCP=%d", &ncp);
3700
+      if (r == 1)
3701
+	return ncp;
3702
+    }
3703
+  return 0;
3704
+}
3705
+
3692 3706
 /*
3693 3707
  * Dump a human-readable rendition of an openvpn packet
3694 3708
  * into a garbage collectable string which is returned.
... ...
@@ -497,6 +497,12 @@ tls_get_peer_info(const struct tls_multi *multi)
497 497
 }
498 498
 #endif
499 499
 
500
+/**
501
+ * Return the Negotiable Crypto Parameters version advertised in the peer info
502
+ * string, or 0 if none specified.
503
+ */
504
+int tls_peer_info_ncp_ver(const char *peer_info);
505
+
500 506
 /*
501 507
  * inline functions
502 508
  */
... ...
@@ -236,6 +236,7 @@ struct tls_options
236 236
 #ifdef ENABLE_OCC
237 237
   bool disable_occ;
238 238
 #endif
239
+  int mode;
239 240
   bool pull;
240 241
 #ifdef ENABLE_PUSH_PEER_INFO
241 242
   int push_peer_info_detail;