]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Add preliminary server-side support for negotiable crypto parameters
authorSteffan Karger <steffan@karger.me>
Mon, 15 Feb 2016 20:07:11 +0000 (21:07 +0100)
committerGert Doering <gert@greenie.muc.de>
Mon, 15 Feb 2016 20:20:24 +0000 (21:20 +0100)
Add preliminary support for Negotiable Crypto Parameters 'level 2'
(IV_NCP=2), as proposed by James Yonan on the openvpn-devel mailinglist:
http://comments.gmane.org/gmane.network.openvpn.devel/9385

This patch makes a server push a 'cipher XXX' directive to the client,
if the client advertises "IV_NCP=2", where XXX is the cipher set in the
server config file.

This enables clients that have support for IV_NCP to connect to a
server, even when the client does not have the correct cipher specified
in it's config file.

Since pushing the cipher directive is quite similar to pushing peer-id,
I moved peer-id pushing to the same prepare_push_reply() function I
created for pushing cipher.  Adding these directives as regular push
options allows us to use the existing 'push-continuation'
infrastructure.  Note that we should not reduce safe_cap in
send_push_reply, because it was never increased to account for peer-id.

This is a preliminary patch, which will be followed by more patches to
add client support, and configurability.

v2:
 * Reword doxygen of push_options_fmt()
 * No longer push IV_NCP as a server

Signed-off-by: Steffan Karger <steffan@karger.me>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <CAA1Abx+gSgFH3=+xO6QN4NDAYwf8jctYhe8VyRxD8e1L=D6LWg@mail.gmail.com>
URL: http://article.gmane.org/gmane.network.openvpn.devel/11170
Signed-off-by: Gert Doering <gert@greenie.muc.de>
src/openvpn/push.c
src/openvpn/push.h

index d4f3cb6d349fbab9415cdef64ebc57df08cdbb39..c29093b4eccd497cc65b6bc86f15399bcc602311 100644 (file)
 
 #if P2MP
 
+/**
+ * Add an option to the push list by providing a format string.
+ *
+ * The string added to the push options is allocated in o->gc, so the caller
+ * does not have to preserve anything.
+ *
+ * @param o            The current connection's options
+ * @param msglevel     The message level to use when printing errors
+ * @param fmt          Format string for the option
+ * @param ...          Format string arguments
+ *
+ * @return true on success, false on failure.
+ */
+static bool push_option_fmt(struct options *o, int msglevel,
+    const char *fmt, ...)
+#ifdef __GNUC__
+#if __USE_MINGW_ANSI_STDIO
+    __attribute__ ((format (gnu_printf, 3, 4)))
+#else
+    __attribute__ ((format (__printf__, 3, 4)))
+#endif
+#endif
+    ;
+
 /*
  * Auth username/password
  *
@@ -239,7 +263,47 @@ send_push_request (struct context *c)
 
 #if P2MP_SERVER
 
-bool
+/**
+ * Prepare push options, based on local options and available peer info.
+ *
+ * @param options      Connection options
+ * @param tls_multi    TLS state structure for the current tunnel
+ *
+ * @return true on success, false on failure.
+ */
+static bool
+prepare_push_reply (struct options *o, struct tls_multi *tls_multi)
+{
+  const char *optstr = NULL;
+  const char * const peer_info = tls_multi->peer_info;
+
+  /* Send peer-id if client supports it */
+  optstr = peer_info ? strstr(peer_info, "IV_PROTO=") : NULL;
+  if (optstr)
+    {
+      int proto = 0;
+      int r = sscanf(optstr, "IV_PROTO=%d", &proto);
+      if ((r == 1) && (proto >= 2))
+       {
+         push_option_fmt(o, M_USAGE, "peer-id %d", tls_multi->peer_id);
+       }
+    }
+
+  /* Push cipher if client supports Negotiable Crypto Parameters */
+  optstr = peer_info ? strstr(peer_info, "IV_NCP=") : NULL;
+  if (optstr)
+    {
+      int ncp = 0;
+      int r = sscanf(optstr, "IV_NCP=%d", &ncp);
+      if ((r == 1) && (ncp == 2))
+       {
+         push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername);
+       }
+    }
+  return true;
+}
+
+static bool
 send_push_reply (struct context *c)
 {
   struct gc_arena gc = gc_new ();
@@ -309,19 +373,6 @@ send_push_reply (struct context *c)
   if (multi_push)
     buf_printf (&buf, ",push-continuation 1");
 
-  /* Send peer-id if client supports it */
-  if (c->c2.tls_multi->peer_info)
-    {
-      const char* proto_str = strstr(c->c2.tls_multi->peer_info, "IV_PROTO=");
-      if (proto_str)
-       {
-         int proto = 0;
-         int r = sscanf(proto_str, "IV_PROTO=%d", &proto);
-         if ((r == 1) && (proto >= 2))
-           buf_printf(&buf, ",peer-id %d", c->c2.tls_multi->peer_id);
-       }
-  }
-
   if (BLEN (&buf) > sizeof(cmd)-1)
     {
       const bool status = send_control_channel_string (c, BSTR (&buf), D_PUSH);
@@ -409,6 +460,21 @@ push_options (struct options *o, char **p, int msglevel, struct gc_arena *gc)
   push_option (o, opt, msglevel);
 }
 
+static bool push_option_fmt(struct options *o, int msglevel,
+    const char *format, ...)
+{
+  va_list arglist;
+  char tmp[256] = {0};
+  int len = -1;
+  va_start (arglist, format);
+  len = vsnprintf (tmp, sizeof(tmp), format, arglist);
+  va_end (arglist);
+  if (len > sizeof(tmp)-1)
+    return false;
+  push_option (o, string_alloc (tmp, &o->gc), msglevel);
+  return true;
+}
+
 void
 push_reset (struct options *o)
 {
@@ -442,7 +508,8 @@ process_incoming_push_request (struct context *c)
        }
       else
        {
-         if (send_push_reply (c))
+         if (prepare_push_reply(&c->options, c->c2.tls_multi) &&
+             send_push_reply (c))
            {
              ret = PUSH_MSG_REQUEST;
              c->c2.sent_push_reply_expiry = now + 30;
index fa06e080bd8b34eb6e442b53d0bb23bac8e0b9c0..19bbf5e1fcd7e6c3f37d501637e6744fddbce1ab 100644 (file)
@@ -62,8 +62,6 @@ void push_options (struct options *o, char **p, int msglevel, struct gc_arena *g
 
 void push_reset (struct options *o);
 
-bool send_push_reply (struct context *c);
-
 void remove_iroutes_from_push_route_list (struct options *o);
 
 void send_auth_failed (struct context *c, const char *client_reason);