- fix shutdown memleak
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet_tunnel.c
index f0232fee2552548c528e38a29e7e47b209143e8e..5f0f660b48f0352de0afe40a8091589dbef8ff71 100644 (file)
@@ -43,6 +43,8 @@
 #define DUMP_KEYS_TO_STDERR GNUNET_NO
 #endif
 
+#define MIN_TUNNEL_BUFFER       8
+#define MAX_TUNNEL_BUFFER       64
 #define MAX_SKIPPED_KEYS        64
 #define MAX_KEY_GAP             256
 #define AX_HEADER_SIZE (sizeof (uint32_t) * 2\
@@ -188,8 +190,9 @@ struct CadetTunnelSkippedKey
   struct GNUNET_CRYPTO_SymmetricSessionKey MK;
 };
 
+
 /**
- * Axolotl data, according to @url https://github.com/trevp/axolotl/wiki .
+ * Axolotl data, according to https://github.com/trevp/axolotl/wiki .
  */
 struct CadetTunnelAxolotl
 {
@@ -250,11 +253,6 @@ struct CadetTunnelAxolotl
    */
   struct GNUNET_CRYPTO_EcdhePrivateKey *kx_0;
 
-  /**
-   * ECDH Identity key (recv).
-   */
-  struct GNUNET_CRYPTO_EcdhePublicKey DHIr;
-
   /**
    * ECDH Ratchet key (send).
    */
@@ -466,28 +464,6 @@ struct CadetTunnelQueue
 };
 
 
-/**
- * Cached Axolotl key with signature.
- */
-struct CadetAxolotlSignedKey
-{
-  /**
-   * Information about what is being signed (@a permanent_key).
-   */
-  struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
-
-  /**
-   * Permanent public ECDH key.
-   */
-  struct GNUNET_CRYPTO_EcdhePublicKey permanent_key;
-
-  /**
-   * An EdDSA signature of the permanent ECDH key with the Peer's ID key.
-   */
-  struct GNUNET_CRYPTO_EddsaSignature signature;
-} GNUNET_PACKED;
-
-
 /******************************************************************************/
 /*******************************   GLOBALS  ***********************************/
 /******************************************************************************/
@@ -533,13 +509,6 @@ const static struct GNUNET_CRYPTO_EddsaPrivateKey *id_key;
 
 /********************************  AXOLOTL ************************************/
 
-static struct GNUNET_CRYPTO_EcdhePrivateKey *ax_key;
-
-/**
- * Own Axolotl permanent public key (cache).
- */
-static struct CadetAxolotlSignedKey ax_identity;
-
 /**
  * How many messages are needed to trigger a ratchet advance.
  */
@@ -656,7 +625,6 @@ is_ready (struct CadetTunnel *t)
 {
   int ready;
 
-  GCT_debug (t, GNUNET_ERROR_TYPE_DEBUG);
   ready = CADET_TUNNEL_READY == t->cstate
           && (CADET_TUNNEL_KEY_OK == t->estate
               || CADET_TUNNEL_KEY_REKEY == t->estate);
@@ -703,19 +671,6 @@ ephemeral_purpose_size (void)
 }
 
 
