More client library rewrites.
[silc.git] / lib / silcclient / client_keyagr.c
index 87f13e1630cb5bb914622804524e4fc2eb0382a8..a68d94a0600f364569cbd84d7d7e14b8ad4e602d 100644 (file)
@@ -2,50 +2,67 @@
 
   client_keyagr.c
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 Pekka Riikonen
+  Copyright (C) 2001 - 2006 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
+  the Free Software Foundation; version 2 of the License.
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
 
 */
-/* $Id$ */
-/* This file includes the Key Agreement packet processing and actual
-   key agreement routines. This file has nothing to do with the actual
-   connection key exchange protocol, it is implemented in the client.c
-   and in protocol.c. This file implements the client-to-client key 
-   agreement as defined by the SILC protocol. */
-
-#include "silcincludes.h"
+
+#include "silc.h"
 #include "silcclient.h"
 #include "client_internal.h"
 
-SILC_TASK_CALLBACK(silc_client_key_agreement_final);
-SILC_TASK_CALLBACK(silc_client_process_key_agreement);
-SILC_TASK_CALLBACK(silc_client_key_agreement_timeout);
-SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start);
+/************************** Types and definitions ***************************/
 
 /* Key agreement context */
 struct SilcClientKeyAgreementStruct {
-  SilcClient client;
-  SilcClientConnection conn;
-  int fd;                                /* Listening/connection socket */
-  SilcSocketConnection sock;             /* Remote socket connection */
-  SilcClientEntry client_entry;                  /* Destination client */
+  SilcClient client;                     /* Client */
+  SilcClientConnection conn;             /* Server connection */
   SilcKeyAgreementCallback completion;   /* Key agreement completion */
   void *context;                         /* User context */
-  SilcTask timeout;                      /* Timeout task */
-  SilcClientKEInternalContext *proto_ctx; /* Key Exchange protocol context */
+
+  /* Responder */
+  SilcNetListener listener;              /* TCP listener */
+  SilcStream stream;                     /* Remote connection (TCP or UDP) */
+
+  /* Initiator */
+  SilcClientConnection client_conn;      /* Connection to remote client */
 };
 
