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