5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2006 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; version 2 of the License.
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.
21 #include "silcclient.h"
22 #include "client_internal.h"
24 /************************** Types and definitions ***************************/
26 /* Key agreement context, used by responder */
27 struct SilcClientKeyAgreementStruct {
28 SilcClient client; /* Client */
29 SilcClientConnection conn; /* Server connection */
30 SilcKeyAgreementCallback completion; /* Key agreement completion */
31 void *context; /* User context */
32 SilcClientConnectionParams params; /* Connection parameters */
33 SilcPublicKey public_key; /* Responder public key */
34 SilcPrivateKey private_key; /* Responder private key */
35 SilcNetListener tcp_listener; /* TCP listener */
36 SilcPacketStream udp_listener; /* UDP listener */
37 SilcPacketStream stream; /* Remote connection (TCP or UDP) */
38 SilcAsyncOperation op; /* SKE operation */
39 SilcSKE ske; /* SKE */
42 /************************ Static utility functions **************************/
44 /* Destroyes key agreement session */
46 static void silc_client_keyagr_free(SilcClient client,
47 SilcClientConnection conn,
48 SilcClientEntry client_entry)
50 SilcClientKeyAgreement ke = client_entry->internal.ke;
52 silc_schedule_task_del_by_context(conn->internal->schedule, client_entry);
55 silc_async_abort(ke->op, NULL, NULL);
57 silc_ske_free(ke->ske);
59 silc_net_close_listener(ke->tcp_listener);
60 silc_packet_stream_destroy(ke->stream);
61 silc_packet_stream_destroy(ke->udp_listener);
63 client_entry->internal.ke = NULL;
64 client_entry->internal.prv_resp = FALSE;
65 silc_client_unref_client(client, conn, client_entry);
70 /* Key agreement timeout callback */
72 SILC_TASK_CALLBACK(silc_client_keyagr_timeout)
74 SilcClientEntry client_entry = context;
75 SilcClientKeyAgreement ke = client_entry->internal.ke;
77 SILC_LOG_DEBUG(("Key agreement %p timeout", ke));
79 ke->completion(ke->client, ke->conn, client_entry,
80 SILC_KEY_AGREEMENT_TIMEOUT, NULL, ke->context);
82 silc_client_keyagr_free(ke->client, ke->conn, client_entry);
85 /* Client resolving callback. Continues with the key agreement processing */
87 static void silc_client_keyagr_resolved(SilcClient client,
88 SilcClientConnection conn,
93 /* If no client found, ignore the packet, a silent error */
95 silc_fsm_next(context, silc_client_key_agreement_error);
97 /* Continue processing the packet */
98 SILC_FSM_CALL_CONTINUE(context);
101 /* Called after application has verified remote host's public key. Responder
104 static void silc_client_keyagr_verify_key_cb(SilcBool success, void *context)
106 VerifyKeyContext verify = context;
108 /* Call the completion callback back to the SKE */
109 verify->completion(verify->ske, success ? SILC_SKE_STATUS_OK :
110 SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
111 verify->completion_context);
116 /* Verify remote host's public key. Responder function. */
118 static void silc_client_keyagr_verify_key(SilcSKE ske,
119 SilcPublicKey public_key,
121 SilcSKEVerifyCbCompletion completion,
122 void *completion_context)
124 SilcClientEntry client_entry = context;
125 SilcClientKeyAgreement ke = client_entry->internal.ke;
126 SilcClientConnection conn = ke->conn;
127 SilcClient client = conn->client;
128 VerifyKeyContext verify;
130 /* If we provided repository for SKE and we got here the key was not
131 found from the repository. */
132 if (ke->params.repository && !ke->params.verify_notfound) {
133 completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
138 SILC_LOG_DEBUG(("Verify remote public key"));
140 verify = silc_calloc(1, sizeof(*verify));
142 completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
147 verify->completion = completion;
148 verify->completion_context = completion_context;
150 /* Verify public key in application */
151 client->internal->ops->verify_public_key(client, conn,
152 SILC_CONN_CLIENT, public_key,
153 silc_client_keyagr_verify_key_cb,
157 /* Key exchange protocol completion callback. Responder function. */
159 static void silc_client_keyagr_completion(SilcSKE ske,
160 SilcSKEStatus status,
161 SilcSKESecurityProperties prop,
162 SilcSKEKeyMaterial keymat,
163 SilcSKERekeyMaterial rekey,
166 SilcClientEntry client_entry = context;
167 SilcClientKeyAgreement ke = client_entry->internal.ke;
168 SilcClientConnection conn = ke->conn;
169 SilcClient client = conn->client;
171 if (status != SILC_SKE_STATUS_OK) {
172 /* Key exchange failed */
173 ke->completion(client, conn, client_entry,
174 status == SILC_SKE_STATUS_TIMEOUT ?
175 SILC_KEY_AGREEMENT_TIMEOUT :
176 SILC_KEY_AGREEMENT_FAILURE, NULL, ke->context);
177 silc_client_keyagr_free(client, conn, client_entry);
181 /* Returns the negotiated key material to application. Key agreement
183 ke->completion(client, conn, client_entry, SILC_KEY_AGREEMENT_OK,
184 keymat, ke->context);
186 silc_client_keyagr_free(client, conn, client_entry);
189 /* Starts key agreement as responder. */
191 static void silc_client_process_key_agreement(SilcClient client,
192 SilcClientConnection conn,
193 SilcClientEntry client_entry)
195 SilcClientKeyAgreement ke = client_entry->internal.ke;
196 SilcSKEParamsStruct params;
198 SILC_LOG_DEBUG(("Processing key agrement %p session", ke));
201 ke->ske = silc_ske_alloc(client->rng, conn->internal->schedule,
202 ke->params.repository, ke->public_key,
203 ke->private_key, client_entry);
205 ke->completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
207 silc_client_keyagr_free(client, conn, client_entry);
211 /* Set SKE parameters */
212 params.version = client->internal->silc_client_version;
213 params.flags = SILC_SKE_SP_FLAG_MUTUAL;
214 if (ke->params.udp) {
215 params.flags |= SILC_SKE_SP_FLAG_IV_INCLUDED;
216 params.session_port = ke->params.local_port;
219 silc_ske_set_callbacks(ke->ske, silc_client_keyagr_verify_key,
220 silc_client_keyagr_completion, client_entry);
222 /* Start key exchange as responder */
223 ke->op = silc_ske_responder(ke->ske, ke->stream, ¶ms);
225 ke->completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
227 silc_client_keyagr_free(client, conn, client_entry);
231 /* TCP network listener callback. Accepts new key agreement connection.
232 Responder function. */
234 static void silc_client_tcp_accept(SilcNetStatus status,
238 SilcClientEntry client_entry = context;
239 SilcClientKeyAgreement ke = client_entry->internal.ke;
241 /* Create packet stream */
242 ke->stream = silc_packet_stream_create(ke->client->internal->packet_engine,
243 ke->conn->internal->schedule, stream);
245 silc_stream_destroy(stream);
249 /* Process session */
250 silc_client_process_key_agreement(ke->client, ke->conn, client_entry);
253 /* UDP network listener callback. Accepts new key agreement session.
254 Responder function. */
256 static SilcBool silc_client_udp_accept(SilcPacketEngine engine,
257 SilcPacketStream stream,
259 void *callback_context,
260 void *stream_context)
262 SilcClientEntry client_entry = callback_context;
263 SilcClientKeyAgreement ke = client_entry->internal.ke;
267 /* We want only key exchange packet. Eat other packets so that default
268 packet callback doesn't get them. */
269 if (packet->type != SILC_PACKET_KEY_EXCHANGE) {
270 silc_packet_free(packet);
274 /* Create packet stream for this remote UDP session */
275 if (!silc_packet_get_sender(packet, &ip, &port)) {
276 silc_packet_free(packet);
279 ke->stream = silc_packet_stream_add_remote(stream, ip, port, packet);
281 silc_packet_free(packet);
285 /* Process session */
286 silc_client_process_key_agreement(ke->client, ke->conn, client_entry);
290 /* Client connect completion callback. Initiator function. */
292 static void silc_client_keyagr_perform_cb(SilcClient client,
293 SilcClientConnection conn,
294 SilcClientConnectionStatus status,
299 SilcClientEntry client_entry = context;
300 SilcClientKeyAgreement ke = client_entry->internal.ke;
301 SilcSKEKeyMaterial keymat;
306 case SILC_CLIENT_CONN_SUCCESS:
307 SILC_LOG_DEBUG(("Key agreement %p successful", ke));
309 keymat = silc_ske_get_key_material(conn->internal->ske);
310 ke->completion(ke->client, ke->conn, client_entry, SILC_KEY_AGREEMENT_OK,
311 keymat, ke->context);
314 case SILC_CLIENT_CONN_ERROR_TIMEOUT:
315 SILC_LOG_DEBUG(("Key agreement %p timeout", ke));
316 ke->completion(ke->client, ke->conn, client_entry,
317 SILC_KEY_AGREEMENT_TIMEOUT, NULL, ke->context);
321 SILC_LOG_DEBUG(("Key agreement %p error %d", ke, status));
322 ke->completion(ke->client, ke->conn, client_entry,
323 SILC_KEY_AGREEMENT_FAILURE, NULL, ke->context);
327 /* Close the created connection */
329 silc_client_close_connection(ke->client, conn);
331 silc_client_keyagr_free(ke->client, ke->conn, client_entry);
334 /* Packet stream callbacks */
335 static SilcPacketCallbacks silc_client_keyagr_stream_cb =
337 silc_client_udp_accept, NULL, NULL
340 /*************************** Key Agreement API ******************************/
342 /* Sends key agreement packet to remote client. If IP addresses are provided
343 creates also listener for Ãncoming key agreement connection. Supports
344 both TCP and UDP transports. */
346 void silc_client_send_key_agreement(SilcClient client,
347 SilcClientConnection conn,
348 SilcClientEntry client_entry,
349 SilcClientConnectionParams *params,
350 SilcPublicKey public_key,
351 SilcPrivateKey private_key,
352 SilcKeyAgreementCallback completion,
355 SilcClientKeyAgreement ke = NULL;
357 SilcUInt16 port = 0, protocol = 0;
358 char *local_ip = NULL;
361 SILC_LOG_DEBUG(("Sending key agreement"));
366 if (client_entry->internal.ke) {
367 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ALREADY_STARTED,
372 if (client_entry == conn->local_entry) {
373 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_SELF_DENIED,
378 /* If local IP is provided, create listener */
379 if (params && (params->local_ip || params->bind_ip)) {
380 ke = silc_calloc(1, sizeof(*ke));
382 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
387 /* Create network listener */
390 stream = silc_net_udp_connect(params->bind_ip ? params->bind_ip :
391 params->local_ip, params->local_port,
392 NULL, 0, conn->internal->schedule);
394 silc_packet_stream_create(client->internal->packet_engine,
395 conn->internal->schedule, stream);
396 if (!ke->udp_listener) {
397 client->internal->ops->say(
398 client, conn, SILC_CLIENT_MESSAGE_ERROR,
399 "Cannot create UDP listener on %s on port %d: %s",
400 params->bind_ip ? params->bind_ip :
401 params->local_ip, params->local_port, strerror(errno));
402 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
405 silc_stream_destroy(stream);
409 silc_packet_stream_link(ke->udp_listener,
410 &silc_client_keyagr_stream_cb,
411 client_entry, 1000000,
412 SILC_PACKET_ANY, -1);
414 port = params->local_port;
416 /* Get listener port */
418 silc_socket_stream_get_info(stream, &sock, NULL, NULL, NULL);
419 port = silc_net_get_local_port(sock);
424 silc_net_tcp_create_listener(params->bind_ip ?
425 (const char **)¶ms->bind_ip :
426 (const char **)¶ms->local_ip,
427 1, params->local_port, FALSE, FALSE,
428 conn->internal->schedule,
429 silc_client_tcp_accept,
431 if (!ke->tcp_listener) {
432 client->internal->ops->say(
433 client, conn, SILC_CLIENT_MESSAGE_ERROR,
434 "Cannot create listener on %s on port %d: %s",
435 params->bind_ip ? params->bind_ip :
436 params->local_ip, params->local_port, strerror(errno));
437 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
443 port = params->local_port;
445 /* Get listener port */
447 ports = silc_net_listener_get_port(ke->tcp_listener, NULL);
453 local_ip = params->local_ip;
454 protocol = params->udp;
458 ke->completion = completion;
459 ke->context = context;
460 ke->params = *params;
461 ke->public_key = public_key;
462 ke->private_key = private_key;
463 silc_client_ref_client(client, conn, client_entry);
464 client_entry->internal.ke = ke;
465 client_entry->internal.prv_resp = TRUE;
468 /* Encode the key agreement payload */
469 buffer = silc_key_agreement_payload_encode(local_ip, protocol, port);
471 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
473 silc_client_keyagr_free(client, conn, client_entry);
477 /* Send the key agreement packet to the client */
478 if (!silc_packet_send_ext(conn->stream, SILC_PACKET_KEY_AGREEMENT, 0,
479 0, NULL, SILC_ID_CLIENT, &client_entry->id,
480 silc_buffer_datalen(buffer), NULL, NULL)) {
481 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
483 silc_client_keyagr_free(client, conn, client_entry);
484 silc_buffer_free(buffer);
488 /* Add key agreement timeout task */
489 if (params && params->timeout_secs)
490 silc_schedule_task_add_timeout(conn->internal->schedule,
491 silc_client_keyagr_timeout,
492 client_entry, params->timeout_secs, 0);
494 silc_buffer_free(buffer);
497 /* Perform key agreement protocol as initiator. Conneects to remote host. */
499 void silc_client_perform_key_agreement(SilcClient client,
500 SilcClientConnection conn,
501 SilcClientEntry client_entry,
502 SilcClientConnectionParams *params,
503 SilcPublicKey public_key,
504 SilcPrivateKey private_key,
505 char *hostname, int port,
506 SilcKeyAgreementCallback completion,
509 SilcClientKeyAgreement ke;
511 SILC_LOG_DEBUG(("Performing key agreement"));
513 if (!client_entry || !hostname || !port) {
514 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
519 if (client_entry == conn->local_entry) {
520 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_SELF_DENIED,
525 ke = silc_calloc(1, sizeof(*ke));
527 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
533 ke->completion = completion;
534 ke->context = context;
535 silc_client_ref_client(client, conn, client_entry);
536 client_entry->internal.ke = ke;
539 params->no_authentication = TRUE;
541 /* Connect to the remote client. Performs key exchange automatically. */
542 if (!silc_client_connect_to_client(client, params, public_key,
543 private_key, hostname, port,
544 silc_client_keyagr_perform_cb,
546 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
548 silc_client_keyagr_free(client, conn, client_entry);
553 /* Same as above but caller has created connection. */
556 silc_client_perform_key_agreement_stream(SilcClient client,
557 SilcClientConnection conn,
558 SilcClientEntry client_entry,
559 SilcClientConnectionParams *params,
560 SilcPublicKey public_key,
561 SilcPrivateKey private_key,
563 SilcKeyAgreementCallback completion,
566 SilcClientKeyAgreement ke;
568 SILC_LOG_DEBUG(("Performing key agreement"));
570 if (!client_entry || !stream) {
571 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
576 if (client_entry == conn->local_entry) {
577 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_SELF_DENIED,
582 ke = silc_calloc(1, sizeof(*ke));
584 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
590 ke->completion = completion;
591 ke->context = context;
592 silc_client_ref_client(client, conn, client_entry);
593 client_entry->internal.ke = ke;
596 params->no_authentication = TRUE;
598 /* Perform key exchange protocol */
599 if (!silc_client_key_exchange(client, params, public_key,
600 private_key, stream, SILC_CONN_CLIENT,
601 silc_client_keyagr_perform_cb,
603 completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
605 silc_client_keyagr_free(client, conn, client_entry);
610 /* This function can be called to unbind the hostname and the port for
611 the key agreement protocol. However, this function has effect only
612 before the key agreement protocol has been performed. After it has
613 been performed the library will automatically unbind the port. The
614 `client_entry' is the client to which we sent the key agreement
617 void silc_client_abort_key_agreement(SilcClient client,
618 SilcClientConnection conn,
619 SilcClientEntry client_entry)
621 SilcClientKeyAgreement ke;
623 if (!client_entry || !client_entry->internal.ke)
626 ke = client_entry->internal.ke;
628 SILC_LOG_DEBUG(("Abort key agreement %p"));
630 ke->completion(client, conn, client_entry,
631 SILC_KEY_AGREEMENT_ABORTED, NULL, ke->context);
633 silc_client_keyagr_free(client, conn, client_entry);
636 /* Key agreement packet received */
638 SILC_FSM_STATE(silc_client_key_agreement)
640 SilcClientConnection conn = fsm_context;
641 SilcClient client = conn->client;
642 SilcPacket packet = state_context;
643 SilcClientID remote_id;
644 SilcClientEntry remote_client;
645 SilcKeyAgreementPayload payload;
647 if (packet->src_id_type != SILC_ID_CLIENT) {
648 /** Invalid packet */
649 silc_fsm_next(fsm, silc_client_key_agreement_error);
650 return SILC_FSM_CONTINUE;
653 if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
654 &remote_id, sizeof(remote_id))) {
655 /** Invalid source ID */
656 silc_fsm_next(fsm, silc_client_key_agreement_error);
657 return SILC_FSM_CONTINUE;
660 /* Check whether we know this client already */
661 remote_client = silc_client_get_client_by_id(client, conn, &remote_id);
662 if (!remote_client || !remote_client->nickname[0]) {
663 /** Resolve client info */
664 silc_client_unref_client(client, conn, remote_client);
665 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
666 client, conn, &remote_id, NULL,
667 silc_client_keyagr_resolved, fsm));
671 /* Parse the key agreement payload */
672 payload = silc_key_agreement_payload_parse(silc_buffer_data(&packet->buffer),
673 silc_buffer_len(&packet->buffer));
675 /** Malformed Payload */
676 SILC_LOG_DEBUG(("Malformed key agreement payload"));
677 silc_fsm_next(fsm, silc_client_key_agreement_error);
678 return SILC_FSM_CONTINUE;
681 /* If remote did not provide connection endpoint, we will assume that we
682 will provide it and will be responder. */
683 if (!silc_key_agreement_get_hostname(payload))
684 remote_client->internal.prv_resp = TRUE;
686 remote_client->internal.prv_resp = FALSE;
688 /* Notify application for key agreement request */
689 client->internal->ops->key_agreement(
690 client, conn, remote_client,
691 silc_key_agreement_get_hostname(payload),
692 silc_key_agreement_get_protocol(payload),
693 silc_key_agreement_get_port(payload));
695 silc_key_agreement_payload_free(payload);
697 silc_packet_free(packet);
698 return SILC_FSM_FINISH;
701 /* Key agreement packet processing error */
703 SILC_FSM_STATE(silc_client_key_agreement_error)
705 SilcPacket packet = state_context;
706 silc_packet_free(packet);
707 return SILC_FSM_FINISH;