-/**
- * Ephemeral key message purpose size.
- *
- * @return Size of the part of the ephemeral key message that must be signed.
- */
-static size_t
-ax_purpose_size (void)
-{
-  return sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
-         sizeof (struct GNUNET_CRYPTO_EcdhePublicKey);
-}
-
-
 /**
  * Size of the encrypted part of a ping message.
  *
@@ -810,7 +765,7 @@ get_connection_allowed (const struct CadetTConnection *tc)
  * @param t Tunnel on which the message came.
  * @param msg The ephemeral key message.
  *
- * @return GNUNET_OK if message is fine, GNUNET_SYSERR otherwise.
+ * @return #GNUNET_OK if message is fine, #GNUNET_SYSERR otherwise.
  */
 int
 check_ephemeral (struct CadetTunnel *t,
@@ -1368,6 +1323,49 @@ try_old_ax_keys (struct CadetTunnel *t, struct GNUNET_CADET_AX *dst,
 }
 
 
+/**
+ * Delete a key from the list of skipped keys.
+ *
+ * @param t Tunnel to delete from.
+ * @param HKr Header Key to use.
+ */
+static void
+store_skipped_key (struct CadetTunnel *t,
+                   const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr)
+{
+  struct CadetTunnelSkippedKey *key;
+
+  key = GNUNET_new (struct CadetTunnelSkippedKey);
+  key->timestamp = GNUNET_TIME_absolute_get ();
+  t_hmac_derive_key (&t->ax->CKr, &key->MK, "0", 1);
+  #if DUMP_KEYS_TO_STDERR
+  LOG (GNUNET_ERROR_TYPE_INFO, "    storing MK for Nr %u: %s\n",
+       t->ax->Nr, GNUNET_h2s ((struct GNUNET_HashCode *) &key->MK));
+  LOG (GNUNET_ERROR_TYPE_INFO, "    for CKr: %s\n",
+       GNUNET_h2s ((struct GNUNET_HashCode *) &t->ax->CKr));
+  #endif
+  t_hmac_derive_key (&t->ax->CKr, &t->ax->CKr, "1", 1);
+  GNUNET_CONTAINER_DLL_insert (t->ax->skipped_head, t->ax->skipped_tail, key);
+  t->ax->Nr++;
+  t->ax->skipped++;
+}
+
+
+/**
+ * Delete a key from the list of skipped keys.
+ *
+ * @param t Tunnel to delete from.
+ * @param key Key to delete.
+ */
+static void
+delete_skipped_key (struct CadetTunnel *t, struct CadetTunnelSkippedKey *key)
+{
+  GNUNET_CONTAINER_DLL_remove (t->ax->skipped_head, t->ax->skipped_tail, key);
+  GNUNET_free (key);
+  t->ax->skipped--;
+}
+
+
 /**
  * Stage skipped AX keys and calculate the message key.
  *
@@ -1375,21 +1373,16 @@ try_old_ax_keys (struct CadetTunnel *t, struct GNUNET_CADET_AX *dst,
  *
  * @param t Tunnel where to stage the keys.
  * @param HKr Header key.
- * @param Nr Current message number.
  * @param Np Received meesage number.
- * @param CKr[in/out] Chain key, gets ratcheted forward to the new state.
  */
 static void
 store_ax_keys (struct CadetTunnel *t,
                const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr,
-               uint32_t Nr, uint32_t Np,
-               struct GNUNET_CRYPTO_SymmetricSessionKey *CKr)
+               uint32_t Np)
 {
-  struct CadetTunnelSkippedKey *key;
-  unsigned int i;
   int gap;
 
-  gap = Np - Nr;
+  gap = Np - t->ax->Nr;
   if (MAX_KEY_GAP < gap || 0 > gap)
   {
     /* Avoid DoS (forcing peer to do 2*33 chain HMAC operations) */
@@ -1398,21 +1391,11 @@ store_ax_keys (struct CadetTunnel *t,
     return;
   }
 
-  for (i = Nr; i < Np; i++)
-  {
-    key = GNUNET_new (struct CadetTunnelSkippedKey);
-    key->timestamp = GNUNET_TIME_absolute_get ();
-    t_hmac_derive_key (CKr, &key->MK, "0", 1);
-    #if DUMP_KEYS_TO_STDERR
-    LOG (GNUNET_ERROR_TYPE_INFO, "    storing MK for Nr %u: %s\n",
-         i, GNUNET_h2s ((struct GNUNET_HashCode *) &key->MK));
-    LOG (GNUNET_ERROR_TYPE_INFO, "    for CKr: %s\n",
-         GNUNET_h2s ((struct GNUNET_HashCode *) &t->ax->CKr));
-    #endif
-    t_hmac_derive_key (CKr, CKr, "1", 1);
-    GNUNET_CONTAINER_DLL_insert (t->ax->skipped_head, t->ax->skipped_tail, key);
-    t->ax->skipped++;
-  }
+  while (t->ax->Nr < Np)
+    store_skipped_key (t, HKr);
+
+  while (t->ax->skipped > MAX_SKIPPED_KEYS)
+    delete_skipped_key (t, t->ax->skipped_tail);
 }
 
 
@@ -1472,7 +1455,7 @@ t_ax_decrypt_and_validate (struct CadetTunnel *t, void *dst,
     Np = ntohl (dstmsg->Ns);
     PNp = ntohl (dstmsg->PNs);
     DHRp = &dstmsg->DHRs;
-    store_ax_keys (t, &HK, ax->Nr, PNp, &ax->CKr);
+    store_ax_keys (t, &HK, PNp);
 
     /* RKp, NHKp, CKp = KDF (HMAC-HASH (RK, DH (DHRp, DHRs))) */
     GNUNET_CRYPTO_ecc_ecdh (ax->DHRs, DHRp, &dh);
@@ -1497,7 +1480,7 @@ t_ax_decrypt_and_validate (struct CadetTunnel *t, void *dst,
   }
 
   if (Np > ax->Nr)
-    store_ax_keys (t, &ax->HKr, ax->Nr, Np, &ax->CKr);
+    store_ax_keys (t, &ax->HKr, Np);
 
   ax->Nr = Np + 1;
 
@@ -1796,11 +1779,7 @@ queue_data (struct CadetTunnel *t, const struct GNUNET_MessageHeader *msg)
 
   LOG (GNUNET_ERROR_TYPE_DEBUG, "queue data on Tunnel %s\n", GCT_2s (t));
 
-  if (GNUNET_YES == is_ready (t))
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
+  GNUNET_assert (GNUNET_NO == is_ready (t));
 
   tqd = GNUNET_malloc (sizeof (struct CadetTunnelDelayed) + size);
 
@@ -2007,6 +1986,29 @@ send_queued_data (struct CadetTunnel *t)
 }
 
 
+/**
+ * @brief Resend the AX KX until we complete the handshake.
+ *
+ * @param cls Closure (tunnel).
+ * @param tc Task context.
+ */
+static void
+ax_kx_resend (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct CadetTunnel *t = cls;
+
+  t->rekey_task = NULL;
+
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+    return;
+
+  if (CADET_TUNNEL_KEY_OK == t->estate)
+    return;
+
+  GCT_send_ax_kx (t, GNUNET_YES);
+}
+
+
 /**
  * Callback called when a queued message is sent.
  *
@@ -2018,15 +2020,31 @@ send_queued_data (struct CadetTunnel *t)
  */
 static void
 ephm_sent (void *cls,
-         struct CadetConnection *c,
-         struct CadetConnectionQueue *q,
-         uint16_t type, int fwd, size_t size)
+           struct CadetConnection *c,
+           struct CadetConnectionQueue *q,
+           uint16_t type, int fwd, size_t size)
 {
   struct CadetTunnel *t = cls;
   LOG (GNUNET_ERROR_TYPE_DEBUG, "ephemeral sent %s\n", GC_m2s (type));
+
   t->ephm_h = NULL;
+
+  if (CADET_TUNNEL_KEY_OK == t->estate)
+    return;
+
+  if (CADET_Axolotl == t->enc_type && CADET_TUNNEL_KEY_OK != t->estate)
+  {
+    if (NULL != t->rekey_task)
+    {
+      GNUNET_break (0);
+      GNUNET_SCHEDULER_cancel (t->rekey_task);
+    }
+    t->rekey_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+                                                  &ax_kx_resend, t);
+  }
 }
 
