gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnunet] 02/02: introduce concept of unverified_kx, as a st


From: gnunet
Subject: [GNUnet-SVN] [gnunet] 02/02: introduce concept of unverified_kx, as a step towards having KX_AUTH implemented properly
Date: Fri, 27 Jan 2017 16:23:40 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository gnunet.

commit c93c2a94d0967e8159a22fd03e3ac7498c4c2907
Author: Christian Grothoff <address@hidden>
AuthorDate: Fri Jan 27 16:23:34 2017 +0100

    introduce concept of unverified_kx, as a step towards having KX_AUTH 
implemented properly
---
 src/cadet/gnunet-service-cadet-new_tunnels.c | 173 ++++++++++++++++++++++-----
 src/cadet/gnunet-service-cadet-new_tunnels.h |   2 +-
 2 files changed, 147 insertions(+), 28 deletions(-)

diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.c 
b/src/cadet/gnunet-service-cadet-new_tunnels.c
index bdc6ac649..10ff2867d 100644
--- a/src/cadet/gnunet-service-cadet-new_tunnels.c
+++ b/src/cadet/gnunet-service-cadet-new_tunnels.c
@@ -49,6 +49,12 @@
 
 #define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__)
 
+/**
+ * How often do we try to decrypt payload with unverified key
+ * material?  Used to limit CPU increase upon receiving bogus
+ * KX.
+ */
+#define MAX_UNVERIFIED_ATTEMPTS 16
 
 /**
  * How long do we wait until tearing down an idle tunnel?
@@ -293,6 +299,15 @@ struct CadetTunnel
   struct CadetTunnelAxolotl ax;
 
   /**
+   * Unverified Axolotl info, used only if we got a fresh KX (not a
+   * KX_AUTH) while our end of the tunnel was still up.  In this case,
+   * we keep the fresh KX around but do not put it into action until
+   * we got encrypted payload that assures us of the authenticity of
+   * the KX.
+   */
+  struct CadetTunnelAxolotl *unverified_ax;
+
+  /**
    * Task scheduled if there are no more channels using the tunnel.
    */
   struct GNUNET_SCHEDULER_Task *destroy_task;
@@ -369,6 +384,13 @@ struct CadetTunnel
   unsigned int num_connections;
 
   /**
+   * How often have we tried and failed to decrypt a message using
+   * the unverified KX material from @e unverified_ax?  Used to
+   * stop trying after #MAX_UNVERIFIED_ATTEMPTS.
+   */
+  unsigned int unverified_attempts;
+
+  /**
    * Number of entries in the @e tq_head DLL.
    */
   unsigned int tq_len;
@@ -1218,13 +1240,14 @@ GCT_change_estate (struct CadetTunnel *t,
  * FIXME: does not take care of sender-authentication yet!
  *
  * @param t Tunnel on which to send it.
+ * @param ax axolotl key context to use
  * @param force_reply Force the other peer to reply with a KX message.
  */
 static void
 send_kx (struct CadetTunnel *t,
+         struct CadetTunnelAxolotl *ax,
          int force_reply)
 {
-  struct CadetTunnelAxolotl *ax = &t->ax;
   struct CadetTConnection *ct;
   struct CadetConnection *cc;
   struct GNUNET_MQ_Envelope *env;
@@ -1269,9 +1292,26 @@ send_kx (struct CadetTunnel *t,
 
 
 /**
- * Handle KX message.
+ * Cleanup state used by @a ax.
  *
- * FIXME: sender-authentication in KX is missing!
+ * @param ax state to free, but not memory of @a ax itself
+ */
+static void
+cleanup_ax (struct CadetTunnelAxolotl *ax)
+{
+  while (NULL != ax->skipped_head)
+    delete_skipped_key (ax,
+                        ax->skipped_head);
+  GNUNET_assert (0 == ax->skipped);
+  GNUNET_free_non_null (ax->kx_0);
+  GNUNET_free_non_null (ax->DHRs);
+}
+
+
+/**
+ * Handle KX message that lacks authentication (and which will thus
+ * only be considered authenticated after we respond with our own
+ * KX_AUTH and finally successfully decrypt payload).
  *
  * @param ct connection/tunnel combo that received encrypted message
  * @param msg the key exchange message
@@ -1281,13 +1321,36 @@ GCT_handle_kx (struct CadetTConnection *ct,
                const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
 {
   struct CadetTunnel *t = ct->t;
-  struct CadetTunnelAxolotl *ax = &t->ax;
+  struct CadetTunnelAxolotl *ax;
   struct GNUNET_HashCode key_material[3];
   struct GNUNET_CRYPTO_SymmetricSessionKey keys[5];
   const char salt[] = "CADET Axolotl salt";
   const struct GNUNET_PeerIdentity *pid;
   int am_I_alice;
 
+  /* We only keep ONE unverified KX around, so if there is an existing one,
+     clean it up. */
+  if (NULL != t->unverified_ax)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Dropping old unverified KX state, got a fresh one.\n",
+         t->unverified_attempts);
+    cleanup_ax (t->unverified_ax);
+    memset (t->unverified_ax,
+            0,
+            sizeof (struct CadetTunnelAxolotl));
+    new_ephemeral (t->unverified_ax);
+    t->unverified_ax->kx_0 = GNUNET_CRYPTO_ecdhe_key_create ();
+  }
+  else
+  {
+    t->unverified_ax = GNUNET_new (struct CadetTunnelAxolotl);
+    new_ephemeral (t->unverified_ax);
+    t->unverified_ax->kx_0 = GNUNET_CRYPTO_ecdhe_key_create ();
+  }
+  t->unverified_attempts = 0;
+  ax = t->unverified_ax;
+
   pid = GCP_get_id (t->destination);
   if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
                                            pid))
