fixing 1792: validate signature in disconnect request
authorChristian Grothoff <christian@grothoff.org>
Fri, 21 Oct 2011 07:36:45 +0000 (07:36 +0000)
committerChristian Grothoff <christian@grothoff.org>
Fri, 21 Oct 2011 07:36:45 +0000 (07:36 +0000)
src/transport/gnunet-service-transport.c
src/transport/gnunet-service-transport_neighbours.c
src/transport/gnunet-service-transport_neighbours.h

index 561873cd945b391ff672c12d09d865b9194051bb..6273816c760e3b772f26a26c93259b66f1f7903d 100644 (file)
@@ -276,9 +276,7 @@ plugin_env_receive_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
                                       NULL);
     break;
   case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT:
-    /* FIXME: do some validation to prevent an attacker from sending
-     * a fake disconnect message... */           
-    GST_neighbours_force_disconnect (peer);
+    GST_neighbours_handle_disconnect_message (peer, message);
     break;
   case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE:
     GST_neighbours_keepalive (peer);
index 23ff82f91ca9f7c4c4b503f9474dbc5c62b1936b..efb94b6f1a89e13ff149d2679a8723d03e8d04e9 100644 (file)
@@ -111,12 +111,18 @@ struct SessionDisconnectMessage
    */
   struct GNUNET_TIME_AbsoluteNBO timestamp;
 
+  /**
+   * Public key of the sender.
+   */
+  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
+  
   /**
    * Signature of the peer that sends us the disconnect.  Only
    * valid if the timestamp is AFTER the timestamp from the
    * corresponding 'CONNECT' message.
    */
   struct GNUNET_CRYPTO_RsaSignature signature;
+
 };
 
 
@@ -1169,9 +1175,11 @@ GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
     disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
     disconnect_msg.reserved = htonl (0);
     disconnect_msg.purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
-                                        sizeof (struct GNUNET_TIME_AbsoluteNBO));
+                                        sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
+                                        sizeof (struct GNUNET_TIME_AbsoluteNBO) );
     disconnect_msg.purpose.purpose = htonl (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
     disconnect_msg.timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
+    disconnect_msg.public_key = GST_my_public_key;
     GNUNET_assert (GNUNET_OK ==
                   GNUNET_CRYPTO_rsa_sign (GST_my_private_key,
                                           &disconnect_msg.purpose,
@@ -1194,6 +1202,72 @@ GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
 }
 
 
+/**
+ * We received a disconnect message from the given peer,
+ * validate and process.
+ * 
+ * @param peer sender of the message
+ * @param msg the disconnect message
+ */
+void
+GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity *peer,
+                                         const struct GNUNET_MessageHeader *msg)
+{
+  struct NeighbourMapEntry *n;
+  const struct SessionDisconnectMessage *sdm;
+  GNUNET_HashCode hc;
+
+  if (ntohs (msg->size) != sizeof (struct SessionDisconnectMessage))
+  {
+    // GNUNET_break_op (0);
+    GNUNET_STATISTICS_update (GST_stats,
+                             gettext_noop ("# disconnect messages ignored (old format)"), 1,
+                             GNUNET_NO);
+    return;
+  }
+  sdm = (const struct SessionDisconnectMessage* ) msg;
+  n = lookup_neighbour (peer);
+  if (NULL == n)
+    return;                     /* gone already */
+  if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value <=
+      n->connect_ts.abs_value)
+  {
+    GNUNET_STATISTICS_update (GST_stats,
+                             gettext_noop ("# disconnect messages ignored (timestamp)"), 1,
+                             GNUNET_NO);
+    return;
+  }
+  GNUNET_CRYPTO_hash (&sdm->public_key,
+                     sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+                     &hc);
+  if (0 != memcmp (peer,
+                  &hc,
+                  sizeof (struct GNUNET_PeerIdentity)))
+  {
+    GNUNET_break_op (0);
+    return;
+  }
+  if (ntohl (sdm->purpose.size) != 
+      sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+      sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
+      sizeof (struct GNUNET_TIME_AbsoluteNBO))
+  {
+    GNUNET_break_op (0);
+    return;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_rsa_verify (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT,
+                               &sdm->purpose,
+                               &sdm->signature,
+                               &sdm->public_key))
+  {
+    GNUNET_break_op (0);
+    return;
+  }
+  GST_neighbours_force_disconnect (peer);
+}
+
+
 /**
  * We received a 'SESSION_CONNECT' message from the other peer.
  * Consider switching to it.
index 2f6962a67506f2766f7227f3e04810eee4d30c33..27f7aae31da23092ff9c378c97007c7033ac5687 100644 (file)
@@ -232,6 +232,17 @@ GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
                               const struct GNUNET_ATS_Information *ats,
                               uint32_t ats_count);
 
+/**
+ * We received a disconnect message from the given peer,
+ * validate and process.
+ * 
+ * @param peer sender of the message
+ * @param msg the disconnect message
+ */
+void
+GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity *peer,
+                                         const struct GNUNET_MessageHeader *msg);
+
 
 #endif
 /* end of file gnunet-service-transport_neighbours.h */