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'. If port is zero then the
226 bound port is undefined (the operating system defines it).
228 If the `hostname' and `port' is not provided then empty key agreement
229 packet is sent to the remote client. The remote client may reply with
230 the same packet including its hostname and port. If the library receives
231 the reply from the remote client the `key_agreement' client operation
232 callback will be called to verify whether the user wants to perform the
233 key agreement or not.
235 NOTE: If the application provided the `hostname' and the `port' and the
236 remote side initiates the key agreement protocol it is not verified
237 from the user anymore whether the protocol should be executed or not.
238 By setting the `hostname' and `port' the user gives permission to
239 perform the protocol (we are responder in this case).
241 NOTE: If the remote side decides not to initiate the key agreement
242 or decides not to reply with the key agreement packet then we cannot
243 perform the key agreement at all. If the key agreement protocol is
244 performed the `completion' callback with the `context' will be called.
245 If remote side decides to ignore the request the `completion' will be
246 called after the specified timeout, `timeout_secs'.
248 NOTE: There can be only one active key agreement for one client entry.
249 Before setting new one, the old one must be finished (it is finished
250 after calling the completion callback) or the function
251 silc_client_abort_key_agreement must be called. */
253 void silc_client_send_key_agreement(SilcClient client,
254 SilcClientConnection conn,
255 SilcClientEntry client_entry,
258 unsigned long timeout_secs,
259 SilcKeyAgreementCallback completion,
262 SilcSocketConnection sock = conn->sock;
263 SilcClientKeyAgreement ke;
266 assert(client_entry);
268 if (client_entry->ke)
271 /* Create the listener if hostname and port was provided */
273 ke = silc_calloc(1, sizeof(*ke));
274 ke->fd = silc_net_create_server(port, hostname);
277 client->ops->say(client, conn,
278 "Cannot create listener on %s on port %d: %s",
279 hostname, port, strerror(errno));
280 completion(client, conn, client_entry, NULL, context);
287 ke->client_entry = client_entry;
288 ke->completion = completion;
289 ke->context = context;
291 /* Add listener task to the queue. This task receives the key
293 silc_task_register(client->io_queue, ke->fd,
294 silc_client_process_key_agreement,
297 SILC_TASK_PRI_NORMAL);
299 /* Register a timeout task that will be executed if the connector
300 will not start the key exchange protocol within the specified
303 silc_task_register(client->timeout_queue, 0,
304 silc_client_key_agreement_timeout,
305 (void *)ke, timeout_secs, 0,
306 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
309 /* Encode the key agreement payload */
310 buffer = silc_key_agreement_payload_encode(hostname, port);
312 /* Send the key agreement packet to the client */
313 silc_client_packet_send(client, sock, SILC_PACKET_KEY_AGREEMENT,
314 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
315 buffer->data, buffer->len, FALSE);
320 silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx)
324 /* Create connection to server asynchronously */
325 sock = silc_net_create_connection_async(ctx->port, ctx->host);
329 /* Register task that will receive the async connect and will
331 ctx->task = silc_task_register(ctx->client->io_queue, sock,
332 silc_client_perform_key_agreement_start,
335 SILC_TASK_PRI_NORMAL);
336 silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
337 silc_schedule_set_listen_fd(sock, ctx->task->iomask);
344 /* Routine used by silc_client_perform_key_agreement to create connection
345 to the remote client on specified port. */
348 silc_client_connect_to_client(SilcClient client,
349 SilcClientConnection conn, int port,
350 char *host, void *context)
352 SilcClientInternalConnectContext *ctx;
354 /* Allocate internal context for connection process. This is
355 needed as we are doing async connecting. */
356 ctx = silc_calloc(1, sizeof(*ctx));
357 ctx->client = client;
359 ctx->host = strdup(host);
362 ctx->context = context;
364 /* Do the actual connecting process */
365 return silc_client_connect_to_client_internal(ctx);
368 /* Callback that is called after connection has been created. This actually
369 starts the key agreement protocol. This is initiator function. */
371 SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start)
373 SilcClientInternalConnectContext *ctx =
374 (SilcClientInternalConnectContext *)context;
375 SilcClient client = ctx->client;
376 SilcClientConnection conn = ctx->conn;
377 SilcClientKeyAgreement ke = (SilcClientKeyAgreement)ctx->context;
378 int opt, opt_len = sizeof(opt);
380 SILC_LOG_DEBUG(("Start"));
382 /* Check the socket status as it might be in error */
383 getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
385 if (ctx->tries < 2) {
386 /* Connection failed but lets try again */
387 client->ops->say(client, conn, "Could not connect to client %s: %s",
388 ctx->host, strerror(opt));
389 client->ops->say(client, conn,
390 "Connecting to port %d of client %s resumed",
391 ctx->port, ctx->host);
393 /* Unregister old connection try */
394 silc_schedule_unset_listen_fd(fd);
395 silc_net_close_connection(fd);
396 silc_task_unregister(client->io_queue, ctx->task);
399 silc_client_connect_to_client_internal(ctx);
402 /* Connection failed and we won't try anymore */
403 client->ops->say(client, conn, "Could not connect to client %s: %s",
404 ctx->host, strerror(opt));
405 silc_schedule_unset_listen_fd(fd);
406 silc_net_close_connection(fd);
407 silc_task_unregister(client->io_queue, ctx->task);
410 /* Call the completion callback */
411 ke->completion(ke->client, ke->conn, ke->client_entry,
418 silc_schedule_unset_listen_fd(fd);
419 silc_task_unregister(client->io_queue, ctx->task);
424 /* Now actually perform the key agreement protocol */
425 silc_client_perform_key_agreement_fd(ke->client, ke->conn,
426 ke->client_entry, ke->fd,
427 ke->completion, ke->context);
431 /* Performs the actual key agreement protocol. Application may use this
432 to initiate the key agreement protocol. This can be called for example
433 after the application has received the `key_agreement' client operation,
434 and did not return TRUE from it.
436 The `hostname' is the remote hostname (or IP address) and the `port'
437 is the remote port. The `completion' callback with the `context' will
438 be called after the key agreement protocol.
440 NOTE: If the application returns TRUE in the `key_agreement' client
441 operation the library will automatically start the key agreement. In this
442 case the application must not call this function. However, application
443 may choose to just ignore the `key_agreement' client operation (and
444 merely just print information about it on the screen) and call this
445 function when the user whishes to do so (by, for example, giving some
446 specific command). Thus, the API provides both, automatic and manual
447 initiation of the key agreement. Calling this function is the manual
448 initiation and returning TRUE in the `key_agreement' client operation
449 is the automatic initiation. */
451 void silc_client_perform_key_agreement(SilcClient client,
452 SilcClientConnection conn,
453 SilcClientEntry client_entry,
456 SilcKeyAgreementCallback completion,
459 SilcClientKeyAgreement ke;
461 assert(client_entry && hostname && port);
463 ke = silc_calloc(1, sizeof(*ke));
466 ke->client_entry = client_entry;
467 ke->completion = completion;
468 ke->context = context;
470 /* Connect to the remote client */
471 ke->fd = silc_client_connect_to_client(client, conn, port, hostname, ke);
473 completion(client, conn, client_entry, NULL, context);
479 /* Same as above but application has created already the connection to
480 the remote host. The `sock' is the socket to the remote connection.
481 Application can use this function if it does not want the client library
482 to create the connection. */
484 void silc_client_perform_key_agreement_fd(SilcClient client,
485 SilcClientConnection conn,
486 SilcClientEntry client_entry,
488 SilcKeyAgreementCallback completion,
491 SilcClientKeyAgreement ke;
492 SilcClientKEInternalContext *proto_ctx;
493 SilcProtocol protocol;
495 assert(client_entry);
497 ke = silc_calloc(1, sizeof(*ke));
500 ke->client_entry = client_entry;
502 ke->completion = completion;
503 ke->context = context;
505 /* Allocate new socket connection object */
506 silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, (void *)conn, &ke->sock);
508 /* Allocate internal context for key exchange protocol. This is
509 sent as context for the protocol. */
510 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
511 proto_ctx->client = client;
512 proto_ctx->sock = ke->sock;
513 proto_ctx->rng = client->rng;
514 proto_ctx->responder = FALSE;
515 proto_ctx->context = ke;
516 proto_ctx->send_packet = silc_client_key_agreement_send_packet;
518 /* Perform key exchange protocol. */
519 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
520 &protocol, (void *)proto_ctx,
521 silc_client_key_agreement_final);
522 ke->sock->protocol = protocol;
524 /* Register the connection for network input and output. This sets
525 that scheduler will listen for incoming packets for this connection
526 and sets that outgoing packets may be sent to this connection as well.
527 However, this doesn't set the scheduler for outgoing traffic, it will
528 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
529 later when outgoing data is available. */
530 context = (void *)client;
531 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
533 /* Execute the protocol */
534 protocol->execute(client->timeout_queue, 0, protocol, sock, 0, 0);
537 /* This function can be called to unbind the hostname and the port for
538 the key agreement protocol. However, this function has effect only
539 before the key agreement protocol has been performed. After it has
540 been performed the library will automatically unbind the port. The
541 `client_entry' is the client to which we sent the key agreement
544 void silc_client_abort_key_agreement(SilcClient client,
545 SilcClientConnection conn,
546 SilcClientEntry client_entry)
548 assert(client_entry);
550 if (client_entry->ke) {
551 if (client_entry->ke->sock)
552 silc_socket_free(client_entry->ke->sock);
553 client_entry->ke = NULL;
554 silc_task_unregister_by_fd(client->io_queue, client_entry->ke->fd);
555 if (client_entry->ke->timeout)
556 silc_task_unregister(client->timeout_queue,
557 client_entry->ke->timeout);
558 silc_free(client_entry->ke);
562 /* Callback function that is called after we've resolved the client
563 information who sent us the key agreement packet from the server.
564 We actually call the key_agreement client operation now. */
567 silc_client_key_agreement_resolve_cb(SilcClient client,
568 SilcClientConnection conn,
569 SilcClientEntry *clients,
570 unsigned int clients_count,
573 SilcPacketContext *packet = (SilcPacketContext *)context;
574 SilcKeyAgreementPayload payload;
576 SilcKeyAgreementCallback completion;
577 void *completion_context;
582 /* Parse the key agreement payload */
583 payload = silc_key_agreement_payload_parse(packet->buffer);
587 /* Call the key_agreement client operation */
588 ret = client->ops->key_agreement(client, conn, clients[0],
589 silc_key_agreement_get_hostname(payload),
590 silc_key_agreement_get_port(payload),
591 &completion, &completion_context);
593 /* If the user returned TRUE then we'll start the key agreement right
594 here and right now. */
596 silc_client_perform_key_agreement(client, conn, clients[0],
597 silc_key_agreement_get_hostname(payload),
598 silc_key_agreement_get_port(payload),
599 completion, completion_context);
601 silc_key_agreement_payload_free(payload);
604 silc_packet_context_free(packet);
607 /* Received Key Agreement packet from remote client. Process the packet
608 and resolve the client information from the server before actually
609 letting the application know that we've received this packet. Then
610 call the key_agreement client operation and let the user decide
611 whether we perform the key agreement protocol now or not. */
613 void silc_client_key_agreement(SilcClient client,
614 SilcSocketConnection sock,
615 SilcPacketContext *packet)
617 SilcClientID *remote_id;
619 if (packet->src_id_type != SILC_ID_CLIENT)
622 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
627 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
628 silc_client_key_agreement_resolve_cb,
629 silc_packet_context_dup(packet));
630 silc_free(remote_id);