+/************************ Static utility functions **************************/
+
+/* TCP network listener callback.  Accepts new key agreement connection */
+
+static void silc_client_tcp_accept(SilcNetStatus status,
+                                  SilcStream stream,
+                                  void *context)
+{
+  SilcClientEntry client_entry = context;
+  SilcClientKeyAgreement ke = client_entry->ke;
+
+  ke->stream = stream;
+  silc_client_process_key_agreement(ke->client, ke->conn, ke);
+}
+
+/* UDP network callback.  All UDP packets are read from here. */
+
+static void silc_client_udp_accept(SilcStream stream,
+                                  SilcStreamStatus status,
+                                  void *context)
+{
+
+}
+
+
 /* Packet sending function used by the SKE in the key agreement process. */
 
 static void silc_client_key_agreement_send_packet(SilcSKE ske,
@@ -54,7 +71,7 @@ static void silc_client_key_agreement_send_packet(SilcSKE ske,
                                                  void *context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientKEInternalContext *ctx = 
+  SilcClientKEInternalContext *ctx =
     (SilcClientKEInternalContext *)protocol->context;
   void *tmp;
 
@@ -92,7 +109,7 @@ SILC_TASK_CALLBACK(silc_client_key_agreement_close)
 SILC_TASK_CALLBACK(silc_client_key_agreement_final)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientKEInternalContext *ctx = 
+  SilcClientKEInternalContext *ctx =
     (SilcClientKEInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   SilcClientKeyAgreement ke = (SilcClientKeyAgreement)ctx->context;
@@ -103,7 +120,7 @@ SILC_TASK_CALLBACK(silc_client_key_agreement_final)
       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
     /* Error occured during protocol */
     ke->client_entry->ke = NULL;
-    ke->completion(ke->client, ke->conn, ke->client_entry, 
+    ke->completion(ke->client, ke->conn, ke->client_entry,
                   SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
     silc_ske_free_key_material(ctx->keymat);
     goto out;
@@ -112,7 +129,7 @@ SILC_TASK_CALLBACK(silc_client_key_agreement_final)
   /* Pass the negotiated key material to the application. The application
      is responsible of freeing the key material. */
   ke->client_entry->ke = NULL;
-  ke->completion(ke->client, ke->conn, ke->client_entry, 
+  ke->completion(ke->client, ke->conn, ke->client_entry,
                 SILC_KEY_AGREEMENT_OK, ctx->keymat, ke->context);
 
  out:
@@ -128,9 +145,9 @@ SILC_TASK_CALLBACK(silc_client_key_agreement_final)
     silc_schedule_task_del(client->schedule, ke->timeout);
   silc_client_del_socket(ke->client, ke->sock);
 
-  silc_schedule_task_add(client->schedule, 0, 
+  silc_schedule_task_add(client->schedule, 0,
                     silc_client_key_agreement_close,
-                    (void *)ke, 0, 1, 
+                    (void *)ke, 0, 1,
                     SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 
   silc_free(ctx);
@@ -154,10 +171,10 @@ SILC_TASK_CALLBACK(silc_client_process_key_agreement)
   sock = silc_net_accept_connection(ke->fd);
   if (sock < 0) {
     client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
-                              "Could not accept key agreement connection: ", 
+                              "Could not accept key agreement connection: ",
                               strerror(errno));
     ke->client_entry->ke = NULL;
-    ke->completion(ke->client, ke->conn, ke->client_entry, 
+    ke->completion(ke->client, ke->conn, ke->client_entry,
                   SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
     silc_schedule_task_del_by_fd(client->schedule, ke->fd);
     silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
@@ -181,10 +198,10 @@ SILC_TASK_CALLBACK(silc_client_process_key_agreement)
   /* Perform name and address lookups for the remote host. */
   silc_net_check_host_by_sock(sock, &newsocket->hostname, &newsocket->ip);
   if (!newsocket->hostname && !newsocket->ip) {
-    client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
+    client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
                               "Could not resolve the remote IP or hostname");
     ke->client_entry->ke = NULL;
-    ke->completion(ke->client, ke->conn, ke->client_entry, 
+    ke->completion(ke->client, ke->conn, ke->client_entry,
                   SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
     silc_schedule_task_del_by_fd(client->schedule, ke->fd);
     silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
@@ -213,14 +230,14 @@ SILC_TASK_CALLBACK(silc_client_process_key_agreement)
 
   /* Prepare the connection for key exchange protocol. We allocate the
      protocol but will not start it yet. The connector will be the
-     initiator of the protocol thus we will wait for initiation from 
+     initiator of the protocol thus we will wait for initiation from
      there before we start the protocol. */
-  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
-                     &newsocket->protocol, proto_ctx, 
+  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+                     &newsocket->protocol, proto_ctx,
                      silc_client_key_agreement_final);
 
   /* Register the connection for network input and output. This sets
-     that scheduler will listen for incoming packets for this connection 
+     that scheduler will listen for incoming packets for this connection
      and sets that outgoing packets may be sent to this connection as well.
      However, this doesn't set the scheduler for outgoing traffic, it
      will be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
@@ -230,7 +247,7 @@ SILC_TASK_CALLBACK(silc_client_process_key_agreement)
 }
 
 /* Timeout occured during key agreement. This means that the key agreement
-   protocol was not completed in the specified timeout. We will call the 
+   protocol was not completed in the specified timeout. We will call the
    completion callback. */
 
 SILC_TASK_CALLBACK(silc_client_key_agreement_timeout)
@@ -238,7 +255,7 @@ SILC_TASK_CALLBACK(silc_client_key_agreement_timeout)
   SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
 
   ke->client_entry->ke = NULL;
-  ke->completion(ke->client, ke->conn, ke->client_entry, 
+  ke->completion(ke->client, ke->conn, ke->client_entry,
                 SILC_KEY_AGREEMENT_TIMEOUT, NULL, ke->context);
 
   if (ke->sock) {
@@ -255,167 +272,128 @@ SILC_TASK_CALLBACK(silc_client_key_agreement_timeout)
   silc_free(ke);
 }
 
-/* Sends key agreement request to the remote client indicated by the
-   `client_entry'. If the caller provides the `hostname' and the `port'
-   arguments then the library will bind the client to that hostname and
-   that port for the key agreement protocol. It also sends the `hostname'
-   and the `port' in the key agreement packet to the remote client. This
-   would indicate that the remote client may initiate the key agreement
-   protocol to the `hostname' on the `port'.  If port is zero then the
-   bound port is undefined (the operating system defines it).
-
-   If the `hostname' and `port' is not provided then empty key agreement
-   packet is sent to the remote client. The remote client may reply with
-   the same packet including its hostname and port. If the library receives
-   the reply from the remote client the `key_agreement' client operation
-   callback will be called to verify whether the user wants to perform the
-   key agreement or not. 
-
-   NOTE: If the application provided the `hostname' and the `port' and the 
-   remote side initiates the key agreement protocol it is not verified
-   from the user anymore whether the protocol should be executed or not.
-   By setting the `hostname' and `port' the user gives permission to
-   perform the protocol (we are responder in this case).
-
-   NOTE: If the remote side decides not to initiate the key agreement
-   or decides not to reply with the key agreement packet then we cannot
-   perform the key agreement at all. If the key agreement protocol is
-   performed the `completion' callback with the `context' will be called.
-   If remote side decides to ignore the request the `completion' will be
-   called after the specified timeout, `timeout_secs'. 
-
-   NOTE: If the `hostname' and the `port' was not provided the `completion'
-   will not be called at all since this does nothing more than sending
-   a packet to the remote host.
-
-   NOTE: There can be only one active key agreement for one client entry.
-   Before setting new one, the old one must be finished (it is finished
-   after calling the completion callback) or the function 
-   silc_client_abort_key_agreement must be called. */
+/*************************** Key Agreement API ******************************/
+
+/* Sends key agreement packet to remote client.  If IP addresses are provided
+   creates also listener for íncoming key agreement connection.  Supports
+   both TCP and UDP transports. */
 
 void silc_client_send_key_agreement(SilcClient client,
                                    SilcClientConnection conn,
                                    SilcClientEntry client_entry,
-                                   const char *hostname,
-                                   const char *bindhost,
+                                   const char *local_ip,
+                                   const char *bind_ip,
                                    int port,
                                    SilcUInt32 timeout_secs,
+                                   SilcBool udp,
                                    SilcKeyAgreementCallback completion,
                                    void *context)
 {
-  SilcSocketConnection sock = conn->sock;
   SilcClientKeyAgreement ke = NULL;
+  SilcAsyncOperation op;
   SilcBuffer buffer;
+  SilcUInt16 ports = NULL;
 
-  if (!client_entry || client_entry->ke)
+  if (!client_entry)
     return;
 
-  /* Create the listener if hostname and port was provided.
-   * also, use bindhost if it was specified.
-   */
-   
-  if (hostname) {
+  if (client_entry->internal->ke) {
+    completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ALREADY_STARTED,
+              NULL, context);
+    return;
+  }
+
+  if (client_entry == conn->local_entry) {
+    completion(client, conn, client_entry, SILC_KEY_AGREEMENT_SELF_DENIED,
+              NULL, context);
+    return;
+  }
+
+  /* If local IP is provided, create listener */
+  if (local_ip || bind_ip) {
     ke = silc_calloc(1, sizeof(*ke));
-    
-    if (bindhost)
-      ke->fd = silc_net_create_server(port, bindhost);
-    else
-      ke->fd = silc_net_create_server(port, hostname);
-
-    if (ke->fd < 0) {
-      client->internal->ops->say(
-                    client, conn, SILC_CLIENT_MESSAGE_ERROR, 
-                    "Cannot create listener on %s on port %d: %s", 
-                    (bindhost) ? bindhost:hostname, port, strerror(errno));
-      completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
+    if (!ke) {
+      completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
                 NULL, context);
-      silc_free(ke);
-
       return;
     }
 
+    /* Create network listener */
+    if (udp) {
+      /* UDP listener */
+      ke->stream =
+       silc_net_udp_connect(bind_ip ? bind_ip : local_ip, port, NULL, 0,
+                            client_entry);
+      if (!ke->stream) {
+       client->internal->ops->say(
+                    client, conn, SILC_CLIENT_MESSAGE_ERROR,
+                    "Cannot create UDP listener on %s on port %d: %s",
+                    bind_ip ? bind_ip : local_ip, port, strerror(errno));
+       completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
+                  NULL, context);
+       silc_free(ke);
+       return;
+      }
+      silc_stream_set_notifier(ke->stream, conn->schedule,
+                              silc_client_udp_accept, client_entry);
+    } else {
+      /* TCP listener */
+      ke->listener =
+       silc_net_tcp_create_listener(bind_ip ? &bind_ip :
+                                    &local_ip, 1, port, FALSE,
+                                    FALSE, conn->internal->schedule,
+                                    silc_client_tcp_accept,
+                                    client_entry);
+      if (!ke->listener) {
+       client->internal->ops->say(
+                    client, conn, SILC_CLIENT_MESSAGE_ERROR,
+                    "Cannot create listener on %s on port %d: %s",
+                    bind_ip ? bind_ip : local_ip, port, strerror(errno));
+       completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
+                  NULL, context);
+       silc_free(ke);
+       return;
+      }
+    }
+
     ke->client = client;
     ke->conn = conn;
-    ke->client_entry = client_entry;
     ke->completion = completion;
     ke->context = context;
-
-    /* Add listener task to the scheduler. This task receives the key 
-       negotiations. */
-    silc_schedule_task_add(client->schedule, ke->fd,
-                          silc_client_process_key_agreement,
-                          (void *)ke, 0, 0, 
-                          SILC_TASK_FD,
-                          SILC_TASK_PRI_NORMAL);
-
-    /* Register a timeout task that will be executed if the connector
-       will not start the key exchange protocol within the specified 
-       timeout. */
-    ke->timeout = silc_schedule_task_add(client->schedule, 0, 
-                                        silc_client_key_agreement_timeout,
-                                        (void *)ke, timeout_secs, 0, 
-                                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
   }
 
-  /* Encode the key agreement payload */
-  buffer = silc_key_agreement_payload_encode(hostname, 
-                                            !ke ? port : 
-                                            silc_net_get_local_port(ke->fd));
-
-  /* Send the key agreement packet to the client */
-  silc_client_packet_send(client, sock, SILC_PACKET_KEY_AGREEMENT,
-                         client_entry->id, SILC_ID_CLIENT, NULL, NULL,
-                         buffer->data, buffer->len, FALSE);
-  silc_buffer_free(buffer);
-
-}
-
-static int 
-silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx)
-{
-  int sock;
-
-  /* Create connection to server asynchronously */
-  sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
-  if (sock < 0)
-    return -1;
-
-  /* Register task that will receive the async connect and will
-     read the result. */
-  ctx->task = silc_schedule_task_add(ctx->client->schedule, sock, 
-                                    silc_client_perform_key_agreement_start,
-                                    (void *)ctx, 0, 0, 
-                                    SILC_TASK_FD,
-                                    SILC_TASK_PRI_NORMAL);
-  silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE);
+  /* Add key agreement timeout task */
+  silc_schedule_task_add_timeout(conn->internal->schedule,
+                                silc_client_key_agreement_timeout,
+                                client_entry, timeout_secs, 0);
 
-  ctx->sock = sock;
+  /* Encode the key agreement payload */
+  if (ke && ke->listener)
+    ports = silc_net_listener_get_port(ke->listener, NULL);
+  buffer = silc_key_agreement_payload_encode(local_ip, (port ? port :
+                                                       ports ? ports[0] : 0));
+  if (!buffer) {
+    if (ke) {
+      if (ke->listener)
+       silc_net_close_listener(ke->listener);
+      silc_free(ke);
+    }
+    completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
+              NULL, context);
+    return;
+  }
+  silc_free(ports);
 
-  return sock;
-}
+  if (ke) {
+    silc_client_ref_client(client, conn, client_entry);
+    client_entry->internal.ke = ke;
+  }
 
-/* Routine used by silc_client_perform_key_agreement to create connection
-   to the remote client on specified port. */
+  /* Send the key agreement packet to the client */
+  silc_packet_send(conn->stream, SILC_PACKET_KEY_AGREEMENT, 0,
+                  silc_buffer_data(buffer), silc_buffer_len(data));
 
-static int
-silc_client_connect_to_client(SilcClient client, 
-                             SilcClientConnection conn, int port,
-                             char *host, void *context)
-{
-  SilcClientInternalConnectContext *ctx;
-
-  /* Allocate internal context for connection process. This is
-     needed as we are doing async connecting. */
-  ctx = silc_calloc(1, sizeof(*ctx));
-  ctx->client = client;
-  ctx->conn = conn;
-  ctx->host = strdup(host);
-  ctx->port = port;
-  ctx->tries = 0;
-  ctx->context = context;
-
-  /* Do the actual connecting process */
-  return silc_client_connect_to_client_internal(ctx);
+  silc_buffer_free(buffer);
 }
 
 /* Callback that is called after connection has been created. This actually
@@ -440,8 +418,8 @@ SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start)
       client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
                                 "Could not connect to client %s: %s",
                                 ctx->host, strerror(opt));
-      client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
-                                "Connecting to port %d of client %s resumed", 
+      client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+                                "Connecting to port %d of client %s resumed",
                                 ctx->port, ctx->host);
 
       /* Unregister old connection try */
@@ -464,7 +442,7 @@ SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start)
       silc_free(ctx);
 
       /* Call the completion callback */
-      ke->completion(ke->client, ke->conn, ke->client_entry, 
+      ke->completion(ke->client, ke->conn, ke->client_entry,
                     SILC_KEY_AGREEMENT_FAILURE, NULL, ke->context);
       silc_free(ke);
     }
@@ -493,7 +471,7 @@ SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start)
    The `hostname' is the remote hostname (or IP address) and the `port'
    is the remote port. The `completion' callback with the `context' will
    be called after the key agreement protocol.
-   
+
    NOTE: If the application returns TRUE in the `key_agreement' client
    operation the library will automatically start the key agreement. In this
    case the application must not call this function. However, application
@@ -517,9 +495,21 @@ void silc_client_perform_key_agreement(SilcClient client,
 
   SILC_LOG_DEBUG(("Start"));
 
-  if (!client_entry || !hostname || !port)
+  if (!client_entry)
     return;
 
+  if (!hostname || !port) {
+    completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
+              NULL, context);
+    return;
+  }
+
+  if (client_entry == conn->local_entry) {
+    completion(client, conn, client_entry, SILC_KEY_AGREEMENT_SELF_DENIED,
+              NULL, context);
+    return;
+  }
+
   ke = silc_calloc(1, sizeof(*ke));
   ke->client = client;
   ke->conn = conn;
@@ -537,8 +527,8 @@ void silc_client_perform_key_agreement(SilcClient client,
   }
 }
 
-/* Same as above but application has created already the connection to 
-   the remote host. The `sock' is the socket to the remote connection. 
+/* Same as above but application has created already the connection to
+   the remote host. The `sock' is the socket to the remote connection.
    Application can use this function if it does not want the client library
    to create the connection. */
 
@@ -559,6 +549,12 @@ void silc_client_perform_key_agreement_fd(SilcClient client,
   if (!client_entry)
     return;
 
+  if (client_entry == conn->local_entry) {
+    completion(client, conn, client_entry, SILC_KEY_AGREEMENT_SELF_DENIED,
+              NULL, context);
+    return;
+  }
+
   ke = silc_calloc(1, sizeof(*ke));
   ke->client = client;
   ke->conn = conn;
@@ -586,15 +582,15 @@ void silc_client_perform_key_agreement_fd(SilcClient client,
   ke->proto_ctx = proto_ctx;
 
   /* Perform key exchange protocol. */
-  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
+  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
                      &protocol, (void *)proto_ctx,
                      silc_client_key_agreement_final);
   ke->sock->protocol = protocol;
 
   /* Register the connection for network input and output. This sets
-     that scheduler will listen for incoming packets for this connection 
+     that scheduler will listen for incoming packets for this connection
      and sets that outgoing packets may be sent to this connection as well.
-     However, this doesn't set the scheduler for outgoing traffic, it will 
+     However, this doesn't set the scheduler for outgoing traffic, it will
      be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
      later when outgoing data is available. */
   context = (void *)client;
@@ -605,10 +601,10 @@ void silc_client_perform_key_agreement_fd(SilcClient client,
 }
 
 /* This function can be called to unbind the hostname and the port for
-   the key agreement protocol. However, this function has effect only 
+   the key agreement protocol. However, this function has effect only
    before the key agreement protocol has been performed. After it has
-   been performed the library will automatically unbind the port. The 
-   `client_entry' is the client to which we sent the key agreement 
+   been performed the library will automatically unbind the port. The
+   `client_entry' is the client to which we sent the key agreement
    request. */
 
 void silc_client_abort_key_agreement(SilcClient client,
@@ -627,21 +623,21 @@ void silc_client_abort_key_agreement(SilcClient client,
     }
     silc_schedule_task_del_by_fd(client->schedule, client_entry->ke->fd);
     if (client_entry->ke->timeout)
-      silc_schedule_task_del(client->schedule, 
+      silc_schedule_task_del(client->schedule,
                             client_entry->ke->timeout);
     ke = client_entry->ke;
     client_entry->ke = NULL;
-    ke->completion(client, conn, client_entry, 
+    ke->completion(client, conn, client_entry,
                   SILC_KEY_AGREEMENT_ABORTED, NULL, ke->context);
     silc_free(ke);
   }
 }
 
-/* Callback function that is called after we've resolved the client 
+/* Callback function that is called after we've resolved the client
    information who sent us the key agreement packet from the server.
    We actually call the key_agreement client operation now. */
 
-static void 
+static void
 silc_client_key_agreement_resolve_cb(SilcClient client,
                                     SilcClientConnection conn,
                                     SilcClientEntry *clients,
@@ -665,7 +661,7 @@ silc_client_key_agreement_resolve_cb(SilcClient client,
 
   /* Call the key_agreement client operation */
   ret = client->internal->ops->key_agreement(
-                                  client, conn, clients[0], 
+                                  client, conn, clients[0],
                                   silc_key_agreement_get_hostname(payload),
                                   silc_key_agreement_get_port(payload),
                                   &completion, &completion_context);
@@ -686,7 +682,7 @@ silc_client_key_agreement_resolve_cb(SilcClient client,
 
 /* Received Key Agreement packet from remote client. Process the packet
    and resolve the client information from the server before actually
-   letting the application know that we've received this packet.  Then 
+   letting the application know that we've received this packet.  Then
    call the key_agreement client operation and let the user decide
    whether we perform the key agreement protocol now or not. */
 
@@ -699,12 +695,13 @@ void silc_client_key_agreement(SilcClient client,
   if (packet->src_id_type != SILC_ID_CLIENT)
     return;
 
-  remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
+  remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
                             SILC_ID_CLIENT);
   if (!remote_id)
     return;
 
   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
+                                      NULL,
                                       silc_client_key_agreement_resolve_cb,
                                       silc_packet_context_dup(packet));
   silc_free(remote_id);