+
+/* A timeout callback for the re-key. We will be the initiator of the
+ re-key protocol. */
+
+SILC_TASK_CALLBACK(silc_client_rekey_callback)
+{
+ SilcSocketConnection sock = (SilcSocketConnection)context;
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+ SilcClient client = (SilcClient)conn->rekey->context;
+ SilcProtocol protocol;
+ SilcClientRekeyInternalContext *proto_ctx;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Allocate internal protocol context. This is sent as context
+ to the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->client = (void *)client;
+ proto_ctx->sock = sock;
+ proto_ctx->responder = FALSE;
+ proto_ctx->pfs = conn->rekey->pfs;
+
+ /* Perform rekey protocol. Will call the final callback after the
+ protocol is over. */
+ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
+ &protocol, proto_ctx, silc_client_rekey_final);
+ sock->protocol = protocol;
+
+ /* Run the protocol */
+ protocol->execute(client->timeout_queue, 0, protocol,
+ sock->sock, 0, 0);
+
+ /* Re-register re-key timeout */
+ silc_task_register(client->timeout_queue, sock->sock,
+ silc_client_rekey_callback,
+ context, conn->rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+}
+
+/* The final callback for the REKEY protocol. This will actually take the
+ new key material into use. */
+
+SILC_TASK_CALLBACK(silc_client_rekey_final)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientRekeyInternalContext *ctx =
+ (SilcClientRekeyInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcSocketConnection sock = ctx->sock;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+ /* Error occured during protocol */
+ silc_protocol_cancel(client->timeout_queue, protocol);
+ silc_protocol_free(protocol);
+ sock->protocol = NULL;
+ if (ctx->keymat)
+ silc_ske_free_key_material(ctx->keymat);
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_free(ctx);
+ return;
+ }
+
+ /* Take the keys into use */
+ if (ctx->pfs == TRUE)
+ silc_client_protocol_rekey_generate_pfs(client, ctx);
+ else
+ silc_client_protocol_rekey_generate(client, ctx);
+
+ /* Cleanup */
+ silc_protocol_free(protocol);
+ sock->protocol = NULL;
+ if (ctx->keymat)
+ silc_ske_free_key_material(ctx->keymat);
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_free(ctx);
+}