Merged silc_1_0_branch to trunk.
[silc.git] / lib / silcclient / protocol.c
index 9231f8cf5ac7e3f5f0e7b8f06d6d69f8ce15cdfa..bc229606f6b0f19b2baa618bcac556730b2a05fb 100644 (file)
@@ -4,13 +4,13 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
-  
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  */
 /* $Id$ */
 
-#include "clientlibincludes.h"
+#include "silcincludes.h"
+#include "silcclient.h"
 #include "client_internal.h"
 
 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
 SILC_TASK_CALLBACK(silc_client_protocol_rekey);
 
-extern char *silc_version_string;
-
 /*
  * Key Exhange protocol functions
  */
@@ -43,7 +42,7 @@ void silc_client_protocol_ke_send_packet(SilcSKE ske,
                                         void *context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientKEInternalContext *ctx = 
+  SilcClientKEInternalContext *ctx =
     (SilcClientKEInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
 
@@ -67,26 +66,26 @@ static void silc_client_verify_key_cb(bool success, void *context)
   SILC_LOG_DEBUG(("Start"));
 
   /* Call the completion callback back to the SKE */
-  verify->completion(verify->ske, success ? SILC_SKE_STATUS_OK : 
-                    SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY, 
+  verify->completion(verify->ske, success ? SILC_SKE_STATUS_OK :
+                    SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
                     verify->completion_context);
 
   silc_free(verify);
 }
 
-/* Callback that is called when we have received KE2 payload from
+/* Callback that is called when we have received KE payload from
    responder. We try to verify the public key now. */
 
 void silc_client_protocol_ke_verify_key(SilcSKE ske,
                                        unsigned char *pk_data,
-                                       uint32 pk_len,
+                                       SilcUInt32 pk_len,
                                        SilcSKEPKType pk_type,
                                        void *context,
                                        SilcSKEVerifyCbCompletion completion,
                                        void *completion_context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientKEInternalContext *ctx = 
+  SilcClientKEInternalContext *ctx =
     (SilcClientKEInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   VerifyKeyContext verify;
@@ -99,10 +98,10 @@ void silc_client_protocol_ke_verify_key(SilcSKE ske,
   verify->completion_context = completion_context;
 
   /* Verify public key from user. */
-  client->ops->verify_public_key(client, ctx->sock->user_data, 
-                                ctx->sock->type,
-                                pk_data, pk_len, pk_type,
-                                silc_client_verify_key_cb, verify);
+  client->internal->ops->verify_public_key(client, ctx->sock->user_data,
+                                          ctx->sock->type,
+                                          pk_data, pk_len, pk_type,
+                                          silc_client_verify_key_cb, verify);
 }
 
 /* Sets the negotiated key material into use for particular connection. */
@@ -114,116 +113,102 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske,
                                      SilcPKCS pkcs,
                                      SilcHash hash,
                                      SilcHmac hmac,
-                                     SilcSKEDiffieHellmanGroup group)
+                                     SilcSKEDiffieHellmanGroup group,
+                                     bool is_responder)
 {
   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+  const char *cname = silc_cipher_get_name(cipher);
 
   SILC_LOG_DEBUG(("Setting new keys into use"));
 
   /* Allocate cipher to be used in the communication */
-  silc_cipher_alloc(cipher->cipher->name, &conn->send_key);
-  silc_cipher_alloc(cipher->cipher->name, &conn->receive_key);
-
-  conn->send_key->cipher->set_key(conn->send_key->context, 
-                                keymat->send_enc_key, 
-                                keymat->enc_key_len);
-  conn->send_key->set_iv(conn->send_key, keymat->send_iv);
-  conn->receive_key->cipher->set_key(conn->receive_key->context, 
-                                   keymat->receive_enc_key, 
-                                   keymat->enc_key_len);
-  conn->receive_key->set_iv(conn->receive_key, keymat->receive_iv);
-
-  /* Allocate PKCS to be used */
-#if 0
-  /* XXX Do we ever need to allocate PKCS for the connection??
-     If yes, we need to change KE protocol to get the initiators
-     public key. */
-  silc_pkcs_alloc(pkcs->pkcs->name, &conn->public_Key);
-  silc_pkcs_set_public_key(conn->public_key, ske->ke2_payload->pk_data, 
-                          ske->ke2_payload->pk_len);
-#endif
-
-  conn->rekey = silc_calloc(1, sizeof(*conn->rekey));
-  conn->rekey->send_enc_key = 
-    silc_calloc(keymat->enc_key_len / 8,
-               sizeof(*conn->rekey->send_enc_key));
-  memcpy(conn->rekey->send_enc_key, 
-        keymat->send_enc_key, keymat->enc_key_len / 8);
-  conn->rekey->enc_key_len = keymat->enc_key_len / 8;
+  silc_cipher_alloc((char *)cname, &conn->internal->send_key);
+  silc_cipher_alloc((char *)cname, &conn->internal->receive_key);
+  silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL,
+                 &conn->internal->hmac_send);
+  silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL,
+                 &conn->internal->hmac_receive);
+
+  if (is_responder == TRUE) {
+    silc_cipher_set_key(conn->internal->send_key, keymat->receive_enc_key,
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(conn->internal->send_key, keymat->receive_iv);
+    silc_cipher_set_key(conn->internal->receive_key, keymat->send_enc_key,
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(conn->internal->receive_key, keymat->send_iv);
+    silc_hmac_set_key(conn->internal->hmac_send, keymat->receive_hmac_key,
+                     keymat->hmac_key_len);
+    silc_hmac_set_key(conn->internal->hmac_receive, keymat->send_hmac_key,
+                     keymat->hmac_key_len);
+  } else {
+    silc_cipher_set_key(conn->internal->send_key, keymat->send_enc_key,
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(conn->internal->send_key, keymat->send_iv);
+    silc_cipher_set_key(conn->internal->receive_key, keymat->receive_enc_key,
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(conn->internal->receive_key, keymat->receive_iv);
+    silc_hmac_set_key(conn->internal->hmac_send, keymat->send_hmac_key,
+                     keymat->hmac_key_len);
+    silc_hmac_set_key(conn->internal->hmac_receive, keymat->receive_hmac_key,
+                     keymat->hmac_key_len);
+  }
 
-  if (ske->start_payload->flags & SILC_SKE_SP_FLAG_PFS)
-    conn->rekey->pfs = TRUE;
-  conn->rekey->ske_group = silc_ske_group_get_number(group);
+  /* Rekey stuff */
+  conn->internal->rekey = silc_calloc(1, sizeof(*conn->internal->rekey));
+  conn->internal->rekey->send_enc_key = silc_memdup(keymat->send_enc_key,
+                                                   keymat->enc_key_len / 8);
+  conn->internal->rekey->enc_key_len = keymat->enc_key_len / 8;
 
-  /* Save HMAC key to be used in the communication. */
-  silc_hmac_alloc(hmac->hmac->name, NULL, &conn->hmac_send);
-  silc_hmac_set_key(conn->hmac_send, keymat->hmac_key, keymat->hmac_key_len);
-  conn->hmac_receive = conn->hmac_send;
+  if (ske->start_payload->flags & SILC_SKE_SP_FLAG_PFS)
+    conn->internal->rekey->pfs = TRUE;
+  conn->internal->rekey->ske_group = silc_ske_group_get_number(group);
 
   /* Save the HASH function */
-  silc_hash_alloc(hash->hash->name, &conn->hash);
+  silc_hash_alloc(silc_hash_get_name(hash), &conn->internal->hash);
 }
 
 /* Checks the version string of the server. */
 
 SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
-                                    uint32 len)
+                                    SilcUInt32 len, void *context)
 {
   SilcClientConnection conn = (SilcClientConnection)ske->sock->user_data;
   SilcClient client = (SilcClient)ske->user_data;
-  SilcSKEStatus status = SILC_SKE_STATUS_OK;
-  char *cp;
-  int maj = 0, min = 0, build = 0, maj2 = 0, min2 = 0, build2 = 0;
-
-  /* Check for initial version string */
-  if (!strstr(version, "SILC-1.0-"))
-    status = SILC_SKE_STATUS_BAD_VERSION;
-
-  /* Check software version */
-
-  cp = version + 9;
-  if (!cp)
-    status = SILC_SKE_STATUS_BAD_VERSION;
-
-  maj = atoi(cp);
-  cp = strchr(cp, '.');
-  if (cp) {
-    min = atoi(cp + 1);
-    cp++;
+  SilcUInt32 l_protocol_version = 0, r_protocol_version = 0;
+
+  if (!silc_parse_version_string(version, &r_protocol_version, NULL, NULL,
+                                NULL, NULL)) {
+    client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+                              "We don't support server version `%s'",
+                              version);
+    return SILC_SKE_STATUS_BAD_VERSION;
   }
-  cp = strchr(cp, '.');
-  if (cp)
-    build = atoi(cp + 1);
-
-  cp = silc_version_string + 9;
-  if (!cp)
-    status = SILC_SKE_STATUS_BAD_VERSION;
-
-  maj2 = atoi(cp);
-  cp = strchr(cp, '.');
-  if (cp) {
-    min2 = atoi(cp + 1);
-    cp++;
+
+  if (!silc_parse_version_string(client->internal->silc_client_version,
+                                &l_protocol_version, NULL, NULL,
+                                NULL, NULL)) {
+    client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+                              "We don't support server version `%s'",
+                              version);
+    return SILC_SKE_STATUS_BAD_VERSION;
   }
-  cp = strchr(cp, '.');
-  if (cp)
-    build2 = atoi(cp + 1);
 
-  if (maj != maj2)
-    status = SILC_SKE_STATUS_BAD_VERSION;
-  if (min < min2)
-    status = SILC_SKE_STATUS_BAD_VERSION;
+  /* If remote is too new, don't connect */
+  if (l_protocol_version < r_protocol_version) {
+    client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+                              "We don't support server version `%s'",
+                              version);
+    return SILC_SKE_STATUS_BAD_VERSION;
+  }
 
-  if (status != SILC_SKE_STATUS_OK)
-    client->ops->say(client, conn, 
-                    "We don't support server version `%s'", version);
+  ske->sock->version = r_protocol_version;
 
-  return status;
+  return SILC_SKE_STATUS_OK;
 }
 
 /* Callback that is called by the SKE to indicate that it is safe to
-   continue the execution of the protocol. Is given as argument to the 
-   silc_ske_initiator_finish or silc_ske_responder_phase_2 functions. 
+   continue the execution of the protocol. Is given as argument to the
+   silc_ske_initiator_finish or silc_ske_responder_phase_2 functions.
    This is called due to the fact that the public key verification
    process is asynchronous and we must not continue the protocl until
    the public key has been verified and this callback is called. */
@@ -232,7 +217,7 @@ static void silc_client_protocol_ke_continue(SilcSKE ske,
                                             void *context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientKEInternalContext *ctx = 
+  SilcClientKEInternalContext *ctx =
     (SilcClientKEInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   SilcClientConnection conn = ctx->sock->user_data;
@@ -240,22 +225,11 @@ static void silc_client_protocol_ke_continue(SilcSKE ske,
   SILC_LOG_DEBUG(("Start"));
 
   if (ske->status != SILC_SKE_STATUS_OK) {
-    if (ske->status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) {
-      client->ops->say(client, conn, 
-                      "Received unsupported server %s public key",
-                      ctx->sock->hostname);
-    } else if (ske->status == SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED) {
-      client->ops->say(client, conn, 
-                      "Remote host did not send its public key, even though "
-                      "it must send it");
-    } else {
-      client->ops->say(client, conn,
-                      "Error during key exchange protocol with server %s",
-                      ctx->sock->hostname);
-    }
-    
+    /* Call failure client operation */
+    client->internal->ops->failure(client, conn, protocol,
+                                  (void *)ske->status);
     protocol->state = SILC_PROTOCOL_STATE_ERROR;
-    silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+    silc_protocol_execute(protocol, client->schedule, 0, 0);
     return;
   }
 
@@ -264,18 +238,18 @@ static void silc_client_protocol_ke_continue(SilcSKE ske,
      if we are initiator. This is happens when this callback was sent
      to silc_ske_initiator_finish function. */
   if (ctx->responder == FALSE) {
-    silc_ske_end(ctx->ske, ctx->send_packet, context);
+    silc_ske_end(ctx->ske);
 
     /* End the protocol on the next round */
     protocol->state = SILC_PROTOCOL_STATE_END;
   }
 
-  /* Advance protocol state and call the next state if we are responder. 
+  /* Advance protocol state and call the next state if we are responder.
      This happens when this callback was sent to silc_ske_responder_phase_2
      function. */
   if (ctx->responder == TRUE) {
     protocol->state++;
-    silc_protocol_execute(protocol, client->timeout_queue, 0, 100000);
+    silc_protocol_execute(protocol, client->schedule, 0, 1);
   }
 }
 
@@ -285,7 +259,7 @@ static void silc_client_protocol_ke_continue(SilcSKE ske,
 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientKEInternalContext *ctx = 
+  SilcClientKEInternalContext *ctx =
     (SilcClientKEInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   SilcClientConnection conn = ctx->sock->user_data;
@@ -305,32 +279,34 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
       SilcSKE ske;
 
       /* Allocate Key Exchange object */
-      ske = silc_ske_alloc();
-      ctx->ske = ske;
-      ske->rng = client->rng;
-      ske->user_data = (void *)client;
-      
+      ctx->ske = ske = silc_ske_alloc(client->rng, client);
+
+      silc_ske_set_callbacks(ske, ctx->send_packet, NULL,
+                            ctx->verify,
+                            silc_client_protocol_ke_continue,
+                            silc_ske_check_version,
+                            context);
+
       if (ctx->responder == TRUE) {
        /* Start the key exchange by processing the received security
           properties packet from initiator. */
-       status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
-                                         silc_version_string,
-                                         ctx->packet->buffer, TRUE,
-                                         NULL, NULL);
+       status =
+         silc_ske_responder_start(ske, ctx->rng, ctx->sock,
+                                  client->internal->silc_client_version,
+                                  ctx->packet->buffer, TRUE);
       } else {
        SilcSKEStartPayload *start_payload;
 
        /* Assemble security properties. */
-       silc_ske_assemble_security_properties(ske, SILC_SKE_SP_FLAG_NONE, 
-                                             silc_version_string,
-                                             &start_payload);
+       silc_ske_assemble_security_properties(
+                                 ske, SILC_SKE_SP_FLAG_MUTUAL,
+                                 client->internal->silc_client_version,
+                                 &start_payload);
 
        /* Start the key exchange by sending our security properties
           to the remote end. */
        status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
-                                         start_payload,
-                                         ctx->send_packet,
-                                         context);
+                                         start_payload);
       }
 
       /* Return now if the procedure is pending */
@@ -344,35 +320,30 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
                        status));
 
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+       silc_protocol_execute(protocol, client->schedule, 0, 0);
        return;
       }
 
       /* Advance protocol state and call the next state if we are responder */
       protocol->state++;
       if (ctx->responder == TRUE)