+
 /**
  * Callback called when a queued message is sent.
  *
@@ -2048,6 +2066,7 @@ pong_sent (void *cls,
   t->pong_h = NULL;
 }
 
+
 /**
  * Sends key exchange message on a tunnel, choosing the best connection.
  * Should not be called on loopback tunnels.
@@ -2663,8 +2682,18 @@ destroy_ax (struct CadetTunnel *t)
 
   GNUNET_free (t->ax);
   t->ax = NULL;
-}
 
+  if (NULL != t->rekey_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->rekey_task);
+    t->rekey_task = NULL;
+  }
+  if (NULL != t->ephm_h)
+  {
+    GCC_cancel (t->ephm_h);
+    t->ephm_h = NULL;
+  }
+}
 
 
 /**
@@ -2760,7 +2789,8 @@ handle_ephemeral (struct CadetTunnel *t,
  * @param msg Key eXchange Pong message.
  */
 static void
-handle_pong (struct CadetTunnel *t, const struct GNUNET_CADET_KX_Pong *msg)
+handle_pong (struct CadetTunnel *t,
+             const struct GNUNET_CADET_KX_Pong *msg)
 {
   uint32_t challenge;
 
@@ -2812,8 +2842,6 @@ handle_kx_ax (struct CadetTunnel *t, const struct GNUNET_CADET_AX_KX *msg)
   struct CadetTunnelAxolotl *ax;
   struct GNUNET_HashCode key_material[3];
   struct GNUNET_CRYPTO_SymmetricSessionKey keys[5];
-  const struct GNUNET_CRYPTO_EcdhePublicKey *pub;
-  const struct GNUNET_CRYPTO_EcdhePrivateKey *priv;
   const char salt[] = "CADET Axolotl salt";
   const struct GNUNET_PeerIdentity *pid;
   int am_I_alice;
@@ -2828,13 +2856,6 @@ handle_kx_ax (struct CadetTunnel *t, const struct GNUNET_CADET_AX_KX *msg)
     return;
   }
 
