Added SILC Server library.
[silc.git] / lib / silcclient / client_keyagr.c
1 /*
2
3   client_keyagr.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2001 - 2005 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20 /* This file includes the Key Agreement packet processing and actual
21    key agreement routines. This file has nothing to do with the actual
22    connection key exchange protocol, it is implemented in the client.c
23    and in protocol.c. This file implements the client-to-client key
24    agreement as defined by the SILC protocol. */
25
26 #include "silc.h"
27 #include "silcclient.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_schedule_task_del_by_fd(client->schedule, 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_schedule_task_del(client->schedule, ke->timeout);
128   silc_client_del_socket(ke->client, ke->sock);
129
130   silc_schedule_task_add(client->schedule, 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->internal->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_schedule_task_del_by_fd(client->schedule, 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_schedule_task_del(client->schedule, 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->internal->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_schedule_task_del_by_fd(client->schedule, 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_schedule_task_del(client->schedule, 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_schedule_task_del_by_fd(ke->client->schedule, 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                                     const char *hostname,
299                                     const char *bindhost,
300                                     int port,
301                                     SilcUInt32 timeout_secs,
302                                     SilcKeyAgreementCallback completion,
303                                     void *context)
304 {
305   SilcSocketConnection sock = conn->sock;
306   SilcClientKeyAgreement ke = NULL;
307   SilcBuffer buffer;
308
309   if (!client_entry)
310     return;
311
312   if (client_entry->ke) {
313     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ALREADY_STARTED,
314                NULL, context);
315     return;
316   }
317
318   if (client_entry == conn->local_entry) {
319     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_SELF_DENIED,
320                NULL, context);
321     return;
322   }
323
324   /* Create the listener if hostname and port was provided.
325    * also, use bindhost if it was specified.
326    */
327
328   if (hostname) {
329     ke = silc_calloc(1, sizeof(*ke));
330
331     if (bindhost)
332       ke->fd = silc_net_create_server(port, bindhost);
333     else
334       ke->fd = silc_net_create_server(port, hostname);
335
336     if (ke->fd < 0) {
337       client->internal->ops->say(
338                      client, conn, SILC_CLIENT_MESSAGE_ERROR,
339                      "Cannot create listener on %s on port %d: %s",
340                      (bindhost) ? bindhost:hostname, port, strerror(errno));
341       completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
342                  NULL, context);
343       silc_free(ke);
344       return;
345     }
346
347     ke->client = client;
348     ke->conn = conn;
349     ke->client_entry = client_entry;
350     ke->completion = completion;
351     ke->context = context;
352
353     /* Add listener task to the scheduler. This task receives the key
354        negotiations. */
355     silc_schedule_task_add(client->schedule, ke->fd,
356                            silc_client_process_key_agreement,
357                            (void *)ke, 0, 0,
358                            SILC_TASK_FD,
359                            SILC_TASK_PRI_NORMAL);
360
361     /* Register a timeout task that will be executed if the connector
362        will not start the key exchange protocol within the specified
363        timeout. */
364     ke->timeout = silc_schedule_task_add(client->schedule, 0,
365                                          silc_client_key_agreement_timeout,
366                                          (void *)ke, timeout_secs, 0,
367                                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
368   }
369
370   /* Encode the key agreement payload */
371   buffer = silc_key_agreement_payload_encode(hostname,
372                                              !ke ? port :
373                                              silc_net_get_local_port(ke->fd));
374
375   /* Send the key agreement packet to the client */
376   silc_client_packet_send(client, sock, SILC_PACKET_KEY_AGREEMENT,
377                           client_entry->id, SILC_ID_CLIENT, NULL, NULL,
378                           buffer->data, buffer->len, FALSE);
379   silc_buffer_free(buffer);
380 }
381
382 static int
383 silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx)
384 {
385   int sock;
386
387   /* Create connection to server asynchronously */
388   sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
389   if (sock < 0)
390     return -1;
391
392   /* Register task that will receive the async connect and will
393      read the result. */
394   ctx->task = silc_schedule_task_add(ctx->client->schedule, sock,
395                                      silc_client_perform_key_agreement_start,
396                                      (void *)ctx, 0, 0,
397                                      SILC_TASK_FD,
398                                      SILC_TASK_PRI_NORMAL);
399   silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE,
400                               FALSE);
401
402   ctx->sock = sock;
403
404   return sock;
405 }
406
407 /* Routine used by silc_client_perform_key_agreement to create connection
408    to the remote client on specified port. */
409
410 static int
411 silc_client_connect_to_client(SilcClient client,
412                               SilcClientConnection conn, int port,
413                               char *host, void *context)
414 {
415   SilcClientInternalConnectContext *ctx;
416
417   /* Allocate internal context for connection process. This is
418      needed as we are doing async connecting. */
419   ctx = silc_calloc(1, sizeof(*ctx));
420   ctx->client = client;
421   ctx->conn = conn;
422   ctx->host = strdup(host);
423   ctx->port = port;
424   ctx->tries = 0;
425   ctx->context = context;
426
427   /* Do the actual connecting process */
428   return silc_client_connect_to_client_internal(ctx);
429 }
430
431 /* Callback that is called after connection has been created. This actually
432    starts the key agreement protocol. This is initiator function. */
433
434 SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start)
435 {
436   SilcClientInternalConnectContext *ctx =
437     (SilcClientInternalConnectContext *)context;
438   SilcClient client = ctx->client;
439   SilcClientConnection conn = ctx->conn;
440   SilcClientKeyAgreement ke = (SilcClientKeyAgreement)ctx->context;
441   int opt, opt_len = sizeof(opt);
442
443   SILC_LOG_DEBUG(("Start"));
444
445   /* Check the socket status as it might be in error */
446   silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
447   if (opt != 0) {
448     if (ctx->tries < 2) {
449       /* Connection failed but lets try again */
450       client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
451                                  "Could not connect to client %s: %s",
452                                  ctx->host, strerror(opt));
453       client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
454                                  "Connecting to port %d of client %s resumed",
455                                  ctx->port, ctx->host);
456
457       /* Unregister old connection try */
458       silc_schedule_unset_listen_fd(client->schedule, fd);
459       silc_net_close_connection(fd);
460       silc_schedule_task_del(client->schedule, ctx->task);
461
462       /* Try again */
463       silc_client_connect_to_client_internal(ctx);
464       ctx->tries++;
465     } else {
466       /* Connection failed and we won't try anymore */
467       client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
468                                  "Could not connect to client %s: %s",
469                                  ctx->host, strerror(opt));
470       silc_schedule_unset_listen_fd(client->schedule, fd);
471       silc_net_close_connection(fd);
472       silc_schedule_task_del(client->schedule, ctx->task);
473       silc_free(ctx->host);
474       silc_free(ctx);
475
476       /* Call the completion callback */
477       ke->completion(ke->client, ke->conn, ke->client_entry,
478                      SILC_KEY_AGREEMENT_FAILURE, NULL, ke->context);
479       silc_free(ke);
480     }
481     return;
482   }
483
484   silc_schedule_unset_listen_fd(client->schedule, fd);
485   silc_schedule_task_del(client->schedule, ctx->task);
486
487   ke->fd = fd;
488
489   /* Now actually perform the key agreement protocol */
490   silc_client_perform_key_agreement_fd(ke->client, ke->conn,
491                                        ke->client_entry, ke->fd, ctx->host,
492                                        ke->completion, ke->context);
493   silc_free(ke);
494   silc_free(ctx->host);
495   silc_free(ctx);
496 }
497
498 /* Performs the actual key agreement protocol. Application may use this
499    to initiate the key agreement protocol. This can be called for example
500    after the application has received the `key_agreement' client operation,
501    and did not return TRUE from it.
502
503    The `hostname' is the remote hostname (or IP address) and the `port'
504    is the remote port. The `completion' callback with the `context' will
505    be called after the key agreement protocol.
506
507    NOTE: If the application returns TRUE in the `key_agreement' client
508    operation the library will automatically start the key agreement. In this
509    case the application must not call this function. However, application
510    may choose to just ignore the `key_agreement' client operation (and
511    merely just print information about it on the screen) and call this
512    function when the user whishes to do so (by, for example, giving some
513    specific command). Thus, the API provides both, automatic and manual
514    initiation of the key agreement. Calling this function is the manual
515    initiation and returning TRUE in the `key_agreement' client operation
516    is the automatic initiation. */
517
518 void silc_client_perform_key_agreement(SilcClient client,
519                                        SilcClientConnection conn,
520                                        SilcClientEntry client_entry,
521                                        char *hostname,
522                                        int port,
523                                        SilcKeyAgreementCallback completion,
524                                        void *context)
525 {
526   SilcClientKeyAgreement ke;
527
528   SILC_LOG_DEBUG(("Start"));
529
530   if (!client_entry)
531     return;
532
533   if (!hostname || !port) {
534     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
535                NULL, context);
536     return;
537   }
538
539   if (client_entry == conn->local_entry) {
540     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_SELF_DENIED,
541                NULL, context);
542     return;
543   }
544
545   ke = silc_calloc(1, sizeof(*ke));
546   ke->client = client;
547   ke->conn = conn;
548   ke->client_entry = client_entry;
549   ke->completion = completion;
550   ke->context = context;
551
552   /* Connect to the remote client */
553   ke->fd = silc_client_connect_to_client(client, conn, port, hostname, ke);
554   if (ke->fd < 0) {
555     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
556                NULL, context);
557     silc_free(ke);
558     return;
559   }
560 }
561
562 /* Same as above but application has created already the connection to
563    the remote host. The `sock' is the socket to the remote connection.
564    Application can use this function if it does not want the client library
565    to create the connection. */
566
567 void silc_client_perform_key_agreement_fd(SilcClient client,
568                                           SilcClientConnection conn,
569                                           SilcClientEntry client_entry,
570                                           int sock,
571                                           char *hostname,
572                                           SilcKeyAgreementCallback completion,
573                                           void *context)
574 {
575   SilcClientKeyAgreement ke;
576   SilcClientKEInternalContext *proto_ctx;
577   SilcProtocol protocol;
578
579   SILC_LOG_DEBUG(("Start"));
580
581   if (!client_entry)
582     return;
583
584   if (client_entry == conn->local_entry) {
585     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_SELF_DENIED,
586                NULL, context);
587     return;
588   }
589
590   ke = silc_calloc(1, sizeof(*ke));
591   ke->client = client;
592   ke->conn = conn;
593   ke->client_entry = client_entry;
594   ke->fd = sock;
595   ke->completion = completion;
596   ke->context = context;
597
598   /* Allocate new socket connection object */
599   silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, (void *)conn, &ke->sock);
600   silc_client_add_socket(client, ke->sock);
601   ke->sock->hostname = strdup(hostname);
602   ke->sock->port = silc_net_get_remote_port(sock);
603
604   /* Allocate internal context for key exchange protocol. This is
605      sent as context for the protocol. */
606   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
607   proto_ctx->client = client;
608   proto_ctx->sock = silc_socket_dup(ke->sock);
609   proto_ctx->rng = client->rng;
610   proto_ctx->responder = FALSE;
611   proto_ctx->context = ke;
612   proto_ctx->send_packet = silc_client_key_agreement_send_packet;
613   proto_ctx->verify = silc_client_protocol_ke_verify_key;
614   ke->proto_ctx = proto_ctx;
615
616   /* Perform key exchange protocol. */
617   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
618                       &protocol, (void *)proto_ctx,
619                       silc_client_key_agreement_final);
620   ke->sock->protocol = protocol;
621
622   /* Register the connection for network input and output. This sets
623      that scheduler will listen for incoming packets for this connection
624      and sets that outgoing packets may be sent to this connection as well.
625      However, this doesn't set the scheduler for outgoing traffic, it will
626      be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
627      later when outgoing data is available. */
628   context = (void *)client;
629   SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
630
631   /* Execute the protocol */
632   silc_protocol_execute(protocol, client->schedule, 0, 0);
633 }
634
635 /* This function can be called to unbind the hostname and the port for
636    the key agreement protocol. However, this function has effect only
637    before the key agreement protocol has been performed. After it has
638    been performed the library will automatically unbind the port. The
639    `client_entry' is the client to which we sent the key agreement
640    request. */
641
642 void silc_client_abort_key_agreement(SilcClient client,
643                                      SilcClientConnection conn,
644                                      SilcClientEntry client_entry)
645 {
646   if (!client_entry)
647     return;
648
649   if (client_entry->ke) {
650     SilcClientKeyAgreement ke;
651
652     if (client_entry->ke->sock) {
653       silc_client_del_socket(client_entry->ke->client, client_entry->ke->sock);
654       silc_socket_free(client_entry->ke->sock);
655     }
656     silc_schedule_task_del_by_fd(client->schedule, client_entry->ke->fd);
657     if (client_entry->ke->timeout)
658       silc_schedule_task_del(client->schedule,
659                              client_entry->ke->timeout);
660     ke = client_entry->ke;
661     client_entry->ke = NULL;
662     ke->completion(client, conn, client_entry,
663                    SILC_KEY_AGREEMENT_ABORTED, NULL, ke->context);
664     silc_free(ke);
665   }
666 }
667
668 /* Callback function that is called after we've resolved the client
669    information who sent us the key agreement packet from the server.
670    We actually call the key_agreement client operation now. */
671
672 static void
673 silc_client_key_agreement_resolve_cb(SilcClient client,
674                                      SilcClientConnection conn,
675                                      SilcClientEntry *clients,
676                                      SilcUInt32 clients_count,
677                                      void *context)
678 {
679   SilcPacketContext *packet = (SilcPacketContext *)context;
680   SilcKeyAgreementPayload payload;
681   int ret;
682   SilcKeyAgreementCallback completion;
683   void *completion_context;
684
685   if (!clients)
686     goto out;
687
688   /* Parse the key agreement payload */
689   payload = silc_key_agreement_payload_parse(packet->buffer->data,
690                                              packet->buffer->len);
691   if (!payload)
692     goto out;
693
694   /* Call the key_agreement client operation */
695   ret = client->internal->ops->key_agreement(
696                                    client, conn, clients[0],
697                                    silc_key_agreement_get_hostname(payload),
698                                    silc_key_agreement_get_port(payload),
699                                    &completion, &completion_context);
700
701   /* If the user returned TRUE then we'll start the key agreement right
702      here and right now. */
703   if (ret == TRUE)
704     silc_client_perform_key_agreement(client, conn, clients[0],
705                                       silc_key_agreement_get_hostname(payload),
706                                       silc_key_agreement_get_port(payload),
707                                       completion, completion_context);
708
709   silc_key_agreement_payload_free(payload);
710
711  out:
712   silc_packet_context_free(packet);
713 }
714
715 /* Received Key Agreement packet from remote client. Process the packet
716    and resolve the client information from the server before actually
717    letting the application know that we've received this packet.  Then
718    call the key_agreement client operation and let the user decide
719    whether we perform the key agreement protocol now or not. */
720
721 void silc_client_key_agreement(SilcClient client,
722                                SilcSocketConnection sock,
723                                SilcPacketContext *packet)
724 {
725   SilcClientID *remote_id;
726
727   if (packet->src_id_type != SILC_ID_CLIENT)
728     return;
729
730   remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
731                              SILC_ID_CLIENT);
732   if (!remote_id)
733     return;
734
735   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
736                                        NULL,
737                                        silc_client_key_agreement_resolve_cb,
738                                        silc_packet_context_dup(packet));
739   silc_free(remote_id);
740 }