-       silc_protocol_execute(protocol, client->timeout_queue, 0, 100000);
+       silc_protocol_execute(protocol, client->schedule, 0, 1);
     }
     break;
   case 2:
     {
-      /* 
-       * Phase 1 
+      /*
+       * Phase 1
        */
       if (ctx->responder == TRUE) {
        /* Sends the selected security properties to the initiator. */
-       status = 
-         silc_ske_responder_phase_1(ctx->ske, 
-                                    ctx->ske->start_payload,
-                                    ctx->send_packet,
-                                    context);
+       status = silc_ske_responder_phase_1(ctx->ske);
       } else {
        /* Call Phase-1 function. This processes the Key Exchange Start
           paylaod reply we just got from the responder. The callback
           function will receive the processed payload where we will
           save it. */
-       status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet->buffer, 
-                                           NULL, NULL);
+       status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet->buffer);
       }
 
       if (status != SILC_SKE_STATUS_OK) {
@@ -382,30 +353,27 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
                        status));
 
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+       silc_protocol_execute(protocol, client->schedule, 0, 0);
        return;
       }
 
       /* Advance protocol state and call next state if we are initiator */
       protocol->state++;
       if (ctx->responder == FALSE)
-       silc_protocol_execute(protocol, client->timeout_queue, 0, 100000);
+       silc_protocol_execute(protocol, client->schedule, 0, 1);
     }
     break;
   case 3:
     {
-      /* 
-       * Phase 2 
+      /*
+       * Phase 2
        */
       if (ctx->responder == TRUE) {
        /* Process the received Key Exchange 1 Payload packet from
           the initiator. This also creates our parts of the Diffie
           Hellman algorithm. The silc_client_protocol_ke_continue will
           be called after the public key has been verified. */
-       status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer, 
-                                           ctx->verify, context, 
-                                           silc_client_protocol_ke_continue,
-                                           context);
+       status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer);
       } else {
        /* Call the Phase-2 function. This creates Diffie Hellman
           key exchange parameters and sends our public part inside
@@ -413,8 +381,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
        status = silc_ske_initiator_phase_2(ctx->ske,
                                            client->public_key,
                                            client->private_key,
-                                           ctx->send_packet,
-                                           context);
+                                           SILC_SKE_PK_TYPE_SILC);
        protocol->state++;
       }
 
@@ -429,25 +396,23 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
                        status));
 
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+       silc_protocol_execute(protocol, client->schedule, 0, 0);
        return;
       }
     }
     break;
   case 4:
     {
-      /* 
+      /*
        * Finish protocol
        */
       if (ctx->responder == TRUE) {
        /* This creates the key exchange material and sends our
           public parts to the initiator inside Key Exchange 2 Payload. */
-       status = 
-         silc_ske_responder_finish(ctx->ske, 
+       status =
+         silc_ske_responder_finish(ctx->ske,
                                    client->public_key, client->private_key,
-                                   SILC_SKE_PK_TYPE_SILC,
-                                   ctx->send_packet,
-                                   context);
+                                   SILC_SKE_PK_TYPE_SILC);
 
        /* End the protocol on the next round */
        protocol->state = SILC_PROTOCOL_STATE_END;
@@ -455,10 +420,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
        /* Finish the protocol. This verifies the Key Exchange 2 payload
           sent by responder. The silc_client_protocol_ke_continue will
           be called after the public key has been verified. */
-       status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer,
-                                          ctx->verify, context, 
-                                          silc_client_protocol_ke_continue,
-                                          context);
+       status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer);
       }
 
       /* Return now if the procedure is pending */