@@ -1309,6 +1372,7 @@ GCT_handle_kx (struct CadetTConnection *ct,
       t->kx_task = NULL;
     }
     send_kx (t,
+             ax,
              GNUNET_NO);
   }
 
@@ -1574,12 +1638,12 @@ destroy_tunnel (void *cls)
   }
   GNUNET_MST_destroy (t->mst);
   GNUNET_MQ_destroy (t->mq);
-  while (NULL != t->ax.skipped_head)
-    delete_skipped_key (&t->ax,
-                        t->ax.skipped_head);
-  GNUNET_assert (0 == t->ax.skipped);
-  GNUNET_free_non_null (t->ax.kx_0);
-  GNUNET_free_non_null (t->ax.DHRs);
+  cleanup_ax (&t->ax);
+  if (NULL != t->unverified_ax)
+  {
+    cleanup_ax (t->unverified_ax);
+    GNUNET_free (t->unverified_ax);
+  }
   GNUNET_free (t);
 }
 
@@ -1669,6 +1733,7 @@ retry_kx (void *cls)
 
   t->kx_task = NULL;
   send_kx (t,
+           &t->ax,
            ( (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) ||
              (CADET_TUNNEL_KEY_SENT == t->estate) )
            ? GNUNET_YES
@@ -1754,6 +1819,7 @@ connection_ready_cb (void *cls,
   {
   case CADET_TUNNEL_KEY_UNINITIALIZED:
     send_kx (t,
+             &t->ax,
              GNUNET_YES);
     break;
   case CADET_TUNNEL_KEY_SENT:
@@ -1773,6 +1839,7 @@ connection_ready_cb (void *cls,
     break;
   case CADET_TUNNEL_KEY_REKEY:
     send_kx (t,
+             &t->ax,
              GNUNET_NO);
     t->estate = CADET_TUNNEL_KEY_OK;
     break;
@@ -2386,13 +2453,70 @@ GCT_handle_encrypted (struct CadetTConnection *ct,
                             "# received encrypted",
                             1,
                             GNUNET_NO);
-  decrypted_size = t_ax_decrypt_and_validate (&t->ax,
-                                              cbuf,
-                                              msg,
-                                              size);
+  decrypted_size = -1;
+  if ( (CADET_TUNNEL_KEY_OK == t->estate) ||
+       (CADET_TUNNEL_KEY_REKEY == t->estate) )
+  {
+    /* We have well-established key material available,
+       try that. (This is the common case.) */
+    decrypted_size = t_ax_decrypt_and_validate (&t->ax,
+                                                cbuf,
+                                                msg,
+                                                size);
+  }
+
+  if ( (-1 == decrypted_size) &&
+       (NULL != t->unverified_ax) )
+  {
+    /* We have un-authenticated KX material available. We should try
+       this as a back-up option, in case the sender crashed and
+       switched keys. */
+    decrypted_size = t_ax_decrypt_and_validate (t->unverified_ax,
+                                                cbuf,
+                                                msg,
+                                                size);
+    if (-1 != decrypted_size)
+    {
+      /* It worked! Treat this as authentication of the AX data! */
+      cleanup_ax (&t->ax);
+      t->ax = *t->unverified_ax;
+      GNUNET_free (t->unverified_ax);
+      t->unverified_ax = NULL;
+    }
+    if (CADET_TUNNEL_KEY_PING == t->estate)
+    {
+      /* First time it worked, move tunnel into production! */
+      GCT_change_estate (t,
+                         CADET_TUNNEL_KEY_OK);
+      if (NULL != t->send_task)
+        GNUNET_SCHEDULER_cancel (t->send_task);
+      t->send_task = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
+                                               t);
+    }
+  }
+  if (NULL != t->unverified_ax)
+  {
+    /* We had unverified KX material that was useless; so increment
+       counter and eventually move to ignore it.  Note that we even do
+       this increment if we successfully decrypted with the old KX
+       material and thus didn't even both with the new one.  This is
+       the ideal case, as a malicious injection of bogus KX data
+       basically only causes us to increment a counter a few times. */
+    t->unverified_attempts++;
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Failed to decrypt message with unverified KX data %u times\n",
+         t->unverified_attempts);
+    if (t->unverified_attempts > MAX_UNVERIFIED_ATTEMPTS)
+    {
+      cleanup_ax (t->unverified_ax);
+      GNUNET_free (t->unverified_ax);
+      t->unverified_ax = NULL;
+    }
+  }
 
   if (-1 == decrypted_size)
   {
+    /* Decryption failed for good, complain. */
     GNUNET_break_op (0);
     LOG (GNUNET_ERROR_TYPE_WARNING,
          "Tunnel %s failed to decrypt and validate encrypted data\n",
@@ -2403,15 +2527,7 @@ GCT_handle_encrypted (struct CadetTConnection *ct,
                               GNUNET_NO);
     return;
   }
-  if (CADET_TUNNEL_KEY_PING == t->estate)
-  {
-    GCT_change_estate (t,
-                       CADET_TUNNEL_KEY_OK);
-    if (NULL != t->send_task)
-      GNUNET_SCHEDULER_cancel (t->send_task);
-    t->send_task = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
-                                             t);
-  }
+
   /* The MST will ultimately call #handle_decrypted() on each message. */
   GNUNET_break_op (GNUNET_OK ==
                    GNUNET_MST_from_buffer (t->mst,
@@ -2430,7 +2546,7 @@ GCT_handle_encrypted (struct CadetTConnection *ct,
  * @param t Tunnel on which this message is transmitted.
  * @param cont Continuation to call once message is really sent.
  * @param cont_cls Closure for @c cont.
- * @return Handle to cancel message. NULL if @c cont is NULL.
+ * @return Handle to cancel message
  */
 struct CadetTunnelQueueEntry *
 GCT_send (struct CadetTunnel *t,
@@ -2443,6 +2559,12 @@ GCT_send (struct CadetTunnel *t,
   struct GNUNET_MQ_Envelope *env;
   struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg;
 
+  if ( (CADET_TUNNEL_KEY_OK != t->estate) &&
+       (CADET_TUNNEL_KEY_REKEY != t->estate) )
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
   payload_size = ntohs (message->size);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Encrypting %u bytes for tunnel %s\n",
@@ -2638,9 +2760,6 @@ GCT_debug (const struct CadetTunnel *t,
         estate2s (t->estate),
         t->tq_len,
         t->num_connections);
-#if DUMP_KEYS_TO_STDERR
-  ax_debug (t->ax, level);
-#endif
   LOG2 (level,
         "TTT channels:\n");
   GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.h 
b/src/cadet/gnunet-service-cadet-new_tunnels.h
index 463780686..080de0fc3 100644
--- a/src/cadet/gnunet-service-cadet-new_tunnels.h
+++ b/src/cadet/gnunet-service-cadet-new_tunnels.h
@@ -200,7 +200,7 @@ GCT_send_channel_destroy (struct CadetTunnel *t,
  * @param t Tunnel on which this message is transmitted.
  * @param cont Continuation to call once message is really sent.
  * @param cont_cls Closure for @c cont.
- * @return Handle to cancel message. NULL if @c cont is NULL.
+ * @return Handle to cancel message.
  */
 struct CadetTunnelQueueEntry *
 GCT_send (struct CadetTunnel *t,

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]