5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2006 - 2007 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 /************************ Static utility functions **************************/
26 /* Callback called after connected to remote host */
28 static void silc_client_connect_callback(SilcNetStatus status,
29 SilcStream stream, void *context)
31 SilcFSMThread fsm = context;
32 SilcClientConnection conn = silc_fsm_get_context(fsm);
33 SilcClient client = conn->client;
35 conn->internal->op = NULL;
36 if (conn->internal->verbose) {
40 case SILC_NET_UNKNOWN_IP:
41 client->internal->ops->say(
42 client, conn, SILC_CLIENT_MESSAGE_ERROR,
43 "Could not connect to host %s: unknown IP address",
46 case SILC_NET_UNKNOWN_HOST:
47 client->internal->ops->say(
48 client, conn, SILC_CLIENT_MESSAGE_ERROR,
49 "Could not connect to host %s: unknown host name",
52 case SILC_NET_HOST_UNREACHABLE:
53 client->internal->ops->say(
54 client, conn, SILC_CLIENT_MESSAGE_ERROR,
55 "Could not connect to host %s: network unreachable",
58 case SILC_NET_CONNECTION_REFUSED:
59 client->internal->ops->say(
60 client, conn, SILC_CLIENT_MESSAGE_ERROR,
61 "Could not connect to host %s: connection refused",
64 case SILC_NET_CONNECTION_TIMEOUT:
65 client->internal->ops->say(
66 client, conn, SILC_CLIENT_MESSAGE_ERROR,
67 "Could not connect to host %s: connection timeout",
71 client->internal->ops->say(
72 client, conn, SILC_CLIENT_MESSAGE_ERROR,
73 "Could not connect to host %s",
79 if (status != SILC_NET_OK) {
80 /* Notify application of failure */
81 SILC_LOG_DEBUG(("Connecting failed"));
82 conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0,
83 NULL, conn->callback_context);
84 silc_fsm_next(fsm, silc_client_st_connect_error);
85 SILC_FSM_CALL_CONTINUE(fsm);
89 /* Connection created successfully */
90 SILC_LOG_DEBUG(("Connected"));
91 conn->stream = (void *)stream;
92 SILC_FSM_CALL_CONTINUE(fsm);
95 /* Called after application has verified remote host's public key */
97 static void silc_client_ke_verify_key_cb(SilcBool success, void *context)
99 VerifyKeyContext verify = (VerifyKeyContext)context;
101 SILC_LOG_DEBUG(("Start"));
103 /* Call the completion callback back to the SKE */
104 verify->completion(verify->ske, success ? SILC_SKE_STATUS_OK :
105 SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
106 verify->completion_context);
111 /* Verify remote host's public key */
113 static void silc_client_ke_verify_key(SilcSKE ske,
114 SilcPublicKey public_key,
116 SilcSKEVerifyCbCompletion completion,
117 void *completion_context)
119 SilcFSMThread fsm = context;
120 SilcClientConnection conn = silc_fsm_get_context(fsm);
121 SilcClient client = conn->client;
122 VerifyKeyContext verify;
124 /* If we provided repository for SKE and we got here the key was not
125 found from the repository. */
126 if (conn->internal->params.repository &&
127 !conn->internal->params.verify_notfound) {
128 completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
133 SILC_LOG_DEBUG(("Verify remote public key"));
135 verify = silc_calloc(1, sizeof(*verify));
137 completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
142 verify->completion = completion;
143 verify->completion_context = completion_context;
145 /* Verify public key in application */
146 client->internal->ops->verify_public_key(client, conn,
147 conn->type, public_key,
148 silc_client_ke_verify_key_cb,
152 /* Key exchange protocol completion callback */
154 static void silc_client_ke_completion(SilcSKE ske,
155 SilcSKEStatus status,
156 SilcSKESecurityProperties prop,
157 SilcSKEKeyMaterial keymat,
158 SilcSKERekeyMaterial rekey,
161 SilcFSMThread fsm = context;
162 SilcClientConnection conn = silc_fsm_get_context(fsm);
163 SilcClient client = conn->client;
164 SilcCipher send_key, receive_key;
165 SilcHmac hmac_send, hmac_receive;
167 conn->internal->op = NULL;
168 if (status != SILC_SKE_STATUS_OK) {
169 /* Key exchange failed */
170 SILC_LOG_DEBUG(("Error during key exchange with %s: %s (%d)",
171 conn->remote_host, silc_ske_map_status(status), status));
173 if (conn->internal->verbose)
174 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
175 "Error during key exchange with %s: %s",
177 silc_ske_map_status(status));
179 conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_KE, 0, NULL,
180 conn->callback_context);
182 silc_ske_free_rekey_material(rekey);
184 silc_fsm_next(fsm, silc_client_st_connect_error);
185 SILC_FSM_CALL_CONTINUE(fsm);
189 SILC_LOG_DEBUG(("Setting keys into use"));
191 /* Allocate the cipher and HMAC contexts */
192 if (!silc_ske_set_keys(ske, keymat, prop, &send_key, &receive_key,
193 &hmac_send, &hmac_receive, &conn->internal->hash)) {
194 /* Error setting keys */
195 SILC_LOG_DEBUG(("Could not set keys into use"));
197 if (conn->internal->verbose)
198 client->internal->ops->say(
199 client, conn, SILC_CLIENT_MESSAGE_ERROR,
200 "Error during key exchange with %s: cannot use keys",
203 conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_KE, 0, NULL,
204 conn->callback_context);
206 silc_ske_free_rekey_material(rekey);
208 silc_fsm_next(fsm, silc_client_st_connect_error);
209 SILC_FSM_CALL_CONTINUE(fsm);
213 /* Set the keys into the packet stream. After this call packets will be
214 encrypted with these keys. */
215 if (!silc_packet_set_keys(conn->stream, send_key, receive_key, hmac_send,
216 hmac_receive, FALSE)) {
217 /* Error setting keys */
218 SILC_LOG_DEBUG(("Could not set keys into use"));
220 if (conn->internal->verbose)
221 client->internal->ops->say(
222 client, conn, SILC_CLIENT_MESSAGE_ERROR,
223 "Error during key exchange with %s: cannot use keys",
226 conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_KE, 0, NULL,
227 conn->callback_context);
229 silc_ske_free_rekey_material(rekey);
231 silc_fsm_next(fsm, silc_client_st_connect_error);
232 SILC_FSM_CALL_CONTINUE(fsm);
236 conn->internal->rekey = rekey;
238 SILC_LOG_DEBUG(("Key Exchange completed"));
240 /* Key exchange done */
241 SILC_FSM_CALL_CONTINUE(fsm);
244 /* Rekey protocol completion callback */
246 static void silc_client_rekey_completion(SilcSKE ske,
247 SilcSKEStatus status,
248 SilcSKESecurityProperties prop,
249 SilcSKEKeyMaterial keymat,
250 SilcSKERekeyMaterial rekey,
253 SilcFSMThread fsm = context;
254 SilcClientConnection conn = silc_fsm_get_context(fsm);
255 SilcClient client = conn->client;
257 conn->internal->op = NULL;
258 if (status != SILC_SKE_STATUS_OK) {
260 SILC_LOG_DEBUG(("Error during rekey with %s: %s (%d)",
261 conn->remote_host, silc_ske_map_status(status), status));
263 if (conn->internal->verbose)
264 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
265 "Error during rekey with %s: %s",
267 silc_ske_map_status(status));
269 silc_fsm_finish(fsm);
273 silc_ske_free_rekey_material(conn->internal->rekey);
274 conn->internal->rekey = rekey;
276 SILC_LOG_DEBUG(("Rekey completed"));
279 silc_fsm_finish(fsm);
282 /* Callback called by application to return authentication data */
284 static void silc_client_connect_auth_method(SilcAuthMethod auth_meth,
285 void *auth, SilcUInt32 auth_len,
288 SilcFSMThread fsm = context;
289 SilcClientConnection conn = silc_fsm_get_context(fsm);
291 conn->internal->params.auth_method = auth_meth;
292 conn->internal->params.auth = auth;
293 conn->internal->params.auth_len = auth_len;
295 SILC_FSM_CALL_CONTINUE(fsm);
298 /* Connection authentication completion callback */
300 static void silc_client_connect_auth_completion(SilcConnAuth connauth,
304 SilcFSMThread fsm = context;
305 SilcClientConnection conn = silc_fsm_get_context(fsm);
306 SilcClient client = conn->client;
308 conn->internal->op = NULL;
309 silc_connauth_free(connauth);
312 if (conn->internal->verbose)
313 client->internal->ops->say(
314 client, conn, SILC_CLIENT_MESSAGE_ERROR,
315 "Authentication failed");
317 conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_AUTH, 0, NULL,
318 conn->callback_context);
319 silc_fsm_next(fsm, silc_client_st_connect_error);
322 SILC_FSM_CALL_CONTINUE(fsm);
325 /********************** CONNECTION_AUTH_REQUEST packet **********************/
327 /* Received connection authentication request packet. We get the
328 required authentication method here. */
330 SILC_FSM_STATE(silc_client_connect_auth_request)
332 SilcClientConnection conn = fsm_context;
333 SilcPacket packet = state_context;
334 SilcUInt16 conn_type, auth_meth;
336 if (!conn->internal->auth_request) {
337 silc_packet_free(packet);
338 return SILC_FSM_FINISH;
341 /* Parse the payload */
342 if (silc_buffer_unformat(&packet->buffer,
343 SILC_STR_UI_SHORT(&conn_type),
344 SILC_STR_UI_SHORT(&auth_meth),
346 auth_meth = SILC_AUTH_NONE;
348 silc_packet_free(packet);
350 SILC_LOG_DEBUG(("Resolved authentication method: %s",
351 (auth_meth == SILC_AUTH_NONE ? "none" :
352 auth_meth == SILC_AUTH_PASSWORD ? "passphrase" :
354 conn->internal->params.auth_method = auth_meth;
356 /* Continue authentication */
357 silc_fsm_continue_sync(&conn->internal->event_thread);
358 return SILC_FSM_FINISH;
361 /*************************** Connect remote host ****************************/
363 /* Connection timeout callback */
365 SILC_TASK_CALLBACK(silc_client_connect_timeout)
367 SilcClientConnection conn = context;
368 SilcClient client = conn->client;
370 SILC_LOG_DEBUG(("Connection timeout"));
372 conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_TIMEOUT, 0, NULL,
373 conn->callback_context);
375 silc_fsm_next(&conn->internal->event_thread, silc_client_st_connect_error);
376 silc_fsm_continue_sync(&conn->internal->event_thread);
379 /* Creates a connection to remote host */
381 SILC_FSM_STATE(silc_client_st_connect)
383 SilcClientConnection conn = fsm_context;
384 SilcClient client = conn->client;
386 SILC_LOG_DEBUG(("Connecting to %s:%d", conn->remote_host,
390 silc_fsm_next(fsm, silc_client_st_connect_set_stream);
392 /* Add connection timeout */
393 if (conn->internal->params.timeout_secs)
394 silc_schedule_task_add_timeout(conn->internal->schedule,
395 silc_client_connect_timeout, conn,
396 conn->internal->params.timeout_secs, 0);
398 if (conn->internal->params.udp) {
401 if (!conn->internal->params.local_ip) {
402 /** IP address not given */
403 SILC_LOG_ERROR(("Local UDP IP address not specified"));
404 conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
405 conn->callback_context);
406 silc_fsm_next(fsm, silc_client_st_connect_error);
407 return SILC_FSM_CONTINUE;
411 stream = silc_net_udp_connect(conn->internal->params.bind_ip ?
412 conn->internal->params.bind_ip :
413 conn->internal->params.local_ip,
414 conn->internal->params.local_port,
415 conn->remote_host, conn->remote_port,
416 conn->internal->schedule);
418 SILC_FSM_CALL(silc_client_connect_callback(stream ? SILC_NET_OK :
419 SILC_NET_HOST_UNREACHABLE,
423 SILC_FSM_CALL(conn->internal->op = silc_net_tcp_connect(
424 NULL, conn->remote_host,
426 conn->internal->schedule,
427 silc_client_connect_callback, fsm));
431 /* Sets the new connection stream into use and creates packet stream */
433 SILC_FSM_STATE(silc_client_st_connect_set_stream)
435 SilcClientConnection conn = fsm_context;
436 SilcClient client = conn->client;
438 if (conn->internal->disconnected) {
440 silc_fsm_next(fsm, silc_client_st_connect_error);
441 return SILC_FSM_CONTINUE;
444 /* Create packet stream */
445 conn->stream = silc_packet_stream_create(client->internal->packet_engine,
446 conn->internal->schedule,
447 (SilcStream)conn->stream);
449 /** Cannot create packet stream */
450 SILC_LOG_DEBUG(("Could not create packet stream"));
451 conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
452 conn->callback_context);
453 silc_fsm_next(fsm, silc_client_st_connect_error);
454 return SILC_FSM_CONTINUE;
457 silc_packet_set_context(conn->stream, conn);
459 /** Start key exchange */
460 silc_fsm_next(fsm, silc_client_st_connect_key_exchange);
461 return SILC_FSM_CONTINUE;
464 /* Starts key exchange protocol with remote host */
466 SILC_FSM_STATE(silc_client_st_connect_key_exchange)
468 SilcClientConnection conn = fsm_context;
469 SilcClient client = conn->client;
470 SilcSKEParamsStruct params;
472 SILC_LOG_DEBUG(("Starting key exchange protocol"));
475 conn->internal->ske =
476 silc_ske_alloc(client->rng, conn->internal->schedule,
477 conn->internal->params.repository,
478 conn->public_key, conn->private_key, fsm);
479 if (!conn->internal->ske) {
481 conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_KE, 0, NULL,
482 conn->callback_context);
483 silc_fsm_next(fsm, silc_client_st_connect_error);
484 return SILC_FSM_CONTINUE;
487 /* Set SKE callbacks */
488 silc_ske_set_callbacks(conn->internal->ske, silc_client_ke_verify_key,
489 silc_client_ke_completion, fsm);
491 /* Set up key exchange parameters */
492 params.version = client->internal->silc_client_version;
493 params.timeout_secs = conn->internal->params.timeout_secs;
494 params.flags = SILC_SKE_SP_FLAG_MUTUAL;
495 if (conn->internal->params.pfs)
496 params.flags |= SILC_SKE_SP_FLAG_PFS;
497 if (conn->internal->params.udp) {
498 params.flags |= SILC_SKE_SP_FLAG_IV_INCLUDED;
499 params.session_port = conn->internal->params.local_port;
502 if (conn->internal->params.no_authentication)
503 /** Run key exchange (no auth) */
504 silc_fsm_next(fsm, silc_client_st_connected);
505 else if (conn->internal->params.udp)
506 /** Run key exchange (UDP)*/
507 silc_fsm_next(fsm, silc_client_st_connect_setup_udp);
509 /** Run key exchange (TCP) */
510 silc_fsm_next(fsm, silc_client_st_connect_auth_resolve);
512 SILC_FSM_CALL(conn->internal->op = silc_ske_initiator(conn->internal->ske,
517 /* For UDP/IP connections, set up the UDP session after successful key
520 SILC_FSM_STATE(silc_client_st_connect_setup_udp)
522 SilcClientConnection conn = fsm_context;
523 SilcClient client = conn->client;
524 SilcStream stream, old;
525 SilcSKESecurityProperties prop;
527 SILC_LOG_DEBUG(("Setup UDP SILC session"));
529 if (conn->internal->disconnected) {
531 silc_fsm_next(fsm, silc_client_st_connect_error);
532 return SILC_FSM_CONTINUE;
535 /* Create new UDP stream */
536 prop = silc_ske_get_security_properties(conn->internal->ske);
537 stream = silc_net_udp_connect(conn->internal->params.local_ip,
538 conn->internal->params.local_port,
539 conn->remote_host, prop->remote_port,
540 conn->internal->schedule);
542 /** Cannot create UDP stream */
543 conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
544 conn->callback_context);
545 silc_fsm_next(fsm, silc_client_st_connect_error);
546 return SILC_FSM_CONTINUE;
549 /* Set the new stream to packet stream */
550 old = silc_packet_stream_get_stream(conn->stream);
551 silc_packet_stream_set_stream(conn->stream, stream);
552 silc_packet_stream_set_iv_included(conn->stream);
553 silc_packet_set_sid(conn->stream, 0);
555 /* Delete the old stream */
556 silc_stream_destroy(old);
558 /** Start authentication */
559 silc_fsm_next(fsm, silc_client_st_connect_auth_resolve);
560 return SILC_FSM_CONTINUE;
563 /* Resolved authentication method to be used in authentication protocol */
565 SILC_FSM_STATE(silc_client_st_connect_auth_resolve)
567 SilcClientConnection conn = fsm_context;
569 SILC_LOG_DEBUG(("Resolve authentication method"));
571 if (conn->internal->disconnected) {
573 silc_fsm_next(fsm, silc_client_st_connect_error);
574 return SILC_FSM_CONTINUE;
577 /* If authentication method and data is set, use them */
578 if (conn->internal->params.auth_set) {
579 /** Got authentication data */
580 silc_fsm_next(fsm, silc_client_st_connect_auth_start);
581 return SILC_FSM_CONTINUE;
584 /* Send connection authentication request packet */
585 silc_packet_send_va(conn->stream,
586 SILC_PACKET_CONNECTION_AUTH_REQUEST, 0,
587 SILC_STR_UI_SHORT(SILC_CONN_CLIENT),
588 SILC_STR_UI_SHORT(SILC_AUTH_NONE),
591 /** Wait for authentication method */
592 conn->internal->auth_request = TRUE;
593 conn->internal->params.auth_method = SILC_AUTH_NONE;
594 silc_fsm_next_later(fsm, silc_client_st_connect_auth_data, 2, 0);
595 return SILC_FSM_WAIT;
598 /* Get authentication data to be used in authentication protocol */
600 SILC_FSM_STATE(silc_client_st_connect_auth_data)
602 SilcClientConnection conn = fsm_context;
603 SilcClient client = conn->client;
605 SILC_LOG_DEBUG(("Get authentication data"));
607 if (conn->internal->disconnected) {
609 silc_fsm_next(fsm, silc_client_st_connect_error);
610 return SILC_FSM_CONTINUE;
613 conn->internal->auth_request = FALSE;
615 /** Get authentication data */
616 silc_fsm_next(fsm, silc_client_st_connect_auth_start);
617 SILC_FSM_CALL(client->internal->ops->get_auth_method(
621 conn->internal->params.auth_method,
622 silc_client_connect_auth_method, fsm));
625 /* Start connection authentication with remote host */
627 SILC_FSM_STATE(silc_client_st_connect_auth_start)
629 SilcClientConnection conn = fsm_context;
630 SilcClient client = conn->client;
631 SilcConnAuth connauth;
633 SILC_LOG_DEBUG(("Starting connection authentication protocol"));
635 if (conn->internal->disconnected) {
637 silc_fsm_next(fsm, silc_client_st_connect_error);
638 return SILC_FSM_CONTINUE;
641 /* We always use the same key for connection authentication and SKE */
642 if (conn->internal->params.auth_method == SILC_AUTH_PUBLIC_KEY)
643 conn->internal->params.auth = conn->private_key;
645 /* Allocate connection authentication protocol */
646 connauth = silc_connauth_alloc(conn->internal->schedule,
648 conn->internal->params.rekey_secs);
651 conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_AUTH, 0, NULL,
652 conn->callback_context);
653 silc_fsm_next(fsm, silc_client_st_connect_error);
654 return SILC_FSM_CONTINUE;
657 /** Start connection authentication */
658 silc_fsm_next(fsm, silc_client_st_connected);
659 SILC_FSM_CALL(conn->internal->op = silc_connauth_initiator(
660 connauth, SILC_CONN_CLIENT,
661 conn->internal->params.auth_method,
662 conn->internal->params.auth,
663 conn->internal->params.auth_len,
664 silc_client_connect_auth_completion,
668 /* Connection fully established */
670 SILC_FSM_STATE(silc_client_st_connected)
672 SilcClientConnection conn = fsm_context;
673 SilcClient client = conn->client;
675 silc_ske_free(conn->internal->ske);
676 conn->internal->ske = NULL;
678 if (conn->internal->disconnected) {
680 silc_fsm_next(fsm, silc_client_st_connect_error);
681 return SILC_FSM_CONTINUE;
684 SILC_LOG_DEBUG(("Connection established"));
686 /* Install rekey timer */
687 silc_schedule_task_add_timeout(conn->internal->schedule,
688 silc_client_rekey_timer, conn,
689 conn->internal->params.rekey_secs, 0);
691 /* If we connected to server, now register to network. */
692 if (conn->type == SILC_CONN_SERVER &&
693 !conn->internal->params.no_authentication) {
695 /* If detach data is provided, resume the session. */
696 if (conn->internal->params.detach_data &&
697 conn->internal->params.detach_data_len) {
698 /** Resume detached session */
699 silc_fsm_next(fsm, silc_client_st_resume);
701 /** Register to network */
702 silc_fsm_next(fsm, silc_client_st_register);
705 return SILC_FSM_CONTINUE;
708 silc_schedule_task_del_by_all(conn->internal->schedule, 0,
709 silc_client_connect_timeout, conn);
711 /* Call connection callback */
712 conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
713 conn->callback_context);
715 return SILC_FSM_FINISH;
718 /* Error during connecting */
720 SILC_FSM_STATE(silc_client_st_connect_error)
722 SilcClientConnection conn = fsm_context;
724 if (conn->internal->ske) {
725 silc_ske_free(conn->internal->ske);
726 conn->internal->ske = NULL;
729 /* Signal to close connection */
730 if (!conn->internal->disconnected) {
731 conn->internal->disconnected = TRUE;
732 SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
735 silc_schedule_task_del_by_all(conn->internal->schedule, 0,
736 silc_client_connect_timeout, conn);
738 return SILC_FSM_FINISH;
741 /****************************** Connect rekey *******************************/
743 /* Connection rekey timer callback */
745 SILC_TASK_CALLBACK(silc_client_rekey_timer)
747 SilcClientConnection conn = context;
749 /* Signal to start rekey */
750 conn->internal->rekey_responder = FALSE;
751 conn->internal->rekeying = TRUE;
752 SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
754 /* Reinstall rekey timer */
755 silc_schedule_task_add_timeout(conn->internal->schedule,
756 silc_client_rekey_timer, conn,
757 conn->internal->params.rekey_secs, 0);
762 SILC_FSM_STATE(silc_client_st_rekey)
764 SilcClientConnection conn = fsm_context;
765 SilcClient client = conn->client;
767 SILC_LOG_DEBUG(("Rekey"));
769 if (conn->internal->disconnected)
770 return SILC_FSM_FINISH;
773 conn->internal->ske =
774 silc_ske_alloc(client->rng, conn->internal->schedule,
775 conn->internal->params.repository,
776 conn->public_key, conn->private_key, fsm);
777 if (!conn->internal->ske)
778 return SILC_FSM_FINISH;
780 /* Set SKE callbacks */
781 silc_ske_set_callbacks(conn->internal->ske, NULL,
782 silc_client_rekey_completion, fsm);
785 if (!conn->internal->rekey_responder)
786 SILC_FSM_CALL(conn->internal->op = silc_ske_rekey_initiator(
789 conn->internal->rekey));
791 SILC_FSM_CALL(conn->internal->op = silc_ske_rekey_responder(
794 conn->internal->rekey));