@@ -467,16 +429,18 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
 
       if (status != SILC_SKE_STATUS_OK) {
         if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) {
-          client->ops->say(client, conn, 
-                          "Received unsupported server %s public key",
-                          ctx->sock->hostname);
+          client->internal->ops->say(
+                            client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+                            "Received unsupported server %s public key",
+                            ctx->sock->hostname);
         } else {
-          client->ops->say(client, conn,
+          client->internal->ops->say(
+                          client, conn, SILC_CLIENT_MESSAGE_AUDIT,
                           "Error during key exchange protocol with server %s",
                           ctx->sock->hostname);
         }
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+       silc_protocol_execute(protocol, client->schedule, 0, 0);
        return;
       }
     }
@@ -484,12 +448,12 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
 
   case SILC_PROTOCOL_STATE_END:
     {
-      /* 
+      /*
        * End protocol
        */
       SilcSKEKeyMaterial *keymat;
       int key_len = silc_cipher_get_key_len(ctx->ske->prop->cipher);
-      int hash_len = ctx->ske->prop->hash->hash->hash_len;
+      int hash_len = silc_hash_len(ctx->ske->prop->hash);
 
       /* Process the key material */
       keymat = silc_calloc(1, sizeof(*keymat));
@@ -497,7 +461,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
                                             keymat);
       if (status != SILC_SKE_STATUS_OK) {
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, client->timeout_queue, 0, 300000);
+       silc_protocol_execute(protocol, client->schedule, 0, 300000);
        silc_ske_free_key_material(keymat);
        return;
       }
