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;
181 proto_ctx->verify = silc_client_protocol_ke_verify_key;
183 /* Prepare the connection for key exchange protocol. We allocate the
184 protocol but will not start it yet. The connector will be the
185 initiator of the protocol thus we will wait for initiation from
186 there before we start the protocol. */
187 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
188 &newsocket->protocol, proto_ctx,
189 silc_client_key_agreement_final);
191 /* Register the connection for network input and output. This sets
192 that scheduler will listen for incoming packets for this connection
193 and sets that outgoing packets may be sent to this connection as well.
194 However, this doesn't set the scheduler for outgoing traffic, it
195 will be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
196 later when outgoing data is available. */
197 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
200 /* Timeout occured during key agreement. This means that the key agreement
201 protocol was not completed in the specified timeout. We will call the
202 completion callback. */
204 SILC_TASK_CALLBACK(silc_client_key_agreement_timeout)
206 SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
208 ke->client_entry->ke = NULL;
209 ke->completion(ke->client, ke->conn, ke->client_entry, NULL, ke->context);
212 silc_socket_free(ke->sock);
213 ke->client_entry->ke = NULL;
215 silc_task_unregister_by_callback(ke->client->timeout_queue,
216 silc_client_failure_callback);
217 silc_task_unregister_by_fd(ke->client->io_queue, ke->fd);
220 /* Sends key agreement request to the remote client indicated by the
221 `client_entry'. If the caller provides the `hostname' and the `port'
222 arguments then the library will bind the client to that hostname and
223 that port for the key agreement protocol. It also sends the `hostname'
224 and the `port' in the key agreement packet to the remote client. This
225 would indicate that the remote client may initiate the key agreement
226 protocol to the `hostname' on the `port'. If port is zero then the
227 bound port is undefined (the operating system defines it).
229 If the `hostname' and `port' is not provided then empty key agreement
230 packet is sent to the remote client. The remote client may reply with
231 the same packet including its hostname and port. If the library receives
232 the reply from the remote client the `key_agreement' client operation
233 callback will be called to verify whether the user wants to perform the
234 key agreement or not.
236 NOTE: If the application provided the `hostname' and the `port' and the
237 remote side initiates the key agreement protocol it is not verified
238 from the user anymore whether the protocol should be executed or not.
239 By setting the `hostname' and `port' the user gives permission to
240 perform the protocol (we are responder in this case).
242 NOTE: If the remote side decides not to initiate the key agreement
243 or decides not to reply with the key agreement packet then we cannot
244 perform the key agreement at all. If the key agreement protocol is
245 performed the `completion' callback with the `context' will be called.
246 If remote side decides to ignore the request the `completion' will be
247 called after the specified timeout, `timeout_secs'.
249 NOTE: There can be only one active key agreement for one client entry.
250 Before setting new one, the old one must be finished (it is finished
251 after calling the completion callback) or the function
252 silc_client_abort_key_agreement must be called. */
254 void silc_client_send_key_agreement(SilcClient client,
255 SilcClientConnection conn,
256 SilcClientEntry client_entry,
259 unsigned long timeout_secs,
260 SilcKeyAgreementCallback completion,
263 SilcSocketConnection sock = conn->sock;
264 SilcClientKeyAgreement ke;
267 assert(client_entry);
269 if (client_entry->ke)
272 /* Create the listener if hostname and port was provided */
274 ke = silc_calloc(1, sizeof(*ke));
275 ke->fd = silc_net_create_server(port, hostname);
278 client->ops->say(client, conn,
279 "Cannot create listener on %s on port %d: %s",
280 hostname, port, strerror(errno));
281 completion(client, conn, client_entry, NULL, context);
288 ke->client_entry = client_entry;
289 ke->completion = completion;
290 ke->context = context;
292 /* Add listener task to the queue. This task receives the key
294 silc_task_register(client->io_queue, ke->fd,
295 silc_client_process_key_agreement,
298 SILC_TASK_PRI_NORMAL);
300 /* Register a timeout task that will be executed if the connector
301 will not start the key exchange protocol within the specified
304 silc_task_register(client->timeout_queue, 0,
305 silc_client_key_agreement_timeout,
306 (void *)ke, timeout_secs, 0,
307 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
310 /* Encode the key agreement payload */
311 buffer = silc_key_agreement_payload_encode(hostname, port);
313 /* Send the key agreement packet to the client */
314 silc_client_packet_send(client, sock, SILC_PACKET_KEY_AGREEMENT,
315 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
316 buffer->data, buffer->len, FALSE);
321 silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx)
325 /* Create connection to server asynchronously */
326 sock = silc_net_create_connection_async(ctx->port, ctx->host);
330 /* Register task that will receive the async connect and will
332 ctx->task = silc_task_register(ctx->client->io_queue, sock,
333 silc_client_perform_key_agreement_start,
336 SILC_TASK_PRI_NORMAL);
337 silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
338 silc_schedule_set_listen_fd(sock, ctx->task->iomask);
345 /* Routine used by silc_client_perform_key_agreement to create connection
346 to the remote client on specified port. */
349 silc_client_connect_to_client(SilcClient client,
350 SilcClientConnection conn, int port,
351 char *host, void *context)
353 SilcClientInternalConnectContext *ctx;
355 /* Allocate internal context for connection process. This is
356 needed as we are doing async connecting. */
357 ctx = silc_calloc(1, sizeof(*ctx));
358 ctx->client = client;
360 ctx->host = strdup(host);
363 ctx->context = context;
365 /* Do the actual connecting process */
366 return silc_client_connect_to_client_internal(ctx);
369 /* Callback that is called after connection has been created. This actually
370 starts the key agreement protocol. This is initiator function. */
372 SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start)
374 SilcClientInternalConnectContext *ctx =
375 (SilcClientInternalConnectContext *)context;
376 SilcClient client = ctx->client;
377 SilcClientConnection conn = ctx->conn;
378 SilcClientKeyAgreement ke = (SilcClientKeyAgreement)ctx->context;
379 int opt, opt_len = sizeof(opt);
381 SILC_LOG_DEBUG(("Start"));
383 /* Check the socket status as it might be in error */
384 getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
386 if (ctx->tries < 2) {
387 /* Connection failed but lets try again */
388 client->ops->say(client, conn, "Could not connect to client %s: %s",
389 ctx->host, strerror(opt));
390 client->ops->say(client, conn,
391 "Connecting to port %d of client %s resumed",
392 ctx->port, ctx->host);
394 /* Unregister old connection try */
395 silc_schedule_unset_listen_fd(fd);
396 silc_net_close_connection(fd);
397 silc_task_unregister(client->io_queue, ctx->task);
400 silc_client_connect_to_client_internal(ctx);
403 /* Connection failed and we won't try anymore */
404 client->ops->say(client, conn, "Could not connect to client %s: %s",
405 ctx->host, strerror(opt));
406 silc_schedule_unset_listen_fd(fd);
407 silc_net_close_connection(fd);
408 silc_task_unregister(client->io_queue, ctx->task);
411 /* Call the completion callback */
412 ke->completion(ke->client, ke->conn, ke->client_entry,
419 silc_schedule_unset_listen_fd(fd);
420 silc_task_unregister(client->io_queue, ctx->task);
425 /* Now actually perform the key agreement protocol */
426 silc_client_perform_key_agreement_fd(ke->client, ke->conn,
427 ke->client_entry, ke->fd,
428 ke->completion, ke->context);
432 /* Performs the actual key agreement protocol. Application may use this
433 to initiate the key agreement protocol. This can be called for example
434 after the application has received the `key_agreement' client operation,
435 and did not return TRUE from it.
437 The `hostname' is the remote hostname (or IP address) and the `port'
438 is the remote port. The `completion' callback with the `context' will
439 be called after the key agreement protocol.
441 NOTE: If the application returns TRUE in the `key_agreement' client
442 operation the library will automatically start the key agreement. In this
443 case the application must not call this function. However, application
444 may choose to just ignore the `key_agreement' client operation (and
445 merely just print information about it on the screen) and call this
446 function when the user whishes to do so (by, for example, giving some
447 specific command). Thus, the API provides both, automatic and manual
448 initiation of the key agreement. Calling this function is the manual
449 initiation and returning TRUE in the `key_agreement' client operation
450 is the automatic initiation. */
452 void silc_client_perform_key_agreement(SilcClient client,
453 SilcClientConnection conn,
454 SilcClientEntry client_entry,
457 SilcKeyAgreementCallback completion,
460 SilcClientKeyAgreement ke;
462 assert(client_entry && hostname && port);
464 ke = silc_calloc(1, sizeof(*ke));
467 ke->client_entry = client_entry;
468 ke->completion = completion;
469 ke->context = context;
471 /* Connect to the remote client */
472 ke->fd = silc_client_connect_to_client(client, conn, port, hostname, ke);
474 completion(client, conn, client_entry, NULL, context);
480 /* Same as above but application has created already the connection to
481 the remote host. The `sock' is the socket to the remote connection.
482 Application can use this function if it does not want the client library
483 to create the connection. */
485 void silc_client_perform_key_agreement_fd(SilcClient client,
486 SilcClientConnection conn,
487 SilcClientEntry client_entry,
489 SilcKeyAgreementCallback completion,
492 SilcClientKeyAgreement ke;
493 SilcClientKEInternalContext *proto_ctx;
494 SilcProtocol protocol;
496 assert(client_entry);
498 ke = silc_calloc(1, sizeof(*ke));
501 ke->client_entry = client_entry;
503 ke->completion = completion;
504 ke->context = context;
506 /* Allocate new socket connection object */
507 silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, (void *)conn, &ke->sock);
509 /* Allocate internal context for key exchange protocol. This is
510 sent as context for the protocol. */
511 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
512 proto_ctx->client = client;
513 proto_ctx->sock = ke->sock;
514 proto_ctx->rng = client->rng;
515 proto_ctx->responder = FALSE;
516 proto_ctx->context = ke;
517 proto_ctx->send_packet = silc_client_key_agreement_send_packet;
518 proto_ctx->verify = silc_client_protocol_ke_verify_key;
520 /* Perform key exchange protocol. */
521 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
522 &protocol, (void *)proto_ctx,
523 silc_client_key_agreement_final);
524 ke->sock->protocol = protocol;
526 /* Register the connection for network input and output. This sets
527 that scheduler will listen for incoming packets for this connection
528 and sets that outgoing packets may be sent to this connection as well.
529 However, this doesn't set the scheduler for outgoing traffic, it will
530 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
531 later when outgoing data is available. */
532 context = (void *)client;
533 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
535 /* Execute the protocol */
536 protocol->execute(client->timeout_queue, 0, protocol, sock, 0, 0);
539 /* This function can be called to unbind the hostname and the port for
540 the key agreement protocol. However, this function has effect only
541 before the key agreement protocol has been performed. After it has
542 been performed the library will automatically unbind the port. The
543 `client_entry' is the client to which we sent the key agreement
546 void silc_client_abort_key_agreement(SilcClient client,
547 SilcClientConnection conn,
548 SilcClientEntry client_entry)
550 assert(client_entry);
552 if (client_entry->ke) {
553 if (client_entry->ke->sock)
554 silc_socket_free(client_entry->ke->sock);
555 client_entry->ke = NULL;
556 silc_task_unregister_by_fd(client->io_queue, client_entry->ke->fd);
557 if (client_entry->ke->timeout)
558 silc_task_unregister(client->timeout_queue,
559 client_entry->ke->timeout);
560 silc_free(client_entry->ke);
564 /* Callback function that is called after we've resolved the client
565 information who sent us the key agreement packet from the server.
566 We actually call the key_agreement client operation now. */
569 silc_client_key_agreement_resolve_cb(SilcClient client,
570 SilcClientConnection conn,
571 SilcClientEntry *clients,
572 unsigned int clients_count,
575 SilcPacketContext *packet = (SilcPacketContext *)context;
576 SilcKeyAgreementPayload payload;
578 SilcKeyAgreementCallback completion;
579 void *completion_context;
584 /* Parse the key agreement payload */
585 payload = silc_key_agreement_payload_parse(packet->buffer);
589 /* Call the key_agreement client operation */
590 ret = client->ops->key_agreement(client, conn, clients[0],
591 silc_key_agreement_get_hostname(payload),
592 silc_key_agreement_get_port(payload),
593 &completion, &completion_context);
595 /* If the user returned TRUE then we'll start the key agreement right
596 here and right now. */
598 silc_client_perform_key_agreement(client, conn, clients[0],
599 silc_key_agreement_get_hostname(payload),
600 silc_key_agreement_get_port(payload),
601 completion, completion_context);
603 silc_key_agreement_payload_free(payload);
606 silc_packet_context_free(packet);
609 /* Received Key Agreement packet from remote client. Process the packet
610 and resolve the client information from the server before actually
611 letting the application know that we've received this packet. Then
612 call the key_agreement client operation and let the user decide
613 whether we perform the key agreement protocol now or not. */
615 void silc_client_key_agreement(SilcClient client,
616 SilcSocketConnection sock,
617 SilcPacketContext *packet)
619 SilcClientID *remote_id;
621 if (packet->src_id_type != SILC_ID_CLIENT)
624 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
629 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
630 silc_client_key_agreement_resolve_cb,
631 silc_packet_context_dup(packet));
632 silc_free(remote_id);