5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 Pekka Riikonen
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.
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.
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. */
27 #include "clientlibincludes.h"
28 #include "client_internal.h"
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);
35 /* Key agreement context */
36 struct SilcClientKeyAgreementStruct {
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 */
47 /* Packet sending function used by the SKE in the key agreement process. */
49 static void silc_client_key_agreement_send_packet(SilcSKE ske,
54 SilcProtocol protocol = (SilcProtocol)context;
55 SilcClientKEInternalContext *ctx =
56 (SilcClientKEInternalContext *)protocol->context;
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;
72 /* This callback is called after the key agreement protocol has been
73 performed. This calls the final completion callback for the application. */
75 SILC_TASK_CALLBACK(silc_client_key_agreement_final)
77 SilcProtocol protocol = (SilcProtocol)context;
78 SilcClientKEInternalContext *ctx =
79 (SilcClientKEInternalContext *)protocol->context;
80 SilcClient client = (SilcClient)ctx->client;
81 SilcClientKeyAgreement ke = (SilcClientKeyAgreement)ctx->context;
83 SILC_LOG_DEBUG(("Start"));
85 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
86 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
87 /* Error occured during protocol */
88 ke->client_entry->ke = NULL;
89 ke->completion(ke->client, ke->conn, ke->client_entry, NULL, ke->context);
90 silc_ske_free_key_material(ctx->keymat);
94 /* Pass the negotiated key material to the application. The application
95 is responsible of freeing the key material. */
96 ke->client_entry->ke = NULL;
97 ke->completion(ke->client, ke->conn, ke->client_entry, ctx->keymat,
101 silc_protocol_free(protocol);
103 silc_ske_free(ctx->ske);
105 silc_free(ctx->dest_id);
106 silc_task_unregister_by_callback(client->timeout_queue,
107 silc_client_failure_callback);
108 silc_task_unregister_by_fd(client->io_queue, ke->fd);
110 silc_task_unregister(client->timeout_queue, ke->timeout);
111 silc_socket_free(ke->sock);
116 /* Key agreement callback that is called when remote end has initiated
117 the key agreement protocol. This accepts the incoming TCP/IP connection
118 for the key agreement protocol. */
120 SILC_TASK_CALLBACK(silc_client_process_key_agreement)
122 SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
123 SilcClient client = ke->client;
124 SilcClientConnection conn = ke->conn;
125 SilcSocketConnection newsocket;
126 SilcClientKEInternalContext *proto_ctx;
129 SILC_LOG_DEBUG(("Start"));
131 sock = silc_net_accept_connection(ke->fd);
133 client->ops->say(client, conn,
134 "Could not accept key agreement connection: ",
136 ke->client_entry->ke = NULL;
137 ke->completion(ke->client, ke->conn, ke->client_entry, NULL, ke->context);
138 silc_task_unregister_by_fd(client->io_queue, ke->fd);
140 silc_task_unregister(client->timeout_queue, ke->timeout);
145 /* Set socket options */
146 silc_net_set_socket_nonblock(sock);
147 silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
149 /* Create socket for this connection (it is of type UNKNOWN since this
150 really is not a real SILC connection. It is only for the key
151 agreement protocol). */
152 silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, (void *)conn, &newsocket);
153 ke->sock = newsocket;
155 /* Perform name and address lookups for the remote host. */
156 silc_net_check_host_by_sock(sock, &newsocket->hostname, &newsocket->ip);
157 if (!newsocket->hostname && !newsocket->ip) {
158 client->ops->say(client, conn,
159 "Could not resolve the remote IP or hostname");
160 ke->client_entry->ke = NULL;
161 ke->completion(ke->client, ke->conn, ke->client_entry, NULL, ke->context);
162 silc_task_unregister_by_fd(client->io_queue, ke->fd);
164 silc_task_unregister(client->timeout_queue, ke->timeout);
168 if (!newsocket->hostname)
169 newsocket->hostname = strdup(newsocket->ip);
170 newsocket->port = silc_net_get_remote_port(sock);
172 /* Allocate internal context for key exchange protocol. This is
173 sent as context for the protocol. */
174 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
175 proto_ctx->client = client;
176 proto_ctx->sock = newsocket;
177 proto_ctx->rng = client->rng;
178 proto_ctx->responder = TRUE;
179 proto_ctx->context = context;
180 proto_ctx->send_packet = silc_client_key_agreement_send_packet;
182 /* Prepare the connection for key exchange protocol. We allocate the
183 protocol but will not start it yet. The connector will be the
184 initiator of the protocol thus we will wait for initiation from
185 there before we start the protocol. */
186 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
187 &newsocket->protocol, proto_ctx,
188 silc_client_key_agreement_final);
190 /* Register the connection for network input and output. This sets
191 that scheduler will listen for incoming packets for this connection
192 and sets that outgoing packets may be sent to this connection as well.
193 However, this doesn't set the scheduler for outgoing traffic, it
194 will be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
195 later when outgoing data is available. */
196 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
199 /* Timeout occured during key agreement. This means that the key agreement
200 protocol was not completed in the specified timeout. We will call the
201 completion callback. */
203 SILC_TASK_CALLBACK(silc_client_key_agreement_timeout)
205 SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
207 ke->client_entry->ke = NULL;
208 ke->completion(ke->client, ke->conn, ke->client_entry, NULL, ke->context);
211 silc_socket_free(ke->sock);
212 ke->client_entry->ke = NULL;
214 silc_task_unregister_by_callback(ke->client->timeout_queue,
215 silc_client_failure_callback);
216 silc_task_unregister_by_fd(ke->client->io_queue, ke->fd);
219 /* Sends key agreement request to the remote client indicated by the
220 `client_entry'. If the caller provides the `hostname' and the `port'
221 arguments then the library will bind the client to that hostname and
222 that port for the key agreement protocol. It also sends the `hostname'
223 and the `port' in the key agreement packet to the remote client. This
224 would indicate that the remote client may initiate the key agreement
225 protocol to the `hostname' on the `port'.
227 If the `hostname' and `port' is not provided then empty key agreement
228 packet is sent to the remote client. The remote client may reply with
229 the same packet including its hostname and port. If the library receives
230 the reply from the remote client the `key_agreement' client operation
231 callback will be called to verify whether the user wants to perform the
232 key agreement or not.
234 NOTE: If the application provided the `hostname' and the `port' and the
235 remote side initiates the key agreement protocol it is not verified
236 from the user anymore whether the protocol should be executed or not.
237 By setting the `hostname' and `port' the user gives permission to
238 perform the protocol (we are responder in this case).
240 NOTE: If the remote side decides not to initiate the key agreement
241 or decides not to reply with the key agreement packet then we cannot
242 perform the key agreement at all. If the key agreement protocol is
243 performed the `completion' callback with the `context' will be called.
244 If remote side decides to ignore the request the `completion' will be
245 called after the specified timeout, `timeout_secs'.
247 NOTE: There can be only one active key agreement for one client entry.
248 Before setting new one, the old one must be finished (it is finished
249 after calling the completion callback) or the function
250 silc_client_abort_key_agreement must be called. */
252 void silc_client_send_key_agreement(SilcClient client,
253 SilcClientConnection conn,
254 SilcClientEntry client_entry,
257 unsigned long timeout_secs,
258 SilcKeyAgreementCallback completion,
261 SilcSocketConnection sock = conn->sock;
262 SilcClientKeyAgreement ke;
265 assert(client_entry);
267 if (client_entry->ke)
270 /* Create the listener if hostname and port was provided */
271 if (hostname && port) {
272 ke = silc_calloc(1, sizeof(*ke));
273 ke->fd = silc_net_create_server(port, hostname);
276 client->ops->say(client, conn,
277 "Cannot create listener on %s on port %d: %s",
278 hostname, port, strerror(errno));
279 completion(client, conn, client_entry, NULL, context);
286 ke->client_entry = client_entry;
287 ke->completion = completion;
288 ke->context = context;
290 /* Add listener task to the queue. This task receives the key
292 silc_task_register(client->io_queue, ke->fd,
293 silc_client_process_key_agreement,
296 SILC_TASK_PRI_NORMAL);
298 /* Register a timeout task that will be executed if the connector
299 will not start the key exchange protocol within the specified
302 silc_task_register(client->timeout_queue, 0,
303 silc_client_key_agreement_timeout,
304 (void *)ke, timeout_secs, 0,
305 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
308 /* Encode the key agreement payload */
309 buffer = silc_key_agreement_payload_encode(hostname, port);
311 /* Send the key agreement packet to the client */
312 silc_client_packet_send(client, sock, SILC_PACKET_KEY_AGREEMENT,
313 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
314 buffer->data, buffer->len, FALSE);
319 silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx)
323 /* Create connection to server asynchronously */
324 sock = silc_net_create_connection_async(ctx->port, ctx->host);
328 /* Register task that will receive the async connect and will
330 ctx->task = silc_task_register(ctx->client->io_queue, sock,
331 silc_client_perform_key_agreement_start,
334 SILC_TASK_PRI_NORMAL);
335 silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
336 silc_schedule_set_listen_fd(sock, ctx->task->iomask);
343 /* Routine used by silc_client_perform_key_agreement to create connection
344 to the remote client on specified port. */
347 silc_client_connect_to_client(SilcClient client,
348 SilcClientConnection conn, int port,
349 char *host, void *context)
351 SilcClientInternalConnectContext *ctx;
353 /* Allocate internal context for connection process. This is
354 needed as we are doing async connecting. */
355 ctx = silc_calloc(1, sizeof(*ctx));
356 ctx->client = client;
358 ctx->host = strdup(host);
361 ctx->context = context;
363 /* Do the actual connecting process */
364 return silc_client_connect_to_client_internal(ctx);
367 /* Callback that is called after connection has been created. This actually
368 starts the key agreement protocol. This is initiator function. */
370 SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start)
372 SilcClientInternalConnectContext *ctx =
373 (SilcClientInternalConnectContext *)context;
374 SilcClient client = ctx->client;
375 SilcClientConnection conn = ctx->conn;
376 SilcClientKeyAgreement ke = (SilcClientKeyAgreement)ctx->context;
377 int opt, opt_len = sizeof(opt);
379 SILC_LOG_DEBUG(("Start"));
381 /* Check the socket status as it might be in error */
382 getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
384 if (ctx->tries < 2) {
385 /* Connection failed but lets try again */
386 client->ops->say(client, conn, "Could not connect to client %s: %s",
387 ctx->host, strerror(opt));
388 client->ops->say(client, conn,
389 "Connecting to port %d of client %s resumed",
390 ctx->port, ctx->host);
392 /* Unregister old connection try */
393 silc_schedule_unset_listen_fd(fd);
394 silc_net_close_connection(fd);
395 silc_task_unregister(client->io_queue, ctx->task);
398 silc_client_connect_to_client_internal(ctx);
401 /* Connection failed and we won't try anymore */
402 client->ops->say(client, conn, "Could not connect to client %s: %s",
403 ctx->host, strerror(opt));
404 silc_schedule_unset_listen_fd(fd);
405 silc_net_close_connection(fd);
406 silc_task_unregister(client->io_queue, ctx->task);
409 /* Call the completion callback */
410 ke->completion(ke->client, ke->conn, ke->client_entry,
417 silc_schedule_unset_listen_fd(fd);
418 silc_task_unregister(client->io_queue, ctx->task);
423 /* Now actually perform the key agreement protocol */
424 silc_client_perform_key_agreement_fd(ke->client, ke->conn,
425 ke->client_entry, ke->fd,
426 ke->completion, ke->context);
430 /* Performs the actual key agreement protocol. Application may use this
431 to initiate the key agreement protocol. This can be called for example
432 after the application has received the `key_agreement' client operation,
433 and did not return TRUE from it.
435 The `hostname' is the remote hostname (or IP address) and the `port'
436 is the remote port. The `completion' callback with the `context' will
437 be called after the key agreement protocol.
439 NOTE: If the application returns TRUE in the `key_agreement' client
440 operation the library will automatically start the key agreement. In this
441 case the application must not call this function. However, application
442 may choose to just ignore the `key_agreement' client operation (and
443 merely just print information about it on the screen) and call this
444 function when the user whishes to do so (by, for example, giving some
445 specific command). Thus, the API provides both, automatic and manual
446 initiation of the key agreement. Calling this function is the manual
447 initiation and returning TRUE in the `key_agreement' client operation
448 is the automatic initiation. */
450 void silc_client_perform_key_agreement(SilcClient client,
451 SilcClientConnection conn,
452 SilcClientEntry client_entry,
455 SilcKeyAgreementCallback completion,
458 SilcClientKeyAgreement ke;
460 assert(client_entry && hostname && port);
462 ke = silc_calloc(1, sizeof(*ke));
465 ke->client_entry = client_entry;
466 ke->completion = completion;
467 ke->context = context;
469 /* Connect to the remote client */
470 ke->fd = silc_client_connect_to_client(client, conn, port, hostname, ke);
472 completion(client, conn, client_entry, NULL, context);
478 /* Same as above but application has created already the connection to
479 the remote host. The `sock' is the socket to the remote connection.
480 Application can use this function if it does not want the client library
481 to create the connection. */
483 void silc_client_perform_key_agreement_fd(SilcClient client,
484 SilcClientConnection conn,
485 SilcClientEntry client_entry,
487 SilcKeyAgreementCallback completion,
490 SilcClientKeyAgreement ke;
491 SilcClientKEInternalContext *proto_ctx;
492 SilcProtocol protocol;
494 assert(client_entry);
496 ke = silc_calloc(1, sizeof(*ke));
499 ke->client_entry = client_entry;
501 ke->completion = completion;
502 ke->context = context;
504 /* Allocate new socket connection object */
505 silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, (void *)conn, &ke->sock);
507 /* Allocate internal context for key exchange protocol. This is
508 sent as context for the protocol. */
509 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
510 proto_ctx->client = client;
511 proto_ctx->sock = ke->sock;
512 proto_ctx->rng = client->rng;
513 proto_ctx->responder = FALSE;
514 proto_ctx->context = ke;
515 proto_ctx->send_packet = silc_client_key_agreement_send_packet;
517 /* Perform key exchange protocol. */
518 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
519 &protocol, (void *)proto_ctx,
520 silc_client_key_agreement_final);
521 ke->sock->protocol = protocol;
523 /* Register the connection for network input and output. This sets
524 that scheduler will listen for incoming packets for this connection
525 and sets that outgoing packets may be sent to this connection as well.
526 However, this doesn't set the scheduler for outgoing traffic, it will
527 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
528 later when outgoing data is available. */
529 context = (void *)client;
530 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
532 /* Execute the protocol */
533 protocol->execute(client->timeout_queue, 0, protocol, sock, 0, 0);
536 /* This function can be called to unbind the hostname and the port for
537 the key agreement protocol. However, this function has effect only
538 before the key agreement protocol has been performed. After it has
539 been performed the library will automatically unbind the port. The
540 `client_entry' is the client to which we sent the key agreement
543 void silc_client_abort_key_agreement(SilcClient client,
544 SilcClientConnection conn,
545 SilcClientEntry client_entry)
547 assert(client_entry);
549 if (client_entry->ke) {
550 if (client_entry->ke->sock)
551 silc_socket_free(client_entry->ke->sock);
552 client_entry->ke = NULL;
553 silc_task_unregister_by_fd(client->io_queue, client_entry->ke->fd);
554 if (client_entry->ke->timeout)
555 silc_task_unregister(client->timeout_queue,
556 client_entry->ke->timeout);
557 silc_free(client_entry->ke);
561 /* Callback function that is called after we've resolved the client
562 information who sent us the key agreement packet from the server.
563 We actually call the key_agreement client operation now. */
566 silc_client_key_agreement_resolve_cb(SilcClient client,
567 SilcClientConnection conn,
568 SilcClientEntry *clients,
569 unsigned int clients_count,
572 SilcPacketContext *packet = (SilcPacketContext *)context;
573 SilcKeyAgreementPayload payload;
575 SilcKeyAgreementCallback completion;
576 void *completion_context;
581 /* Parse the key agreement payload */
582 payload = silc_key_agreement_payload_parse(packet->buffer);
586 /* Call the key_agreement client operation */
587 ret = client->ops->key_agreement(client, conn, clients[0],
588 silc_key_agreement_get_hostname(payload),
589 silc_key_agreement_get_port(payload),
590 &completion, &completion_context);
592 /* If the user returned TRUE then we'll start the key agreement right
593 here and right now. */
595 silc_client_perform_key_agreement(client, conn, clients[0],
596 silc_key_agreement_get_hostname(payload),
597 silc_key_agreement_get_port(payload),
598 completion, completion_context);
600 silc_key_agreement_payload_free(payload);
603 silc_packet_context_free(packet);
606 /* Received Key Agreement packet from remote client. Process the packet
607 and resolve the client information from the server before actually
608 letting the application know that we've received this packet. Then
609 call the key_agreement client operation and let the user decide
610 whether we perform the key agreement protocol now or not. */
612 void silc_client_key_agreement(SilcClient client,
613 SilcSocketConnection sock,
614 SilcPacketContext *packet)
616 SilcClientID *remote_id;
618 if (packet->src_id_type != SILC_ID_CLIENT)
621 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
626 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
627 silc_client_key_agreement_resolve_cb,
628 silc_packet_context_dup(packet));
629 silc_free(remote_id);