@@ -506,17 +470,17 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
       /* Send Ok to the other end if we are responder. If we are initiator
         we have sent this already. */
       if (ctx->responder == TRUE)
-       silc_ske_end(ctx->ske, ctx->send_packet, context);
+       silc_ske_end(ctx->ske);
 
-      /* Unregister the timeout task since the protocol has ended. 
+      /* Unregister the timeout task since the protocol has ended.
         This was the timeout task to be executed if the protocol is
         not completed fast enough. */
       if (ctx->timeout_task)
-       silc_task_unregister(client->timeout_queue, ctx->timeout_task);
+       silc_schedule_task_del(client->schedule, ctx->timeout_task);
 
       /* Protocol has ended, call the final callback */
       if (protocol->final_callback)
-       silc_protocol_execute_final(protocol, client->timeout_queue);
+       silc_protocol_execute_final(protocol, client->schedule);
       else
        silc_protocol_free(protocol);
     }
@@ -526,14 +490,13 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
     /*
      * Error during protocol
      */
-    
+
     /* Send abort notification */
-    silc_ske_abort(ctx->ske, ctx->ske->status, 
-                  ctx->send_packet, context);
+    silc_ske_abort(ctx->ske, ctx->ske->status);
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, client->timeout_queue);
+      silc_protocol_execute_final(protocol, client->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -543,15 +506,15 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
      * Received failure from remote.
      */
 
-    /* Unregister the timeout task since the protocol has ended. 
+    /* Unregister the timeout task since the protocol has ended.
        This was the timeout task to be executed if the protocol is
        not completed fast enough. */
     if (ctx->timeout_task)
-      silc_task_unregister(client->timeout_queue, ctx->timeout_task);
+      silc_schedule_task_del(client->schedule, ctx->timeout_task);
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, client->timeout_queue);
+      silc_protocol_execute_final(protocol, client->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -566,26 +529,17 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
 
 static int
 silc_client_get_public_key_auth(SilcClient client,
-                               char *filepath,
+                               SilcClientConnection conn,
                                unsigned char *auth_data,
-                               uint32 *auth_data_len,
+                               SilcUInt32 *auth_data_len,
                                SilcSKE ske)
 {
   int len;
   SilcPKCS pkcs;
   SilcBuffer auth;
-  SilcPublicKey pub_key;
-
-  if (!silc_pkcs_load_public_key(filepath,&pub_key, SILC_PKCS_FILE_PEM))
-    if (!silc_pkcs_load_public_key(filepath, &pub_key, SILC_PKCS_FILE_BIN))
-      return FALSE;
 
-  silc_pkcs_alloc(pub_key->name, &pkcs);
-  if (!silc_pkcs_public_key_set(pkcs, pub_key)) {
-    silc_pkcs_free(pkcs);
-    silc_pkcs_public_key_free(pub_key);
-    return FALSE;
-  }
+  /* Use our default key */
+  pkcs = client->pkcs;
 
   /* Make the authentication data. Protocol says it is HASH plus
      KE Start Payload. */
@@ -598,34 +552,43 @@ silc_client_get_public_key_auth(SilcClient client,
                                          ske->start_payload_copy->len),
                     SILC_STR_END);
 
-  if (silc_pkcs_sign(pkcs, auth->data, auth->len, auth_data, auth_data_len)) {
-    silc_pkcs_free(pkcs);
+  if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data,
+                              auth->len, auth_data, auth_data_len)) {
     silc_buffer_free(auth);
-    silc_pkcs_public_key_free(pub_key);
     return TRUE;
   }
 