-  if (GNUNET_OK != GCP_check_key (t->peer, &msg->permanent_key,
-                                  &msg->purpose, &msg->signature))
-  {
-    GNUNET_break_op (0);
-    return;
-  }
-
   pid = GCT_get_destination (t);
   if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, pid))
     am_I_alice = GNUNET_YES;
@@ -2846,42 +2867,54 @@ handle_kx_ax (struct CadetTunnel *t, const struct GNUNET_CADET_AX_KX *msg)
     return;
   }
 
+  if (GNUNET_CADET_AX_KX_FLAG_FORCE_REPLY ==
+      (GNUNET_CADET_AX_KX_FLAG_FORCE_REPLY & ntohl (msg->flags)))
+    GCT_send_ax_kx (t, GNUNET_NO);
+
+  if (CADET_TUNNEL_KEY_OK == t->estate)
+    return;
+
   LOG (GNUNET_ERROR_TYPE_INFO, " is Alice? %s\n", am_I_alice ? "YES" : "NO");
 
   ax = t->ax;
   ax->DHRr = msg->ratchet_key;
-  ax->DHIr = msg->permanent_key;
 
   /* ECDH A B0 */
   if (GNUNET_YES == am_I_alice)
   {
-    priv = ax_key;                                              /* A */
-    pub = &msg->ephemeral_key;                                  /* B0 */
+    GNUNET_CRYPTO_eddsa_ecdh (id_key,              /* A */
+                              &msg->ephemeral_key,  /* B0 */
+                              &key_material[0]);
   }
   else
   {
-    priv = ax->kx_0;                                            /* B0 */
-    pub = &ax->DHIr;                                            /* A */
+    GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0,            /* B0 */
+                              &pid->public_key,    /* A */
+                              &key_material[0]);
   }
-  GNUNET_CRYPTO_ecc_ecdh (priv, pub, &key_material[0]);
 
   /* ECDH A0 B */
   if (GNUNET_YES == am_I_alice)
   {
-    priv = ax->kx_0;                                            /* A0 */
-    pub = &ax->DHIr;                                            /* B */
+    GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0,            /* A0 */
+                              &pid->public_key,    /* B */
+                              &key_material[1]);
   }
   else
   {
-    priv = ax_key;                                              /* B */
-    pub = &msg->ephemeral_key;                                  /* A0 */
+    GNUNET_CRYPTO_eddsa_ecdh (id_key,              /* A */
+                              &msg->ephemeral_key,  /* B0 */
+                              &key_material[1]);
+
+
   }
-  GNUNET_CRYPTO_ecc_ecdh (priv, pub, &key_material[1]);
 
