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