-  silc_pkcs_free(pkcs);
   silc_buffer_free(auth);
-  silc_pkcs_public_key_free(pub_key);
   return FALSE;
 }
 
 /* Continues the connection authentication protocol. This funtion may
    be called directly or used as SilcAskPassphrase callback. */
 
-static void 
+static void
 silc_client_conn_auth_continue(unsigned char *auth_data,
-                              uint32 auth_data_len, void *context)
+                              SilcUInt32 auth_data_len, void *context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientConnAuthInternalContext *ctx = 
+  SilcClientConnAuthInternalContext *ctx =
     (SilcClientConnAuthInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   SilcBuffer packet;
   int payload_len = 0;
-
-  SILC_LOG_DEBUG(("Start"));
+  unsigned char *autf8 = NULL;
+
+  SILC_LOG_DEBUG(("Sending authentication to server"));
+
+  /* Passphrase must be UTF-8 encoded, if it isn't encode it */
+  if (ctx->auth_meth == SILC_AUTH_PASSWORD &&
+      !silc_utf8_valid(auth_data, auth_data_len)) {
+    payload_len = silc_utf8_encoded_len(auth_data, auth_data_len,
+                                       SILC_STRING_ASCII);
+    autf8 = silc_calloc(payload_len, sizeof(*autf8));
+    auth_data_len = silc_utf8_encode(auth_data, auth_data_len,
+                                    SILC_STRING_ASCII, autf8, payload_len);
+    auth_data = autf8;
+  }
 
   payload_len = 4 + auth_data_len;
   packet = silc_buffer_alloc(payload_len);
@@ -641,21 +604,17 @@ silc_client_conn_auth_continue(unsigned char *auth_data,
                          SILC_PACKET_CONNECTION_AUTH,
                          NULL, 0, NULL, NULL,
                          packet->data, packet->len, TRUE);
-
-  if (auth_data) {
-    memset(auth_data, 0, auth_data_len);
-    silc_free(auth_data);
-  }
   silc_buffer_free(packet);
-      
+  silc_free(autf8);
+
   /* Next state is end of protocol */
   protocol->state = SILC_PROTOCOL_STATE_END;
 }
-                                                   
+
 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientConnAuthInternalContext *ctx = 
