updates.
[silc.git] / lib / silcclient / client_keyagr.c
1 /*
2
3   client_keyagr.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 2001 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21 /* This file includes the Key Agreement packet processing and actual
22    key agreement routines. This file has nothing to do with the actual
23    connection key exchange protocol, it is implemented in the client.c
24    and in protocol.c. This file implements the client-to-client key 
25    agreement as defined by the SILC protocol. */
26
27 #include "clientlibincludes.h"
28 #include "client_internal.h"
29
30 SILC_TASK_CALLBACK(silc_client_key_agreement_final);
31 SILC_TASK_CALLBACK(silc_client_process_key_agreement);
32 SILC_TASK_CALLBACK(silc_client_key_agreement_timeout);
33 SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start);
34
35 /* Key agreement context */
36 struct SilcClientKeyAgreementStruct {
37   SilcClient client;
38   SilcClientConnection conn;
39   int fd;                                 /* Listening/connection socket */
40   SilcSocketConnection sock;              /* Remote socket connection */
41   SilcClientEntry client_entry;           /* Destination client */
42   SilcKeyAgreementCallback completion;    /* Key agreement completion */
43   void *context;                          /* User context */
44   SilcTask timeout;                       /* Timeout task */
45   SilcClientKEInternalContext *proto_ctx; /* Key Exchange protocol context */
46 };
47
48 /* Packet sending function used by the SKE in the key agreement process. */
49
50 static void silc_client_key_agreement_send_packet(SilcSKE ske,
51                                                   SilcBuffer packet,
52                                                   SilcPacketType type,
53                                                   void *context)
54 {
55   SilcProtocol protocol = (SilcProtocol)context;
56   SilcClientKEInternalContext *ctx = 
57     (SilcClientKEInternalContext *)protocol->context;
58   void *tmp;
59
60   /* Send the packet immediately. We will assure that the packet is not
61      encrypted by setting the socket's user_data pointer to NULL. The
62      silc_client_packet_send would take the keys (wrong keys that is,
63      because user_data is the current SilcClientConnection) from it and
64      we cannot allow that. The packets are never encrypted when doing SKE
65      with another client. */
66   tmp = ske->sock->user_data;
67   ske->sock->user_data = NULL;
68   silc_client_packet_send(ctx->client, ske->sock, type, NULL, 0, NULL, NULL,
69                           packet->data, packet->len, TRUE);
70   ske->sock->user_data = tmp;
71 }
72
73 /* Timeout callback that is called to close the connection and free the
74    socket connection data. */
75
76 SILC_TASK_CALLBACK(silc_client_key_agreement_close)
77 {
78   SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
79
80   silc_schedule_unset_listen_fd(ke->client->schedule, ke->sock->sock);
81   silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
82   silc_net_close_connection(ke->sock->sock);
83   silc_net_close_connection(ke->fd);
84   silc_socket_free(ke->sock);
85   silc_free(ke);
86 }
87
88 /* This callback is called after the key agreement protocol has been
89    performed. This calls the final completion callback for the application. */
90
91 SILC_TASK_CALLBACK(silc_client_key_agreement_final)
92 {
93   SilcProtocol protocol = (SilcProtocol)context;
94   SilcClientKEInternalContext *ctx = 
95     (SilcClientKEInternalContext *)protocol->context;
96   SilcClient client = (SilcClient)ctx->client;
97   SilcClientKeyAgreement ke = (SilcClientKeyAgreement)ctx->context;
98
99   SILC_LOG_DEBUG(("Start"));
100
101   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
102       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
103     /* Error occured during protocol */
104     ke->client_entry->ke = NULL;
105     ke->completion(ke->client, ke->conn, ke->client_entry, 
106                    SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
107     silc_ske_free_key_material(ctx->keymat);
108     goto out;
109   }
110
111   /* Pass the negotiated key material to the application. The application
112      is responsible of freeing the key material. */
113   ke->client_entry->ke = NULL;
114   ke->completion(ke->client, ke->conn, ke->client_entry, 
115                  SILC_KEY_AGREEMENT_OK, ctx->keymat, ke->context);
116
117  out:
118   silc_protocol_free(protocol);
119   if (ctx->ske)
120     silc_ske_free(ctx->ske);
121   if (ctx->dest_id)
122     silc_free(ctx->dest_id);
123   silc_task_unregister_by_fd(client->io_queue, ke->fd);
124   silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
125   silc_net_close_connection(ke->fd);
126   if (ke->timeout)
127     silc_task_unregister(client->timeout_queue, ke->timeout);
128   silc_client_del_socket(ke->client, ke->sock);
129
130   silc_task_register(client->timeout_queue, 0, 
131                      silc_client_key_agreement_close,
132                      (void *)ke, 0, 1, 
133                      SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
134
135   silc_free(ctx);
136 }
137
138 /* Key agreement callback that is called when remote end has initiated
139    the key agreement protocol. This accepts the incoming TCP/IP connection
140    for the key agreement protocol. */
141
142 SILC_TASK_CALLBACK(silc_client_process_key_agreement)
143 {
144   SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
145   SilcClient client = ke->client;
146   SilcClientConnection conn = ke->conn;
147   SilcSocketConnection newsocket;
148   SilcClientKEInternalContext *proto_ctx;
149   int sock;
150
151   SILC_LOG_DEBUG(("Start"));
152
153   sock = silc_net_accept_connection(ke->fd);
154   if (sock < 0) {
155     client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
156                      "Could not accept key agreement connection: ", 
157                      strerror(errno));
158     ke->client_entry->ke = NULL;
159     ke->completion(ke->client, ke->conn, ke->client_entry, 
160                    SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
161     silc_task_unregister_by_fd(client->io_queue, ke->fd);
162     silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
163     silc_net_close_connection(ke->fd);
164     if (ke->timeout)
165       silc_task_unregister(client->timeout_queue, ke->timeout);
166     silc_free(ke);
167     return;
168   }
169
170   /* Set socket options */
171   silc_net_set_socket_nonblock(sock);
172   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
173
174   /* Create socket for this connection (it is of type UNKNOWN since this
175      really is not a real SILC connection. It is only for the key
176      agreement protocol). */
177   silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, (void *)conn, &newsocket);
178   ke->sock = newsocket;
179
180   /* Perform name and address lookups for the remote host. */
181   silc_net_check_host_by_sock(sock, &newsocket->hostname, &newsocket->ip);
182   if (!newsocket->hostname && !newsocket->ip) {
183     client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
184                      "Could not resolve the remote IP or hostname");
185     ke->client_entry->ke = NULL;
186     ke->completion(ke->client, ke->conn, ke->client_entry, 
187                    SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
188     silc_task_unregister_by_fd(client->io_queue, ke->fd);
189     silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
190     silc_net_close_connection(ke->fd);
191     if (ke->timeout)
192       silc_task_unregister(client->timeout_queue, ke->timeout);
193     silc_free(ke);
194     return;
195   }
196   if (!newsocket->hostname)
197     newsocket->hostname = strdup(newsocket->ip);
198   newsocket->port = silc_net_get_remote_port(sock);
199   silc_client_add_socket(client, newsocket);
200
201   /* Allocate internal context for key exchange protocol. This is
202      sent as context for the protocol. */
203   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
204   proto_ctx->client = client;
205   proto_ctx->sock = silc_socket_dup(newsocket);
206   proto_ctx->rng = client->rng;
207   proto_ctx->responder = TRUE;
208   proto_ctx->context = context;
209   proto_ctx->send_packet = silc_client_key_agreement_send_packet;
210   proto_ctx->verify = silc_client_protocol_ke_verify_key;
211   ke->proto_ctx = proto_ctx;
212
213   /* Prepare the connection for key exchange protocol. We allocate the
214      protocol but will not start it yet. The connector will be the
215      initiator of the protocol thus we will wait for initiation from 
216      there before we start the protocol. */
217   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
218                       &newsocket->protocol, proto_ctx, 
219                       silc_client_key_agreement_final);
220
221   /* Register the connection for network input and output. This sets
222      that scheduler will listen for incoming packets for this connection 
223      and sets that outgoing packets may be sent to this connection as well.
224      However, this doesn't set the scheduler for outgoing traffic, it
225      will be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
226      later when outgoing data is available. */
227   context = (void *)client;
228   SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
229 }
230
231 /* Timeout occured during key agreement. This means that the key agreement
232    protocol was not completed in the specified timeout. We will call the 
233    completion callback. */
234
235 SILC_TASK_CALLBACK(silc_client_key_agreement_timeout)
236 {
237   SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
238
239   ke->client_entry->ke = NULL;
240   ke->completion(ke->client, ke->conn, ke->client_entry, 
241                  SILC_KEY_AGREEMENT_TIMEOUT, NULL, ke->context);
242
243   if (ke->sock) {
244     silc_client_del_socket(ke->client, ke->sock);
245     silc_socket_free(ke->sock);
246   }
247   if (ke->proto_ctx && ke->proto_ctx->ske)
248     silc_ske_free(ke->proto_ctx->ske);
249   ke->client_entry->ke = NULL;
250   if (ke->fd)
251     silc_task_unregister_by_fd(ke->client->io_queue, ke->fd);
252   silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
253   silc_net_close_connection(ke->fd);
254   silc_free(ke);
255 }
256
257 /* Sends key agreement request to the remote client indicated by the
258    `client_entry'. If the caller provides the `hostname' and the `port'
259    arguments then the library will bind the client to that hostname and
260    that port for the key agreement protocol. It also sends the `hostname'
261    and the `port' in the key agreement packet to the remote client. This
262    would indicate that the remote client may initiate the key agreement
263    protocol to the `hostname' on the `port'.  If port is zero then the
264    bound port is undefined (the operating system defines it).
265
266    If the `hostname' and `port' is not provided then empty key agreement
267    packet is sent to the remote client. The remote client may reply with
268    the same packet including its hostname and port. If the library receives
269    the reply from the remote client the `key_agreement' client operation
270    callback will be called to verify whether the user wants to perform the
271    key agreement or not. 
272
273    NOTE: If the application provided the `hostname' and the `port' and the 
274    remote side initiates the key agreement protocol it is not verified
275    from the user anymore whether the protocol should be executed or not.
276    By setting the `hostname' and `port' the user gives permission to
277    perform the protocol (we are responder in this case).
278
279    NOTE: If the remote side decides not to initiate the key agreement
280    or decides not to reply with the key agreement packet then we cannot
281    perform the key agreement at all. If the key agreement protocol is
282    performed the `completion' callback with the `context' will be called.
283    If remote side decides to ignore the request the `completion' will be
284    called after the specified timeout, `timeout_secs'. 
285
286    NOTE: If the `hostname' and the `port' was not provided the `completion'
287    will not be called at all since this does nothing more than sending
288    a packet to the remote host.
289
290    NOTE: There can be only one active key agreement for one client entry.
291    Before setting new one, the old one must be finished (it is finished
292    after calling the completion callback) or the function 
293    silc_client_abort_key_agreement must be called. */
294
295 void silc_client_send_key_agreement(SilcClient client,
296                                     SilcClientConnection conn,
297                                     SilcClientEntry client_entry,
298                                     char *hostname,
299                                     int port,
300                                     uint32 timeout_secs,
301                                     SilcKeyAgreementCallback completion,
302                                     void *context)
303 {
304   SilcSocketConnection sock = conn->sock;
305   SilcClientKeyAgreement ke = NULL;
306   SilcBuffer buffer;
307
308   assert(client_entry);
309
310   if (client_entry->ke)
311     return;
312
313   /* Create the listener if hostname and port was provided */
314   if (hostname) {
315     ke = silc_calloc(1, sizeof(*ke));
316     ke->fd = silc_net_create_server(port, hostname);
317
318     if (ke->fd < 0) {
319       client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR, 
320                        "Cannot create listener on %s on port %d: %s", 
321                        hostname, port, strerror(errno));
322       completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
323                  NULL, context);
324       silc_free(ke);
325       return;
326     }
327
328     ke->client = client;
329     ke->conn = conn;
330     ke->client_entry = client_entry;
331     ke->completion = completion;
332     ke->context = context;
333
334     /* Add listener task to the queue. This task receives the key 
335        negotiations. */
336     silc_task_register(client->io_queue, ke->fd,
337                        silc_client_process_key_agreement,
338                        (void *)ke, 0, 0, 
339                        SILC_TASK_FD,
340                        SILC_TASK_PRI_NORMAL);
341
342     /* Register a timeout task that will be executed if the connector
343        will not start the key exchange protocol within the specified 
344        timeout. */
345     ke->timeout = silc_task_register(client->timeout_queue, 0, 
346                                      silc_client_key_agreement_timeout,
347                                      (void *)ke, timeout_secs, 0, 
348                                      SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
349   }
350
351   /* Encode the key agreement payload */
352   buffer = silc_key_agreement_payload_encode(hostname, 
353                                              !ke ? port : 
354                                              silc_net_get_local_port(ke->fd));
355
356   /* Send the key agreement packet to the client */
357   silc_client_packet_send(client, sock, SILC_PACKET_KEY_AGREEMENT,
358                           client_entry->id, SILC_ID_CLIENT, NULL, NULL,
359                           buffer->data, buffer->len, FALSE);
360   silc_free(buffer);
361 }
362
363 static int 
364 silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx)
365 {
366   int sock;
367
368   /* Create connection to server asynchronously */
369   sock = silc_net_create_connection_async(ctx->port, ctx->host);
370   if (sock < 0)
371     return -1;
372
373   /* Register task that will receive the async connect and will
374      read the result. */
375   ctx->task = silc_task_register(ctx->client->io_queue, sock, 
376                                  silc_client_perform_key_agreement_start,
377                                  (void *)ctx, 0, 0, 
378                                  SILC_TASK_FD,
379                                  SILC_TASK_PRI_NORMAL);
380   silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
381   silc_schedule_set_listen_fd(ctx->client->schedule, sock, ctx->task->iomask);
382
383   ctx->sock = sock;
384
385   return sock;
386 }
387
388 /* Routine used by silc_client_perform_key_agreement to create connection
389    to the remote client on specified port. */
390
391 static int
392 silc_client_connect_to_client(SilcClient client, 
393                               SilcClientConnection conn, int port,
394                               char *host, void *context)
395 {
396   SilcClientInternalConnectContext *ctx;
397
398   /* Allocate internal context for connection process. This is
399      needed as we are doing async connecting. */
400   ctx = silc_calloc(1, sizeof(*ctx));
401   ctx->client = client;
402   ctx->conn = conn;
403   ctx->host = strdup(host);
404   ctx->port = port;
405   ctx->tries = 0;
406   ctx->context = context;
407
408   /* Do the actual connecting process */
409   return silc_client_connect_to_client_internal(ctx);
410 }
411
412 /* Callback that is called after connection has been created. This actually
413    starts the key agreement protocol. This is initiator function. */
414
415 SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start)
416 {
417   SilcClientInternalConnectContext *ctx =
418     (SilcClientInternalConnectContext *)context;
419   SilcClient client = ctx->client;
420   SilcClientConnection conn = ctx->conn;
421   SilcClientKeyAgreement ke = (SilcClientKeyAgreement)ctx->context;
422   int opt, opt_len = sizeof(opt);
423
424   SILC_LOG_DEBUG(("Start"));
425
426   /* Check the socket status as it might be in error */
427   silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
428   if (opt != 0) {
429     if (ctx->tries < 2) {
430       /* Connection failed but lets try again */
431       client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
432                        "Could not connect to client %s: %s",
433                        ctx->host, strerror(opt));
434       client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
435                        "Connecting to port %d of client %s resumed", 
436                        ctx->port, ctx->host);
437
438       /* Unregister old connection try */
439       silc_schedule_unset_listen_fd(client->schedule, fd);
440       silc_net_close_connection(fd);
441       silc_task_unregister(client->io_queue, ctx->task);
442
443       /* Try again */
444       silc_client_connect_to_client_internal(ctx);
445       ctx->tries++;
446     } else {
447       /* Connection failed and we won't try anymore */
448       client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
449                        "Could not connect to client %s: %s",
450                        ctx->host, strerror(opt));
451       silc_schedule_unset_listen_fd(client->schedule, fd);
452       silc_net_close_connection(fd);
453       silc_task_unregister(client->io_queue, ctx->task);
454       silc_free(ctx->host);
455       silc_free(ctx);
456
457       /* Call the completion callback */
458       ke->completion(ke->client, ke->conn, ke->client_entry, 
459                      SILC_KEY_AGREEMENT_FAILURE, NULL, ke->context);
460       silc_free(ke);
461     }
462     return;
463   }
464
465   silc_schedule_unset_listen_fd(client->schedule, fd);
466   silc_task_unregister(client->io_queue, ctx->task);
467
468   ke->fd = fd;
469
470   /* Now actually perform the key agreement protocol */
471   silc_client_perform_key_agreement_fd(ke->client, ke->conn,
472                                        ke->client_entry, ke->fd, ctx->host,
473                                        ke->completion, ke->context);
474   silc_free(ke);
475   silc_free(ctx->host);
476   silc_free(ctx);
477 }
478
479 /* Performs the actual key agreement protocol. Application may use this
480    to initiate the key agreement protocol. This can be called for example
481    after the application has received the `key_agreement' client operation,
482    and did not return TRUE from it.
483
484    The `hostname' is the remote hostname (or IP address) and the `port'
485    is the remote port. The `completion' callback with the `context' will
486    be called after the key agreement protocol.
487    
488    NOTE: If the application returns TRUE in the `key_agreement' client
489    operation the library will automatically start the key agreement. In this
490    case the application must not call this function. However, application
491    may choose to just ignore the `key_agreement' client operation (and
492    merely just print information about it on the screen) and call this
493    function when the user whishes to do so (by, for example, giving some
494    specific command). Thus, the API provides both, automatic and manual
495    initiation of the key agreement. Calling this function is the manual
496    initiation and returning TRUE in the `key_agreement' client operation
497    is the automatic initiation. */
498
499 void silc_client_perform_key_agreement(SilcClient client,
500                                        SilcClientConnection conn,
501                                        SilcClientEntry client_entry,
502                                        char *hostname,
503                                        int port,
504                                        SilcKeyAgreementCallback completion,
505                                        void *context)
506 {
507   SilcClientKeyAgreement ke;
508
509   SILC_LOG_DEBUG(("Start"));
510
511   assert(client_entry && hostname && port);
512
513   ke = silc_calloc(1, sizeof(*ke));
514   ke->client = client;
515   ke->conn = conn;
516   ke->client_entry = client_entry;
517   ke->completion = completion;
518   ke->context = context;
519
520   /* Connect to the remote client */
521   ke->fd = silc_client_connect_to_client(client, conn, port, hostname, ke);
522   if (ke->fd < 0) {
523     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
524                NULL, context);
525     silc_free(ke);
526     return;
527   }
528 }
529
530 /* Same as above but application has created already the connection to 
531    the remote host. The `sock' is the socket to the remote connection. 
532    Application can use this function if it does not want the client library
533    to create the connection. */
534
535 void silc_client_perform_key_agreement_fd(SilcClient client,
536                                           SilcClientConnection conn,
537                                           SilcClientEntry client_entry,
538                                           int sock,
539                                           char *hostname,
540                                           SilcKeyAgreementCallback completion,
541                                           void *context)
542 {
543   SilcClientKeyAgreement ke;
544   SilcClientKEInternalContext *proto_ctx;
545   SilcProtocol protocol;
546
547   SILC_LOG_DEBUG(("Start"));
548
549   assert(client_entry);
550
551   ke = silc_calloc(1, sizeof(*ke));
552   ke->client = client;
553   ke->conn = conn;
554   ke->client_entry = client_entry;
555   ke->fd = sock;
556   ke->completion = completion;
557   ke->context = context;
558
559   /* Allocate new socket connection object */
560   silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, (void *)conn, &ke->sock);
561   silc_client_add_socket(client, ke->sock);
562   ke->sock->hostname = strdup(hostname);
563   ke->sock->port = silc_net_get_remote_port(sock);
564
565   /* Allocate internal context for key exchange protocol. This is
566      sent as context for the protocol. */
567   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
568   proto_ctx->client = client;
569   proto_ctx->sock = silc_socket_dup(ke->sock);
570   proto_ctx->rng = client->rng;
571   proto_ctx->responder = FALSE;
572   proto_ctx->context = ke;
573   proto_ctx->send_packet = silc_client_key_agreement_send_packet;
574   proto_ctx->verify = silc_client_protocol_ke_verify_key;
575   ke->proto_ctx = proto_ctx;
576
577   /* Perform key exchange protocol. */
578   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
579                       &protocol, (void *)proto_ctx,
580                       silc_client_key_agreement_final);
581   ke->sock->protocol = protocol;
582
583   /* Register the connection for network input and output. This sets
584      that scheduler will listen for incoming packets for this connection 
585      and sets that outgoing packets may be sent to this connection as well.
586      However, this doesn't set the scheduler for outgoing traffic, it will 
587      be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
588      later when outgoing data is available. */
589   context = (void *)client;
590   SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
591
592   /* Execute the protocol */
593   silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
594 }
595
596 /* This function can be called to unbind the hostname and the port for
597    the key agreement protocol. However, this function has effect only 
598    before the key agreement protocol has been performed. After it has
599    been performed the library will automatically unbind the port. The 
600    `client_entry' is the client to which we sent the key agreement 
601    request. */
602
603 void silc_client_abort_key_agreement(SilcClient client,
604                                      SilcClientConnection conn,
605                                      SilcClientEntry client_entry)
606 {
607   assert(client_entry);
608
609   if (client_entry->ke) {
610     if (client_entry->ke->sock) {
611       silc_client_del_socket(client_entry->ke->client, client_entry->ke->sock);
612       silc_socket_free(client_entry->ke->sock);
613     }
614     client_entry->ke = NULL;
615     silc_task_unregister_by_fd(client->io_queue, client_entry->ke->fd);
616     if (client_entry->ke->timeout)
617       silc_task_unregister(client->timeout_queue, 
618                            client_entry->ke->timeout);
619     silc_free(client_entry->ke);
620   }
621 }
622
623 /* Callback function that is called after we've resolved the client 
624    information who sent us the key agreement packet from the server.
625    We actually call the key_agreement client operation now. */
626
627 static void 
628 silc_client_key_agreement_resolve_cb(SilcClient client,
629                                      SilcClientConnection conn,
630                                      SilcClientEntry *clients,
631                                      uint32 clients_count,
632                                      void *context)
633 {
634   SilcPacketContext *packet = (SilcPacketContext *)context;
635   SilcKeyAgreementPayload payload;
636   int ret;
637   SilcKeyAgreementCallback completion;
638   void *completion_context;
639
640   if (!clients)
641     goto out;
642
643   /* Parse the key agreement payload */
644   payload = silc_key_agreement_payload_parse(packet->buffer);
645   if (!payload)
646     goto out;
647
648   /* Call the key_agreement client operation */
649   ret = client->ops->key_agreement(client, conn, clients[0], 
650                                    silc_key_agreement_get_hostname(payload),
651                                    silc_key_agreement_get_port(payload),
652                                    &completion, &completion_context);
653
654   /* If the user returned TRUE then we'll start the key agreement right
655      here and right now. */
656   if (ret == TRUE)
657     silc_client_perform_key_agreement(client, conn, clients[0],
658                                       silc_key_agreement_get_hostname(payload),
659                                       silc_key_agreement_get_port(payload),
660                                       completion, completion_context);
661
662   silc_key_agreement_payload_free(payload);
663
664  out:
665   silc_packet_context_free(packet);
666 }
667
668 /* Received Key Agreement packet from remote client. Process the packet
669    and resolve the client information from the server before actually
670    letting the application know that we've received this packet.  Then 
671    call the key_agreement client operation and let the user decide
672    whether we perform the key agreement protocol now or not. */
673
674 void silc_client_key_agreement(SilcClient client,
675                                SilcSocketConnection sock,
676                                SilcPacketContext *packet)
677 {
678   SilcClientID *remote_id;
679
680   if (packet->src_id_type != SILC_ID_CLIENT)
681     return;
682
683   remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
684                              SILC_ID_CLIENT);
685   if (!remote_id)
686     return;
687
688   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
689                                        silc_client_key_agreement_resolve_cb,
690                                        silc_packet_context_dup(packet));
691   silc_free(remote_id);
692 }