-  /* ECDH A0 B0*/
-  priv = ax->kx_0;                                              /* A0 or B0 */
-  pub = &msg->ephemeral_key;                                    /* B0 or A0 */
-  GNUNET_CRYPTO_ecc_ecdh (priv, pub, &key_material[2]);
+  /* ECDH A0 B0 */
+  /* (This is the triple-DH, we could probably safely skip this,
+     as A0/B0 are already in the key material.) */
+  GNUNET_CRYPTO_ecc_ecdh (ax->kx_0,             /* A0 or B0 */
+                          &msg->ephemeral_key,  /* B0 or A0 */
+                          &key_material[2]);
 
   #if DUMP_KEYS_TO_STDERR
   {
@@ -3003,39 +3036,49 @@ GCT_handle_encrypted (struct CadetTunnel *t,
   size_t payload_size;
   int decrypted_size;
   uint16_t type;
-  struct GNUNET_MessageHeader *msgh;
+  const struct GNUNET_MessageHeader *msgh;
   unsigned int off;
 
   type = ntohs (msg->type);
-  if (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED == type)
+  switch (type)
   {
-    const struct GNUNET_CADET_Encrypted *emsg;
+  case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
+    {
+      const struct GNUNET_CADET_Encrypted *emsg;
 
-    emsg = (struct GNUNET_CADET_Encrypted *) msg;
-    payload_size = size - sizeof (struct GNUNET_CADET_Encrypted);
-    decrypted_size = t_decrypt_and_validate (t, cbuf, &emsg[1], payload_size,
-                                             emsg->iv, &emsg->hmac);
-  }
-  else if (GNUNET_MESSAGE_TYPE_CADET_AX == type)
-  {
-    const struct GNUNET_CADET_AX *emsg;
+      emsg = (const struct GNUNET_CADET_Encrypted *) msg;
+      payload_size = size - sizeof (struct GNUNET_CADET_Encrypted);
+      decrypted_size = t_decrypt_and_validate (t, cbuf, &emsg[1], payload_size,
+                                               emsg->iv, &emsg->hmac);
+    }
+    break;
+  case GNUNET_MESSAGE_TYPE_CADET_AX:
+    {
+      const struct GNUNET_CADET_AX *emsg;
 
-    emsg = (struct GNUNET_CADET_AX *) msg;
-    decrypted_size = t_ax_decrypt_and_validate (t, cbuf, emsg, size);
+      emsg = (const struct GNUNET_CADET_AX *) msg;
+      decrypted_size = t_ax_decrypt_and_validate (t, cbuf, emsg, size);
+    }
+    break;
+  default:
+    GNUNET_break_op (0);
+    return;
   }
-
   if (-1 == decrypted_size)
   {
     GNUNET_break_op (0);
     return;
   }
 
+  /* FIXME: this is bad, as the structs returned from
+     this loop may be unaligned, see util's MST for
+     how to do this right. */
   off = 0;
   while (off < decrypted_size)
   {
     uint16_t msize;
 
-    msgh = (struct GNUNET_MessageHeader *) &cbuf[off];
+    msgh = (const struct GNUNET_MessageHeader *) &cbuf[off];
     msize = ntohs (msgh->size);
     if (msize < sizeof (struct GNUNET_MessageHeader))
     {
@@ -3142,16 +3185,6 @@ GCT_init (const struct GNUNET_CONFIGURATION_Handle *c,
   otr_kx_msg.purpose.size = htonl (ephemeral_purpose_size ());
   otr_kx_msg.origin_identity = my_full_id;
   rekey_task = GNUNET_SCHEDULER_add_now (&global_otr_rekey, NULL);
-
-  ax_key = GNUNET_CRYPTO_ecdhe_key_create ();
-  GNUNET_CRYPTO_ecdhe_key_get_public (ax_key, &ax_identity.permanent_key);
-  ax_identity.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CADET_AXKX);
-  ax_identity.purpose.size = htonl (ax_purpose_size ());
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CRYPTO_eddsa_sign (id_key,
-                                           &ax_identity.purpose,
-                                           &ax_identity.signature));
-
   tunnels = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
 }
 
@@ -3169,7 +3202,6 @@ GCT_shutdown (void)
   }
   GNUNET_CONTAINER_multipeermap_iterate (tunnels, &destroy_iterator, NULL);
   GNUNET_CONTAINER_multipeermap_destroy (tunnels);
-  GNUNET_free (ax_key);
 }
 
 
@@ -3228,7 +3260,7 @@ GCT_change_cstate (struct CadetTunnel* t, enum CadetTunnelCState cstate)
     else if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
     {
       LOG (GNUNET_ERROR_TYPE_DEBUG, "  cstate triggered kx\n");
-      GCT_send_ax_kx (t);
+      GCT_send_ax_kx (t, GNUNET_NO);
     }
     else
     {
@@ -3622,6 +3654,9 @@ GCT_destroy (struct CadetTunnel *t)
                 GNUNET_CONTAINER_multipeermap_remove (tunnels,
                                                       GCP_get_id (t->peer), t));
 
+  while (NULL != t->tq_head)
+    unqueue_data (t->tq_head);
+
   for (iter_c = t->connection_head; NULL != iter_c; iter_c = next_c)
   {
     next_c = iter_c->next;
@@ -3846,7 +3881,7 @@ GCT_get_channels_buffer (struct CadetTunnel *t)
   {
     /* Probably getting buffer for a channel create/handshake. */
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  no channels, allow max\n");
-    return 64;
+    return MIN_TUNNEL_BUFFER;
   }
 
   buffer = 0;
@@ -3856,6 +3891,14 @@ GCT_get_channels_buffer (struct CadetTunnel *t)
     if (ch_buf > buffer)
       buffer = ch_buf;
   }
