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