+  SilcClientConnAuthInternalContext *ctx =
     (SilcClientConnAuthInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   SilcClientConnection conn = ctx->sock->user_data;
@@ -668,12 +627,13 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
   switch(protocol->state) {
   case SILC_PROTOCOL_STATE_START:
     {
-      /* 
+      /*
        * Start protocol. We send authentication data to the server
        * to be authenticated.
        */
       unsigned char *auth_data = NULL;
-      uint32 auth_data_len = 0;
+      SilcUInt32 auth_data_len = 0;
+      unsigned char sign[1024];
 
       switch(ctx->auth_meth) {
       case SILC_AUTH_NONE:
@@ -688,27 +648,28 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
          break;
        }
 
-       client->ops->say(client, conn, 
-                        "Password authentication required by server %s",
-                        ctx->sock->hostname);
-       client->ops->ask_passphrase(client, conn,
-                                   silc_client_conn_auth_continue,
-                                   protocol);
+       client->internal->ops->say(
+                       client, conn, SILC_CLIENT_MESSAGE_INFO,
+                       "Password authentication required by server %s",
+                       ctx->sock->hostname);
+       client->internal->ops->ask_passphrase(client, conn,
+                                             silc_client_conn_auth_continue,
+                                             protocol);
        return;
        break;
 
       case SILC_AUTH_PUBLIC_KEY:
-       {
-         unsigned char sign[1024];
-
+       if (!ctx->auth_data) {
          /* Public key authentication */
-         silc_client_get_public_key_auth(client, ctx->auth_data,
-                                         sign, &auth_data_len, 
+         silc_client_get_public_key_auth(client, conn, sign, &auth_data_len,
                                          ctx->ske);
-         auth_data = silc_calloc(auth_data_len, sizeof(*auth_data));
-         memcpy(auth_data, sign, auth_data_len);
-         break;
+         auth_data = sign;
+       } else {
+         auth_data = ctx->auth_data;
+         auth_data_len = ctx->auth_data_len;
        }
+
+       break;
       }
 
       silc_client_conn_auth_continue(auth_data,
@@ -718,13 +679,13 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
 
   case SILC_PROTOCOL_STATE_END:
     {
-      /* 
+      /*
        * End protocol. Nothing special to be done here.
        */
 
       /* Protocol has ended, call the final callback */
       if (protocol->final_callback)
-       silc_protocol_execute_final(protocol, client->timeout_queue);
+       silc_protocol_execute_final(protocol, client->schedule);
       else
        silc_protocol_free(protocol);
     }
@@ -732,7 +693,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
 
   case SILC_PROTOCOL_STATE_ERROR:
     {
-      /* 
+      /*
        * Error. Send notify to remote.
        */
       unsigned char error[4];
@@ -746,7 +707,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
 
       /* On error the final callback is always called. */
       if (protocol->final_callback)
-       silc_protocol_execute_final(protocol, client->timeout_queue);
+       silc_protocol_execute_final(protocol, client->schedule);
       else
        silc_protocol_free(protocol);
     }
@@ -758,7 +719,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, client->timeout_queue);
+      silc_protocol_execute_final(protocol, client->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -774,7 +735,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
 
 /* Actually takes the new keys into use. */
 
-static void 
+static void
 silc_client_protocol_rekey_validate(SilcClient client,
                                    SilcClientRekeyInternalContext *ctx,
                                    SilcSocketConnection sock,
@@ -785,70 +746,67 @@ silc_client_protocol_rekey_validate(SilcClient client,
 
   if (ctx->responder == TRUE) {
     if (send) {
-      silc_cipher_set_key(conn->send_key, keymat->receive_enc_key, 
+      silc_cipher_set_key(conn->internal->send_key, keymat->receive_enc_key,
                          keymat->enc_key_len);
-      silc_cipher_set_iv(conn->send_key, keymat->receive_iv);
+      silc_cipher_set_iv(conn->internal->send_key, keymat->receive_iv);
+      silc_hmac_set_key(conn->internal->hmac_send, keymat->receive_hmac_key,
+                       keymat->hmac_key_len);
     } else {
-      silc_cipher_set_key(conn->receive_key, keymat->send_enc_key, 
+      silc_cipher_set_key(conn->internal->receive_key, keymat->send_enc_key,
                          keymat->enc_key_len);
-      silc_cipher_set_iv(conn->receive_key, keymat->send_iv);
+      silc_cipher_set_iv(conn->internal->receive_key, keymat->send_iv);
+      silc_hmac_set_key(conn->internal->hmac_receive, keymat->send_hmac_key,
+                       keymat->hmac_key_len);
     }
   } else {
     if (send) {
-      silc_cipher_set_key(conn->send_key, keymat->send_enc_key, 
+      silc_cipher_set_key(conn->internal->send_key, keymat->send_enc_key,
                          keymat->enc_key_len);
-      silc_cipher_set_iv(conn->send_key, keymat->send_iv);
+      silc_cipher_set_iv(conn->internal->send_key, keymat->send_iv);
+      silc_hmac_set_key(conn->internal->hmac_send, keymat->send_hmac_key,
+                       keymat->hmac_key_len);
     } else {
-      silc_cipher_set_key(conn->receive_key, keymat->receive_enc_key, 
-                         keymat->enc_key_len);
-      silc_cipher_set_iv(conn->receive_key, keymat->receive_iv);
+      silc_cipher_set_key(conn->internal->receive_key,
+                         keymat->receive_enc_key, keymat->enc_key_len);
+      silc_cipher_set_iv(conn->internal->receive_key, keymat->receive_iv);
+      silc_hmac_set_key(conn->internal->hmac_receive,
+                       keymat->receive_hmac_key, keymat->hmac_key_len);
     }
   }
 
-  if (send) {
-    silc_hmac_alloc(conn->hmac_receive->hmac->name, NULL, &conn->hmac_send);
-    silc_hmac_set_key(conn->hmac_send, keymat->hmac_key, 
-                     keymat->hmac_key_len);
-  } else {
-    silc_hmac_free(conn->hmac_receive);
-    conn->hmac_receive = conn->hmac_send;
-  }
-
   /* Save the current sending encryption key */
   if (!send) {
-    memset(conn->rekey->send_enc_key, 0, conn->rekey->enc_key_len);
-    silc_free(conn->rekey->send_enc_key);
-    conn->rekey->send_enc_key = 
-      silc_calloc(keymat->enc_key_len / 8,
-                 sizeof(*conn->rekey->send_enc_key));
-    memcpy(conn->rekey->send_enc_key, keymat->send_enc_key, 
-          keymat->enc_key_len / 8);
-    conn->rekey->enc_key_len = keymat->enc_key_len / 8;
+    memset(conn->internal->rekey->send_enc_key, 0,
+          conn->internal->rekey->enc_key_len);
+    silc_free(conn->internal->rekey->send_enc_key);
+    conn->internal->rekey->send_enc_key = silc_memdup(keymat->send_enc_key,
+                                                     keymat->enc_key_len / 8);
+    conn->internal->rekey->enc_key_len = keymat->enc_key_len / 8;
   }
 }
 
 /* This function actually re-generates (when not using PFS) the keys and
    takes them into use. */
 
-static void 
+static void
 silc_client_protocol_rekey_generate(SilcClient client,
                                    SilcClientRekeyInternalContext *ctx,
                                    bool send)
 {
   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
   SilcSKEKeyMaterial *keymat;
-  uint32 key_len = silc_cipher_get_key_len(conn->send_key);
-  uint32 hash_len = conn->hash->hash->hash_len;
+  SilcUInt32 key_len = silc_cipher_get_key_len(conn->internal->send_key);
+  SilcUInt32 hash_len = silc_hash_len(conn->internal->hash);
 
   SILC_LOG_DEBUG(("Generating new %s session keys (no PFS)",
                  send ? "sending" : "receiving"));
 
   /* Generate the new key */
   keymat = silc_calloc(1, sizeof(*keymat));
-  silc_ske_process_key_material_data(conn->rekey->send_enc_key,
-                                    conn->rekey->enc_key_len,
-                                    16, key_len, hash_len, 
-                                    conn->hash, keymat);
+  silc_ske_process_key_material_data(conn->internal->rekey->send_enc_key,
+                                    conn->internal->rekey->enc_key_len,
+                                    16, key_len, hash_len,
+                                    conn->internal->hash, keymat);
 
   /* Set the keys into use */
   silc_client_protocol_rekey_validate(client, ctx, ctx->sock, keymat, send);
@@ -859,17 +817,17 @@ silc_client_protocol_rekey_generate(SilcClient client,
 /* This function actually re-generates (with PFS) the keys and
    takes them into use. */
 
-static void 
+static void
 silc_client_protocol_rekey_generate_pfs(SilcClient client,
                                        SilcClientRekeyInternalContext *ctx,
                                        bool send)
 {
   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
   SilcSKEKeyMaterial *keymat;
-  uint32 key_len = silc_cipher_get_key_len(conn->send_key);
-  uint32 hash_len = conn->hash->hash->hash_len;
+  SilcUInt32 key_len = silc_cipher_get_key_len(conn->internal->send_key);
+  SilcUInt32 hash_len = silc_hash_len(conn->internal->hash);
   unsigned char *tmpbuf;
-  uint32 klen;
+  SilcUInt32 klen;
 
   SILC_LOG_DEBUG(("Generating new %s session keys (with PFS)",
                  send ? "sending" : "receiving"));
@@ -879,8 +837,8 @@ silc_client_protocol_rekey_generate_pfs(SilcClient client,
 
   /* Generate the new key */
   keymat = silc_calloc(1, sizeof(*keymat));
-  silc_ske_process_key_material_data(tmpbuf, klen, 16, key_len, hash_len, 
-                                    conn->hash, keymat);
+  silc_ske_process_key_material_data(tmpbuf, klen, 16, key_len, hash_len,
+                                    conn->internal->hash, keymat);
 
   /* Set the keys into use */
   silc_client_protocol_rekey_validate(client, ctx, ctx->sock, keymat, send);
@@ -893,14 +851,14 @@ silc_client_protocol_rekey_generate_pfs(SilcClient client,
 /* Packet sending callback. This function is provided as packet sending
    routine to the Key Exchange functions. */
 
-static void 
+static void
 silc_client_protocol_rekey_send_packet(SilcSKE ske,
                                       SilcBuffer packet,
                                       SilcPacketType type,
                                       void *context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientRekeyInternalContext *ctx = 
+  SilcClientRekeyInternalContext *ctx =
     (SilcClientRekeyInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
 
@@ -914,7 +872,7 @@ silc_client_protocol_rekey_send_packet(SilcSKE ske,
 SILC_TASK_CALLBACK(silc_client_protocol_rekey)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientRekeyInternalContext *ctx = 
+  SilcClientRekeyInternalContext *ctx =
     (SilcClientRekeyInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
@@ -930,7 +888,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
   switch(protocol->state) {
   case SILC_PROTOCOL_STATE_START:
     {
-      /* 
+      /*
        * Start protocol.
        */
 
@@ -940,7 +898,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
         */
 
        if (ctx->pfs == TRUE) {
-         /* 
+         /*
           * Use Perfect Forward Secrecy, ie. negotiate the key material
           * using the SKE protocol.
           */
@@ -948,79 +906,83 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
          if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_1) {
            /* Error in protocol */
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, client->timeout_queue, 0, 300000);
+           silc_protocol_execute(protocol, client->schedule, 0, 300000);
          }
 
-         ctx->ske = silc_ske_alloc();
-         ctx->ske->rng = client->rng;
+         ctx->ske = silc_ske_alloc(client->rng, client);
          ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop));
-         silc_ske_get_group_by_number(conn->rekey->ske_group,
+         silc_ske_group_get_by_number(conn->internal->rekey->ske_group,
                                       &ctx->ske->prop->group);
 
-         status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer,
-                                             NULL, NULL, NULL, NULL);
+         silc_ske_set_callbacks(ctx->ske,
+                                silc_client_protocol_rekey_send_packet,
+                                NULL,  NULL, NULL, silc_ske_check_version,
+                                context);
+
+         status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer);
          if (status != SILC_SKE_STATUS_OK) {
            SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
                              status));
-           
+
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, client->timeout_queue, 0, 300000);
+           silc_protocol_execute(protocol, client->schedule, 0, 300000);
            return;
          }
 
          /* Advance the protocol state */
          protocol->state++;
-         silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+         silc_protocol_execute(protocol, client->schedule, 0, 0);
        } else {
          /*
           * Do normal and simple re-key.
           */
 
          /* Send the REKEY_DONE to indicate we will take new keys into use */
-         silc_client_packet_send(client, ctx->sock, 
-                                 SILC_PACKET_REKEY_DONE, 
+         silc_client_packet_send(client, ctx->sock,
+                                 SILC_PACKET_REKEY_DONE,
                                  NULL, 0, NULL, NULL, NULL, 0, FALSE);
 
          /* After we send REKEY_DONE we must set the sending encryption
             key to the new key since all packets after this packet must
             encrypted with the new key. */
          silc_client_protocol_rekey_generate(client, ctx, TRUE);
+         silc_client_packet_queue_purge(client, ctx->sock);
 
          /* The protocol ends in next stage. */
          protocol->state = SILC_PROTOCOL_STATE_END;
        }
-      
+
       } else {
        /*
         * We are the initiator of this protocol
         */
 
        /* Start the re-key by sending the REKEY packet */
-       silc_client_packet_send(client, ctx->sock, SILC_PACKET_REKEY, 
+       silc_client_packet_send(client, ctx->sock, SILC_PACKET_REKEY,
                                NULL, 0, NULL, NULL, NULL, 0, FALSE);
 
        if (ctx->pfs == TRUE) {
-         /* 
+         /*
           * Use Perfect Forward Secrecy, ie. negotiate the key material
           * using the SKE protocol.
           */
-         ctx->ske = silc_ske_alloc();
-         ctx->ske->rng = client->rng;
+         ctx->ske = silc_ske_alloc(client->rng, client);
          ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop));
-         silc_ske_get_group_by_number(conn->rekey->ske_group,
+         silc_ske_group_get_by_number(conn->internal->rekey->ske_group,
                                       &ctx->ske->prop->group);
 
-         status = 
-           silc_ske_initiator_phase_2(ctx->ske, NULL, NULL,
-                                      silc_client_protocol_rekey_send_packet,
-                                      context);
+         silc_ske_set_callbacks(ctx->ske,
+                                silc_client_protocol_rekey_send_packet,
+                                NULL,  NULL, NULL, silc_ske_check_version,
+                                context);
 
+         status =  silc_ske_initiator_phase_2(ctx->ske, NULL, NULL, 0);
          if (status != SILC_SKE_STATUS_OK) {
            SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
                              status));
-           
+
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, client->timeout_queue, 0, 300000);
+           silc_protocol_execute(protocol, client->schedule, 0, 300000);
            return;
          }
 
@@ -1031,16 +993,17 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
           * Do normal and simple re-key.
           */
 
-         /* Send the REKEY_DONE to indicate we will take new keys into use 
-            now. */ 
-         silc_client_packet_send(client, ctx->sock, 
-                                 SILC_PACKET_REKEY_DONE, 
+         /* Send the REKEY_DONE to indicate we will take new keys into use
+            now. */
+         silc_client_packet_send(client, ctx->sock,
+                                 SILC_PACKET_REKEY_DONE,
                                  NULL, 0, NULL, NULL, NULL, 0, FALSE);
 
          /* After we send REKEY_DONE we must set the sending encryption
             key to the new key since all packets after this packet must
             encrypted with the new key. */
          silc_client_protocol_rekey_generate(client, ctx, TRUE);
+         silc_client_packet_queue_purge(client, ctx->sock);
 
          /* The protocol ends in next stage. */
          protocol->state = SILC_PROTOCOL_STATE_END;
@@ -1059,18 +1022,15 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
         * Send our KE packe to the initiator now that we've processed
         * the initiator's KE packet.
         */
-       status = 
-         silc_ske_responder_finish(ctx->ske, NULL, NULL, 
-                                   SILC_SKE_PK_TYPE_SILC,
-                                   silc_client_protocol_rekey_send_packet,
-                                   context);
+       status = silc_ske_responder_finish(ctx->ske, NULL, NULL,
+                                          SILC_SKE_PK_TYPE_SILC);
 
          if (status != SILC_SKE_STATUS_OK) {
            SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
                              status));
-           
+
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, client->timeout_queue, 0, 300000);
+           silc_protocol_execute(protocol, client->schedule, 0, 300000);
            return;
          }
       }
@@ -1083,27 +1043,26 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
        if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_2) {
          /* Error in protocol */
          protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, client->timeout_queue, 0, 300000);
+         silc_protocol_execute(protocol, client->schedule, 0, 300000);
        }
-       
-       status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer,
-                                          NULL, NULL, NULL, NULL);
+
+       status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer);
        if (status != SILC_SKE_STATUS_OK) {
          SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
                            status));
-         
+
          protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, client->timeout_queue, 0, 300000);
+         silc_protocol_execute(protocol, client->schedule, 0, 300000);
          return;
        }
       }
     }
 