+  if (MIN_TUNNEL_BUFFER > buffer)
+    return MIN_TUNNEL_BUFFER;
+
+  if (MAX_TUNNEL_BUFFER < buffer)
+  {
+    GNUNET_break (0);
+    return MAX_TUNNEL_BUFFER;
+  }
   return buffer;
 }
 
@@ -3875,7 +3918,7 @@ GCT_get_connections_buffer (struct CadetTunnel *t)
 
   if (GNUNET_NO == is_ready (t))
   {
-    if (count_queued_data (t) > 3)
+    if (count_queued_data (t) >= 3)
       return 0;
     else
       return 1;
@@ -3967,6 +4010,9 @@ GCT_unchoke_channels (struct CadetTunnel *t)
   if (NULL != t->channel_head)
     LOG (GNUNET_ERROR_TYPE_DEBUG, " head ch: %p\n", t->channel_head->ch);
 
+  if (NULL != t->tq_head)
+    send_queued_data (t);
+
   /* Get buffer space */
   buffer = GCT_get_connections_buffer (t);
   if (0 == buffer)
@@ -4082,6 +4128,7 @@ GCT_cancel (struct CadetTunnelQueue *q)
 {
   if (NULL != q->cq)
   {
+    GNUNET_assert (NULL == q->tqd);
     GCC_cancel (q->cq);
     /* tun_message_sent() will be called and free q */
   }
@@ -4126,11 +4173,13 @@ GCT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
  * Send an Axolotl KX message.
  *
  * @param t Tunnel on which to send it.
+ * @param force_reply Force the other peer to reply with a KX message.
  */
 void
-GCT_send_ax_kx (struct CadetTunnel *t)
+GCT_send_ax_kx (struct CadetTunnel *t, int force_reply)
 {
   struct GNUNET_CADET_AX_KX msg;
+  enum GNUNET_CADET_AX_KX_Flags flags;
 
   LOG (GNUNET_ERROR_TYPE_INFO, "===> AX_KX for %s\n", GCT_2s (t));
   if (NULL != t->ephm_h)
@@ -4141,14 +4190,16 @@ GCT_send_ax_kx (struct CadetTunnel *t)
 
   msg.header.size = htons (sizeof (msg));
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_AX_KX);
-  msg.permanent_key = ax_identity.permanent_key;
-  msg.purpose = ax_identity.purpose;
-  msg.signature = ax_identity.signature;
+  flags = GNUNET_CADET_AX_KX_FLAG_NONE;
+  if (force_reply)
+    flags |= GNUNET_CADET_AX_KX_FLAG_FORCE_REPLY;
+  msg.flags = htonl (flags);
   GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->kx_0, &msg.ephemeral_key);
   GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &msg.ratchet_key);
 
   t->ephm_h = send_kx (t, &msg.header);
-  GCT_change_estate (t, CADET_TUNNEL_KEY_SENT);
+  if (CADET_TUNNEL_KEY_OK != t->estate)
+    GCT_change_estate (t, CADET_TUNNEL_KEY_SENT);
 }
 
 
@@ -4305,14 +4356,9 @@ ax_debug (const struct CadetTunnelAxolotl *ax, enum GNUNET_ErrorType level)
   LOG2 (level, "TTT  CKr\t %s\n",
         GNUNET_h2s ((struct GNUNET_HashCode *) &ax->CKr));
 
-  GNUNET_CRYPTO_ecdhe_key_get_public (ax_key, &pub);
-  LOG2 (level, "TTT  DHIs\t %s\n",
-        GNUNET_h2s ((struct GNUNET_HashCode *) &pub));
-  LOG2 (level, "TTT  DHIr\t %s\n",
-        GNUNET_h2s ((struct GNUNET_HashCode *) &ax->DHIr));
   GNUNET_CRYPTO_ecdhe_key_get_public (ax->DHRs, &pub);
   LOG2 (level, "TTT  DHRs\t %s\n",
-        GNUNET_h2s ((struct GNUNET_HashCode *) &pub));
+        GNUNET_i2s ((struct GNUNET_PeerIdentity *) &pub));
   LOG2 (level, "TTT  DHRr\t %s\n",
         GNUNET_h2s ((struct GNUNET_HashCode *) &ax->DHRr));