9191edd623036e2ff302be70dbc485f786f33386
[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->sock->sock);
80   silc_schedule_unset_listen_fd(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_callback(client->timeout_queue,
123                                    silc_client_failure_callback);
124   silc_task_unregister_by_fd(client->io_queue, ke->fd);
125   silc_schedule_unset_listen_fd(ke->fd);
126   silc_net_close_connection(ke->fd);
127   if (ke->timeout)
128     silc_task_unregister(client->timeout_queue, ke->timeout);
129   silc_client_del_socket(ke->client, ke->sock);
130
131   silc_task_register(client->timeout_queue, 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->ops->say(client, conn, 
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_task_unregister_by_fd(client->io_queue, ke->fd);
163     silc_schedule_unset_listen_fd(ke->fd);
164     silc_net_close_connection(ke->fd);
165     if (ke->timeout)
166       silc_task_unregister(client->timeout_queue, 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->ops->say(client, conn, 
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_task_unregister_by_fd(client->io_queue, ke->fd);
190     silc_schedule_unset_listen_fd(ke->fd);
191     silc_net_close_connection(ke->fd);
192     if (ke->timeout)
193       silc_task_unregister(client->timeout_queue, 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 = 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
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   ke->client_entry->ke = NULL;
248   silc_task_unregister_by_callback(ke->client->timeout_queue,
249                                    silc_client_failure_callback);
250   if (ke->fd)
251     silc_task_unregister_by_fd(ke->client->io_queue, ke->fd);
252   silc_schedule_unset_listen_fd(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: There can be only one active key agreement for one client entry.
287    Before setting new one, the old one must be finished (it is finished
288    after calling the completion callback) or the function 
289    silc_client_abort_key_agreement must be called. */
290
291 void silc_client_send_key_agreement(SilcClient client,
292                                     SilcClientConnection conn,
293                                     SilcClientEntry client_entry,
294                                     char *hostname,
295                                     int port,
296                                     uint32 timeout_secs,
297                                     SilcKeyAgreementCallback completion,
298                                     void *context)
299 {
300   SilcSocketConnection sock = conn->sock;
301   SilcClientKeyAgreement ke = NULL;
302   SilcBuffer buffer;
303
304   assert(client_entry);
305
306   if (client_entry->ke)
307     return;
308
309   /* Create the listener if hostname and port was provided */
310   if (hostname) {
311     ke = silc_calloc(1, sizeof(*ke));
312     ke->fd = silc_net_create_server(port, hostname);
313
314     if (ke->fd < 0) {
315       client->ops->say(client, conn, 
316                        "Cannot create listener on %s on port %d: %s", 
317                        hostname, port, strerror(errno));
318       completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
319                  NULL, context);
320       silc_free(ke);
321       return;
322     }
323
324     ke->client = client;
325     ke->conn = conn;
326     ke->client_entry = client_entry;
327     ke->completion = completion;
328     ke->context = context;
329
330     /* Add listener task to the queue. This task receives the key 
331        negotiations. */
332     silc_task_register(client->io_queue, ke->fd,
333                        silc_client_process_key_agreement,
334                        (void *)ke, 0, 0, 
335                        SILC_TASK_FD,
336                        SILC_TASK_PRI_NORMAL);
337
338     /* Register a timeout task that will be executed if the connector
339        will not start the key exchange protocol within the specified 
340        timeout. */
341     ke->timeout = silc_task_register(client->timeout_queue, 0, 
342                                      silc_client_key_agreement_timeout,
343                                      (void *)ke, timeout_secs, 0, 
344                                      SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
345   }
346
347   /* Encode the key agreement payload */
348   buffer = silc_key_agreement_payload_encode(hostname, 
349                                              !ke ? port : 
350                                              silc_net_get_local_port(ke->fd));
351
352   /* Send the key agreement packet to the client */
353   silc_client_packet_send(client, sock, SILC_PACKET_KEY_AGREEMENT,
354                           client_entry->id, SILC_ID_CLIENT, NULL, NULL,
355                           buffer->data, buffer->len, FALSE);
356   silc_free(buffer);
357 }
358
359 static int 
360 silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx)
361 {
362   int sock;
363
364   /* Create connection to server asynchronously */
365   sock = silc_net_create_connection_async(ctx->port, ctx->host);
366   if (sock < 0)
367     return -1;
368
369   /* Register task that will receive the async connect and will
370      read the result. */
371   ctx->task = silc_task_register(ctx->client->io_queue, sock, 
372                                  silc_client_perform_key_agreement_start,
373                                  (void *)ctx, 0, 0, 
374                                  SILC_TASK_FD,
375                                  SILC_TASK_PRI_NORMAL);
376   silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
377   silc_schedule_set_listen_fd(sock, ctx->task->iomask);
378
379   ctx->sock = sock;
380
381   return sock;
382 }
383
384 /* Routine used by silc_client_perform_key_agreement to create connection
385    to the remote client on specified port. */
386
387 static int
388 silc_client_connect_to_client(SilcClient client, 
389                               SilcClientConnection conn, int port,
390                               char *host, void *context)
391 {
392   SilcClientInternalConnectContext *ctx;
393
394   /* Allocate internal context for connection process. This is
395      needed as we are doing async connecting. */
396   ctx = silc_calloc(1, sizeof(*ctx));
397   ctx->client = client;
398   ctx->conn = conn;
399   ctx->host = strdup(host);
400   ctx->port = port;
401   ctx->tries = 0;
402   ctx->context = context;
403
404   /* Do the actual connecting process */
405   return silc_client_connect_to_client_internal(ctx);
406 }
407
408 /* Callback that is called after connection has been created. This actually
409    starts the key agreement protocol. This is initiator function. */
410
411 SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start)
412 {
413   SilcClientInternalConnectContext *ctx =
414     (SilcClientInternalConnectContext *)context;
415   SilcClient client = ctx->client;
416   SilcClientConnection conn = ctx->conn;
417   SilcClientKeyAgreement ke = (SilcClientKeyAgreement)ctx->context;
418   int opt, opt_len = sizeof(opt);
419
420   SILC_LOG_DEBUG(("Start"));
421
422   /* Check the socket status as it might be in error */
423   getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
424   if (opt != 0) {
425     if (ctx->tries < 2) {
426       /* Connection failed but lets try again */
427       client->ops->say(client, conn, "Could not connect to client %s: %s",
428                        ctx->host, strerror(opt));
429       client->ops->say(client, conn, 
430                        "Connecting to port %d of client %s resumed", 
431                        ctx->port, ctx->host);
432
433       /* Unregister old connection try */
434       silc_schedule_unset_listen_fd(fd);
435       silc_net_close_connection(fd);
436       silc_task_unregister(client->io_queue, ctx->task);
437
438       /* Try again */
439       silc_client_connect_to_client_internal(ctx);
440       ctx->tries++;
441     } else {
442       /* Connection failed and we won't try anymore */
443       client->ops->say(client, conn, "Could not connect to client %s: %s",
444                        ctx->host, strerror(opt));
445       silc_schedule_unset_listen_fd(fd);
446       silc_net_close_connection(fd);
447       silc_task_unregister(client->io_queue, ctx->task);
448       silc_free(ctx->host);
449       silc_free(ctx);
450
451       /* Call the completion callback */
452       ke->completion(ke->client, ke->conn, ke->client_entry, 
453                      SILC_KEY_AGREEMENT_FAILURE, NULL, ke->context);
454       silc_free(ke);
455     }
456     return;
457   }
458
459   silc_schedule_unset_listen_fd(fd);
460   silc_task_unregister(client->io_queue, ctx->task);
461
462   ke->fd = fd;
463
464   /* Now actually perform the key agreement protocol */
465   silc_client_perform_key_agreement_fd(ke->client, ke->conn,
466                                        ke->client_entry, ke->fd, ctx->host,
467                                        ke->completion, ke->context);
468   silc_free(ke);
469   silc_free(ctx->host);
470   silc_free(ctx);
471 }
472
473 /* Performs the actual key agreement protocol. Application may use this
474    to initiate the key agreement protocol. This can be called for example
475    after the application has received the `key_agreement' client operation,
476    and did not return TRUE from it.
477
478    The `hostname' is the remote hostname (or IP address) and the `port'
479    is the remote port. The `completion' callback with the `context' will
480    be called after the key agreement protocol.
481    
482    NOTE: If the application returns TRUE in the `key_agreement' client
483    operation the library will automatically start the key agreement. In this
484    case the application must not call this function. However, application
485    may choose to just ignore the `key_agreement' client operation (and
486    merely just print information about it on the screen) and call this
487    function when the user whishes to do so (by, for example, giving some
488    specific command). Thus, the API provides both, automatic and manual
489    initiation of the key agreement. Calling this function is the manual
490    initiation and returning TRUE in the `key_agreement' client operation
491    is the automatic initiation. */
492
493 void silc_client_perform_key_agreement(SilcClient client,
494                                        SilcClientConnection conn,
495                                        SilcClientEntry client_entry,
496                                        char *hostname,
497                                        int port,
498                                        SilcKeyAgreementCallback completion,
499                                        void *context)
500 {
501   SilcClientKeyAgreement ke;
502
503   SILC_LOG_DEBUG(("Start"));
504
505   assert(client_entry && hostname && port);
506
507   ke = silc_calloc(1, sizeof(*ke));
508   ke->client = client;
509   ke->conn = conn;
510   ke->client_entry = client_entry;
511   ke->completion = completion;
512   ke->context = context;
513
514   /* Connect to the remote client */
515   ke->fd = silc_client_connect_to_client(client, conn, port, hostname, ke);
516   if (ke->fd < 0) {
517     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
518                NULL, context);
519     silc_free(ke);
520     return;
521   }
522 }
523
524 /* Same as above but application has created already the connection to 
525    the remote host. The `sock' is the socket to the remote connection. 
526    Application can use this function if it does not want the client library
527    to create the connection. */
528
529 void silc_client_perform_key_agreement_fd(SilcClient client,
530                                           SilcClientConnection conn,
531                                           SilcClientEntry client_entry,
532                                           int sock,
533                                           char *hostname,
534                                           SilcKeyAgreementCallback completion,
535                                           void *context)
536 {
537   SilcClientKeyAgreement ke;
538   SilcClientKEInternalContext *proto_ctx;
539   SilcProtocol protocol;
540
541   SILC_LOG_DEBUG(("Start"));
542
543   assert(client_entry);
544
545   ke = silc_calloc(1, sizeof(*ke));
546   ke->client = client;
547   ke->conn = conn;
548   ke->client_entry = client_entry;
549   ke->fd = sock;
550   ke->completion = completion;
551   ke->context = context;
552
553   /* Allocate new socket connection object */
554   silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, (void *)conn, &ke->sock);
555   silc_client_add_socket(client, ke->sock);
556   ke->sock->hostname = strdup(hostname);
557   ke->sock->port = silc_net_get_remote_port(sock);
558
559   /* Allocate internal context for key exchange protocol. This is
560      sent as context for the protocol. */
561   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
562   proto_ctx->client = client;
563   proto_ctx->sock = ke->sock;
564   proto_ctx->rng = client->rng;
565   proto_ctx->responder = FALSE;
566   proto_ctx->context = ke;
567   proto_ctx->send_packet = silc_client_key_agreement_send_packet;
568   proto_ctx->verify = silc_client_protocol_ke_verify_key;
569
570   /* Perform key exchange protocol. */
571   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
572                       &protocol, (void *)proto_ctx,
573                       silc_client_key_agreement_final);
574   ke->sock->protocol = protocol;
575
576   /* Register the connection for network input and output. This sets
577      that scheduler will listen for incoming packets for this connection 
578      and sets that outgoing packets may be sent to this connection as well.
579      However, this doesn't set the scheduler for outgoing traffic, it will 
580      be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
581      later when outgoing data is available. */
582   context = (void *)client;
583   SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
584
585   /* Execute the protocol */
586   protocol->execute(client->timeout_queue, 0, protocol, sock, 0, 0);
587 }
588
589 /* This function can be called to unbind the hostname and the port for
590    the key agreement protocol. However, this function has effect only 
591    before the key agreement protocol has been performed. After it has
592    been performed the library will automatically unbind the port. The 
593    `client_entry' is the client to which we sent the key agreement 
594    request. */
595
596 void silc_client_abort_key_agreement(SilcClient client,
597                                      SilcClientConnection conn,
598                                      SilcClientEntry client_entry)
599 {
600   assert(client_entry);
601
602   if (client_entry->ke) {
603     if (client_entry->ke->sock) {
604       silc_client_del_socket(client_entry->ke->client, client_entry->ke->sock);
605       silc_socket_free(client_entry->ke->sock);
606     }
607     client_entry->ke = NULL;
608     silc_task_unregister_by_fd(client->io_queue, client_entry->ke->fd);
609     if (client_entry->ke->timeout)
610       silc_task_unregister(client->timeout_queue, 
611                            client_entry->ke->timeout);
612     silc_free(client_entry->ke);
613   }
614 }
615
616 /* Callback function that is called after we've resolved the client 
617    information who sent us the key agreement packet from the server.
618    We actually call the key_agreement client operation now. */
619
620 static void 
621 silc_client_key_agreement_resolve_cb(SilcClient client,
622                                      SilcClientConnection conn,
623                                      SilcClientEntry *clients,
624                                      uint32 clients_count,
625                                      void *context)
626 {
627   SilcPacketContext *packet = (SilcPacketContext *)context;
628   SilcKeyAgreementPayload payload;
629   int ret;
630   SilcKeyAgreementCallback completion;
631   void *completion_context;
632
633   if (!clients)
634     goto out;
635
636   /* Parse the key agreement payload */
637   payload = silc_key_agreement_payload_parse(packet->buffer);
638   if (!payload)
639     goto out;
640
641   /* Call the key_agreement client operation */
642   ret = client->ops->key_agreement(client, conn, clients[0], 
643                                    silc_key_agreement_get_hostname(payload),
644                                    silc_key_agreement_get_port(payload),
645                                    &completion, &completion_context);
646
647   /* If the user returned TRUE then we'll start the key agreement right
648      here and right now. */
649   if (ret == TRUE)
650     silc_client_perform_key_agreement(client, conn, clients[0],
651                                       silc_key_agreement_get_hostname(payload),
652                                       silc_key_agreement_get_port(payload),
653                                       completion, completion_context);
654
655   silc_key_agreement_payload_free(payload);
656
657  out:
658   silc_packet_context_free(packet);
659 }
660
661 /* Received Key Agreement packet from remote client. Process the packet
662    and resolve the client information from the server before actually
663    letting the application know that we've received this packet.  Then 
664    call the key_agreement client operation and let the user decide
665    whether we perform the key agreement protocol now or not. */
666
667 void silc_client_key_agreement(SilcClient client,
668                                SilcSocketConnection sock,
669                                SilcPacketContext *packet)
670 {
671   SilcClientID *remote_id;
672
673   if (packet->src_id_type != SILC_ID_CLIENT)
674     return;
675
676   remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
677                              SILC_ID_CLIENT);
678   if (!remote_id)
679     return;
680
681   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
682                                        silc_client_key_agreement_resolve_cb,
683                                        silc_packet_context_dup(packet));
684   silc_free(remote_id);
685 }