Ticket #49: tlsfloat.patch

File tlsfloat.patch, 11.1 KB (added by avalentin, 11 years ago)

Enable floating in UDP server mode if auth algo is enabled

  • src/openvpn/crypto.c

    From 4e4ba281fb2821b27ab3f3a329e4ff3b4b1147da Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Andr=C3=A9=20Valentin?= <avalentin@marcant.net>
    Date: Mon, 14 Oct 2013 23:06:05 +0200
    Subject: [PATCH] Floating: Add support for floating in TLS mode
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    To: openvpn-devel@lists.sourceforge.net
    
    Add support for floating in tls mode using the HMAC of a packet. It costs
    a roundtrip through the clients. Its security comes from a secret key, both
    peers have. This key and the data form the signature used, which is then
    checked againts existing peer connections. Therefore a good auth algo is
    recommended.
    
    URL: https://community.openvpn.net/openvpn/ticket/49
    
    Signed-off-by: André Valentin <avalentin@marcant.net>
    ---
     src/openvpn/crypto.c  |   55 ++++++++++++++++++++++++
     src/openvpn/crypto.h  |    4 ++
     src/openvpn/mudp.c    |  112 +++++++++++++++++++++++++++++++++++++++++++++++++
     src/openvpn/mudp.h    |   18 ++++++++
     src/openvpn/options.c |    3 ++
     src/openvpn/perf.h    |    2 +
     src/openvpn/ssl.c     |   28 +++++++++++++
     src/openvpn/ssl.h     |    6 +++
     8 files changed, 228 insertions(+)
    
    diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
    index c4c356d..891488d 100644
    a b openvpn_decrypt (struct buffer *buf, struct buffer work, 
    389389}
    390390
    391391/*
     392 * This verifies if a packet and its HMAC fit to a crypto context.
     393 *
     394 * On success true is returned.
     395 */
     396bool
     397crypto_test_hmac (struct buffer *buf,
     398          const struct crypto_options *opt)
     399{
     400  struct gc_arena gc;
     401  gc_init (&gc);
     402  int offset = 1;
     403
     404  if (buf->len > 0 && opt->key_ctx_bi)
     405    {
     406      struct key_ctx *ctx = &opt->key_ctx_bi->decrypt;
     407
     408      /* Verify the HMAC */
     409      if (ctx->hmac)
     410        {
     411          int hmac_len;
     412          uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */
     413
     414          hmac_ctx_reset(ctx->hmac);
     415
     416          /* Assume the length of the input HMAC */
     417          hmac_len = hmac_ctx_size (ctx->hmac);
     418
     419          /* Authentication fails if insufficient data in packet for HMAC */
     420          if ((buf->len - offset) < hmac_len)
     421            {
     422              gc_free (&gc);
     423              return false;
     424            }
     425
     426          hmac_ctx_update (ctx->hmac, BPTR (buf) + offset + hmac_len, BLEN (buf) - offset - hmac_len);
     427          hmac_ctx_final (ctx->hmac, local_hmac);
     428
     429          /* Compare locally computed HMAC with packet HMAC */
     430          if (memcmp_constant_time (local_hmac, BPTR (buf) + offset, hmac_len))
     431            {
     432              gc_free (&gc);
     433              return false;
     434            }
     435           
     436          gc_free (&gc);
     437          return true;
     438        }
     439    }
     440
     441  gc_free (&gc);
     442  return false;
     443}
     444
     445
     446/*
    392447 * How many bytes will we add to frame buffer for a given
    393448 * set of crypto options?
    394449 */
  • src/openvpn/crypto.h

    diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h
    index 3b4b88e..296519a 100644
    a b bool openvpn_decrypt (struct buffer *buf, struct buffer work, 
    279279                      const struct crypto_options *opt,
    280280                      const struct frame* frame);
    281281
     282
     283bool crypto_test_hmac (struct buffer *buf,
     284           const struct crypto_options *opt);
     285           
    282286/** @} name Functions for performing security operations on data channel packets */
    283287
    284288void crypto_adjust_frame_parameters(struct frame *frame,
  • src/openvpn/mudp.c

    diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
    index 3468dab..9fb4fb5 100644
    a b multi_get_create_instance_udp (struct multi_context *m) 
    6363        {
    6464          mi = (struct multi_instance *) he->value;
    6565        }
     66      else if (multi_find_instance_udp (m,  mi, real))
     67        {
     68          /* found instance */
     69          msg (D_MULTI_LOW, "MULTI: Floated with HMAC authentication to a new client address: %s",
     70               print_link_socket_actual (&m->top.c2.from, &gc));
     71        }
    6672      else
    6773        {
    6874          if (!m->top.c2.tls_auth_standalone
    multi_get_create_instance_udp (struct multi_context *m) 
    111117}
    112118
    113119/*
     120 * Find a client instance based on the HMAC, if auth is used. The function
     121 * iterates over all peers to find a fitting instance. The found instance is
     122 * updated with the current peer address.
     123 * If the instance doesn't exist, return false.
     124 */
     125bool
     126multi_find_instance_udp (struct multi_context *m,  struct multi_instance *mi,
     127                         struct mroute_addr real)
     128{
     129  struct gc_arena gc = gc_new ();
     130  struct hash *hash = m->hash;
     131  struct hash_element *he;
     132  const uint32_t hv = hash_value (hash, &real);
     133  struct hash_bucket *bucket = hash_bucket (hash, hv);
     134  struct hash_iterator hi;
     135  struct mroute_addr real_old;
     136  int op;
     137  uint8_t c;
     138 
     139  perf_push (PERF_MULTI_FIND_INSTANCE);
     140 
     141  /* try to detect client floating */
     142  if (!m->top.options.ce.remote_float
     143      || !m->top.options.authname_defined)
     144   goto err;
     145
     146  /* minimum size 1 byte */
     147  if (m->top.c2.buf.len < 1)
     148    goto err;
     149
     150  /* Only accept DATA_V1 opcode */
     151  c = *BPTR (&m->top.c2.buf);
     152  op = c >> P_OPCODE_SHIFT;
     153  if (op != P_DATA_V1)
     154    goto err;
     155
     156  hash_iterator_init (hash, &hi);
     157  while ((he = hash_iterator_next (&hi)))
     158    {
     159      mi = (struct multi_instance *) he->value;
     160   
     161      /* verify if this instance allows hmac verification */
     162      if (!crypto_test_hmac (&m->top.c2.buf, &mi->context.c2.crypto_options))
     163        continue;
     164
     165      generate_prefix (mi);
     166      msg (D_MULTI_MEDIUM, "MULTI: Detected floating by hmac test, new client address: %s",
     167           print_link_socket_actual (&m->top.c2.from, &gc));
     168
     169      /* update address */
     170      real_old = mi->real;
     171      mi->real = real;
     172      mi->context.c1.link_socket_addr = m->top.c1.link_socket_addr;
     173      mi->context.c2.from = m->top.c2.from;             
     174      mi->context.c2.to_link_addr = &mi->context.c2.from;
     175 
     176      /* switch to new log prefix */
     177      generate_prefix (mi);
     178 
     179      /* inherit buffers */
     180      mi->context.c2.buffers = m->top.c2.buffers;
     181
     182      /* inherit parent link_socket and link_socket_info */
     183      mi->context.c2.link_socket = m->top.c2.link_socket;
     184      mi->context.c2.link_socket_info->lsa->actual = m->top.c2.from;
     185   
     186      /* fix remote_addr in tls structure */
     187      tls_update_remote_addr (mi->context.c2.tls_multi, &mi->context.c2.from);
     188
     189      mi->did_open_context = true;
     190      if (IS_SIG (&mi->context))
     191        goto errloop;
     192
     193      /* remove and readd this instance under the new address */
     194      hash_iterator_delete_element (&hi);
     195      hash_add_fast (hash, bucket, &mi->real, hv, mi);
     196      hash_remove (m->iter, &real_old);
     197      hash_add (m->iter, &mi->real, mi, false);
     198#ifdef MANAGEMENT_DEF_AUTH
     199      hash_remove (m->cid_hash, &mi->context.c2.mda_context.cid);
     200      hash_add (m->cid_hash, &mi->context.c2.mda_context.cid, mi, false);
     201#endif
     202
     203      /* enforce update */
     204      mi->did_real_hash = true;
     205      mi->did_iter = true;
     206#ifdef MANAGEMENT_DEF_AUTH
     207      mi->did_cid_hash = true;
     208#endif
     209     
     210      /* cleanup */
     211      hash_iterator_free (&hi);
     212      perf_pop ();
     213      gc_free (&gc);
     214      return true;
     215   }
     216
     217  errloop:   
     218    hash_iterator_free (&hi);
     219  err:
     220    perf_pop ();
     221    gc_free (&gc);
     222    return false;
     223}
     224
     225/*
    114226 * Send a packet to TCP/UDP socket.
    115227 */
    116228static inline void
  • src/openvpn/mudp.h

    diff --git a/src/openvpn/mudp.h b/src/openvpn/mudp.h
    index 97f961b..759ea6d 100644
    a b void tunnel_server_udp (struct context *top); 
    6767 */
    6868struct multi_instance *multi_get_create_instance_udp (struct multi_context *m);
    6969
     70
     71/**************************************************************************/
     72/**
     73 * Find a client instance based on the HMAC, if auth is used.
     74 * @ingroup external_multiplexer
     75 *
     76 * Find a client instance based on the HMAC, if auth is used. The function
     77 * iterates over all peers to find a fitting instance. The found instance is
     78 * updated with the current peer address.
     79 * 
     80 * @param m            - The single multi_context structure.
     81 * @param mi           - The multi_instance structure.
     82 * @param real         - The mroute_addr structure.
     83 *
     84 * @return Boolen, true if peer found, false if not.
     85 */
     86bool multi_find_instance_udp (struct multi_context *m,  struct multi_instance *mi, struct mroute_addr real);
     87
    7088#endif
    7189#endif
  • src/openvpn/options.c

    diff --git a/src/openvpn/options.c b/src/openvpn/options.c
    index 4d0271f..e14a1b7 100644
    a b static const char usage_message[] = 
    166166  "                  Set n=\"infinite\" to retry indefinitely.\n"
    167167  "--float         : Allow remote to change its IP address/port, such as through\n"
    168168  "                  DHCP (this is the default if --remote is not used).\n"
     169#ifdef ENABLE_CRYPTO
     170  "                  In server mode a valid/default auth algo is needed.\n"
     171#endif
    169172  "--ipchange cmd  : Run command cmd on remote ip address initial\n"
    170173  "                  setting or change -- execute as: cmd ip-address port#\n"
    171174  "--port port     : TCP/UDP port # for both local and remote.\n"
  • src/openvpn/perf.h

    diff --git a/src/openvpn/perf.h b/src/openvpn/perf.h
    index c531d9c..e1121d2 100644
    a b  
    5757#define PERF_PROC_OUT_TUN           18
    5858#define PERF_PROC_OUT_TUN_MTCP      19
    5959#define PERF_N                      20
     60#define PERF_MULTI_FIND_INSTANCE    21
     61
    6062
    6163#ifdef ENABLE_PERFORMANCE_METRICS
    6264
  • src/openvpn/ssl.c

    diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
    index 69f77f3..709edf7 100644
    a b tls_rec_payload (struct tls_multi *multi, 
    34543454  return ret;
    34553455}
    34563456
     3457/* Update the remote_addr, needed if a client floats. */
     3458void
     3459tls_update_remote_addr (struct tls_multi *multi,
     3460               const struct link_socket_actual *from)
     3461{
     3462  struct gc_arena gc = gc_new ();
     3463  int i;
     3464 
     3465  for (i = 0; i < KEY_SCAN_SIZE; ++i)
     3466    {
     3467      struct key_state *ks = multi->key_scan[i];
     3468      if (DECRYPT_KEY_ENABLED (multi, ks)
     3469         && ks->authenticated
     3470         && link_socket_actual_defined(&ks->remote_addr)
     3471      )
     3472       {
     3473         if (link_socket_actual_match (from, &ks->remote_addr))
     3474           continue;
     3475          dmsg (D_TLS_KEYSELECT,
     3476              "TLS: tls_update_remote_addr from IP=%s to IP=%s",
     3477              print_link_socket_actual (&ks->remote_addr, &gc),
     3478              print_link_socket_actual (from, &gc));
     3479          ks->remote_addr = *from;
     3480       }
     3481    }
     3482  gc_free (&gc);
     3483}
     3484
    34573485/*
    34583486 * Dump a human-readable rendition of an openvpn packet
    34593487 * into a garbage collectable string which is returned.
  • src/openvpn/ssl.h

    diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h
    index cd7cae2..c501b64 100644
    a b bool tls_send_payload (struct tls_multi *multi, 
    431431bool tls_rec_payload (struct tls_multi *multi,
    432432                      struct buffer *buf);
    433433
     434/*
     435 * Update remote address of a tls_multi structure
     436 */
     437void tls_update_remote_addr (struct tls_multi *multi,
     438                 const struct link_socket_actual *from);
     439                 
    434440#ifdef MANAGEMENT_DEF_AUTH
    435441static inline char *
    436442tls_get_peer_info(const struct tls_multi *multi)