-    /* Send the REKEY_DONE to indicate we will take new keys into use 
-       now. */ 
-    silc_client_packet_send(client, ctx->sock, SILC_PACKET_REKEY_DONE, 
+    /* Send the REKEY_DONE to indicate we will take new keys into use
+       now. */
+    silc_client_packet_send(client, ctx->sock, SILC_PACKET_REKEY_DONE,
                            NULL, 0, NULL, NULL, NULL, 0, FALSE);
-    
+
     /* After we send REKEY_DONE we must set the sending encryption
        key to the new key since all packets after this packet must
        encrypted with the new key. */
@@ -1114,23 +1073,26 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
     break;
 
   case SILC_PROTOCOL_STATE_END:
-    /* 
+    /*
      * End protocol
      */
 
     if (ctx->packet->type != SILC_PACKET_REKEY_DONE) {
       /* Error in protocol */
       protocol->state = SILC_PROTOCOL_STATE_ERROR;
-      silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+      silc_protocol_execute(protocol, client->schedule, 0, 0);
     }
 
     /* We received the REKEY_DONE packet and all packets after this is
        encrypted with the new key so set the decryption key to the new key */
-    silc_client_protocol_rekey_generate(client, ctx, FALSE);
+    if (ctx->pfs == TRUE)
+      silc_client_protocol_rekey_generate_pfs(client, ctx, FALSE);
+    else
+      silc_client_protocol_rekey_generate(client, ctx, FALSE);
 
     /* Protocol has ended, call the final callback */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, client->timeout_queue);
+      silc_protocol_execute_final(protocol, client->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -1142,14 +1104,12 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
 
     if (ctx->pfs == TRUE) {
       /* Send abort notification */
-      silc_ske_abort(ctx->ske, ctx->ske->status, 
-                    silc_client_protocol_ke_send_packet,
-                    context);
+      silc_ske_abort(ctx->ske, ctx->ske->status);
     }
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, client->timeout_queue);
+      silc_protocol_execute_final(protocol, client->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -1161,7 +1121,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, client->timeout_queue);
+      silc_protocol_execute_final(protocol, client->schedule);
     else
       silc_protocol_free(protocol);
     break;