Created SILC Crypto Toolkit git repository.
[crypto.git] / lib / silcske / silcske.c
diff --git a/lib/silcske/silcske.c b/lib/silcske/silcske.c
deleted file mode 100644 (file)
index b3a151e..0000000
+++ /dev/null
@@ -1,3623 +0,0 @@
-/*
-
-  silcske.c
-
-  Author: Pekka Riikonen <priikone@silcnet.org>
-
-  Copyright (C) 2000 - 2007 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; version 2 of the License.
-
-  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
-  GNU General Public License for more details.
-
-*/
-/* $Id$ */
-
-#include "silc.h"
-#include "silcske.h"
-#include "groups_internal.h"
-
-/************************** Types and definitions ***************************/
-
-/* Structure to hold all SKE callbacks. */
-struct SilcSKECallbacksStruct {
-  SilcSKEVerifyCb verify_key;
-  SilcSKECompletionCb completed;
-  void *context;
-};
-
-/************************ Static utility functions **************************/
-
-/* States */
-SILC_FSM_STATE(silc_ske_st_initiator_start);
-SILC_FSM_STATE(silc_ske_st_initiator_phase1);
-SILC_FSM_STATE(silc_ske_st_initiator_phase2);
-SILC_FSM_STATE(silc_ske_st_initiator_phase2_send);
-SILC_FSM_STATE(silc_ske_st_initiator_phase3);
-SILC_FSM_STATE(silc_ske_st_initiator_phase4);
-SILC_FSM_STATE(silc_ske_st_initiator_phase5);
-SILC_FSM_STATE(silc_ske_st_initiator_end);
-SILC_FSM_STATE(silc_ske_st_initiator_aborted);
-SILC_FSM_STATE(silc_ske_st_initiator_error);
-SILC_FSM_STATE(silc_ske_st_initiator_failure);
-SILC_FSM_STATE(silc_ske_st_responder_start);
-SILC_FSM_STATE(silc_ske_st_responder_phase1);
-SILC_FSM_STATE(silc_ske_st_responder_phase2);
-SILC_FSM_STATE(silc_ske_st_responder_phase4);
-SILC_FSM_STATE(silc_ske_st_responder_phase5);
-SILC_FSM_STATE(silc_ske_st_responder_phase5_send);
-SILC_FSM_STATE(silc_ske_st_responder_end);
-SILC_FSM_STATE(silc_ske_st_responder_aborted);
-SILC_FSM_STATE(silc_ske_st_responder_failure);
-SILC_FSM_STATE(silc_ske_st_responder_error);
-SILC_FSM_STATE(silc_ske_st_rekey_initiator_start);
-SILC_FSM_STATE(silc_ske_st_rekey_initiator_done);
-SILC_FSM_STATE(silc_ske_st_rekey_initiator_end);
-SILC_FSM_STATE(silc_ske_st_rekey_responder_wait);
-SILC_FSM_STATE(silc_ske_st_rekey_responder_start);
-SILC_FSM_STATE(silc_ske_st_rekey_responder_done);
-SILC_FSM_STATE(silc_ske_st_rekey_responder_end);
-SILC_TASK_CALLBACK(silc_ske_packet_send_retry);
-
-SilcSKEKeyMaterial
-silc_ske_process_key_material(SilcSKE ske,
-                             SilcUInt32 req_iv_len,
-                             SilcUInt32 req_enc_key_len,
-                             SilcUInt32 req_hmac_key_len,
-                             SilcSKERekeyMaterial *rekey);
-static SilcBool silc_ske_packet_send(SilcSKE ske,
-                                    SilcPacketType type,
-                                    SilcPacketFlags flags,
-                                    const unsigned char *data,
-                                    SilcUInt32 data_len);
-
-/* Packet callback */
-
-static SilcBool silc_ske_packet_receive(SilcPacketEngine engine,
-                                       SilcPacketStream stream,
-                                       SilcPacket packet,
-                                       void *callback_context,
-                                       void *app_context)
-{
-  SilcSKE ske = callback_context;
-
-  /* Clear retransmission */
-  ske->retry_timer = SILC_SKE_RETRY_MIN;
-  ske->retry_count = 0;
-  silc_schedule_task_del_by_callback(ske->schedule,
-                                    silc_ske_packet_send_retry);
-
-  /* Signal for new packet */
-  ske->packet = packet;
-
-  /* Check if we were aborted */
-  if (ske->aborted) {
-    silc_packet_free(packet);
-    ske->packet = NULL;
-
-    if (ske->responder)
-      silc_fsm_next(&ske->fsm, silc_ske_st_responder_aborted);
-    else
-      silc_fsm_next(&ske->fsm, silc_ske_st_initiator_aborted);
-
-    silc_fsm_continue_sync(&ske->fsm);
-    return TRUE;
-  }
-
-  /* See if received failure from remote */
-  if (packet->type == SILC_PACKET_FAILURE) {
-    if (ske->responder)
-      silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
-    else
-      silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
-  }
-
-  /* Handle rekey and SUCCESS packets synchronously.  After SUCCESS packets
-     they keys are taken into use immediately, hence the synchronous
-     processing to get the keys in use as soon as possible. */
-  if (ske->rekeying || packet->type == SILC_PACKET_SUCCESS)
-    silc_fsm_continue_sync(&ske->fsm);
-  else
-    silc_fsm_continue(&ske->fsm);
-
-  return TRUE;
-}
-
-/* Packet stream callbacks */
-static SilcPacketCallbacks silc_ske_stream_cbs =
-{
-  silc_ske_packet_receive, NULL, NULL
-};
-
-/* Aborts SKE protocol */
-
-static void silc_ske_abort(SilcAsyncOperation op, void *context)
-{
-  SilcSKE ske = context;
-  if (ske->key_op)
-    silc_async_abort(ske->key_op, NULL, NULL);
-  ske->aborted = TRUE;
-}
-
-/* Public key verification completion callback */
-
-static void silc_ske_pk_verified(SilcSKE ske, SilcSKEStatus status,
-                                void *completion_context)
-{
-  ske->status = status;
-  SILC_FSM_CALL_CONTINUE(&ske->fsm);
-}
-
-/* SKR find callback */
-
-static void silc_ske_skr_callback(SilcSKR repository,
-                                 SilcSKRFind find,
-                                 SilcSKRStatus status,
-                                 SilcDList keys, void *context)
-{
-  SilcSKE ske = context;
-
-  silc_skr_find_free(find);
-
-  if (status != SILC_SKR_OK) {
-    if (ske->callbacks->verify_key) {
-      /* Verify from application */
-      ske->callbacks->verify_key(ske, ske->prop->public_key,
-                                ske->callbacks->context,
-                                silc_ske_pk_verified, NULL);
-      return;
-    }
-  }
-
-  if (keys)
-    silc_dlist_uninit(keys);
-
-  /* Continue */
-  ske->status = (status == SILC_SKR_OK ? SILC_SKE_STATUS_OK :
-                SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY);
-  SILC_FSM_CALL_CONTINUE(&ske->fsm);
-}
-
-/* Checks remote and local versions */
-
-static SilcSKEStatus silc_ske_check_version(SilcSKE ske)
-{
-  SilcUInt32 r_software_version = 0;
-  char *r_software_string = NULL;
-
-  if (!ske->remote_version || !ske->version)
-    return SILC_SKE_STATUS_BAD_VERSION;
-
-  if (!silc_parse_version_string(ske->remote_version, NULL, NULL,
-                                &r_software_version,
-                                &r_software_string, NULL))
-    return SILC_SKE_STATUS_BAD_VERSION;
-
-  return SILC_SKE_STATUS_OK;
-}
-
-/* Selects the supported security properties from the initiator's Key
-   Exchange Start Payload.  A responder function.  Saves our reply
-   start payload to ske->start_payload. */
-
-static SilcSKEStatus
-silc_ske_select_security_properties(SilcSKE ske,
-                                   SilcSKEStartPayload remote_payload,
-                                   SilcSKESecurityProperties *prop)
-{
-  SilcSKEStatus status;
-  SilcSKEStartPayload rp, payload;
-  char *cp;
-  int len;
-
-  SILC_LOG_DEBUG(("Parsing KE Start Payload"));
-
-  rp = remote_payload;
-
-  /* Check for mandatory fields */
-  if (!rp->ke_grp_len) {
-    SILC_LOG_DEBUG(("KE group not defined in payload"));
-    return SILC_SKE_STATUS_BAD_PAYLOAD;
-  }
-  if (!rp->pkcs_alg_len) {
-    SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
-    return SILC_SKE_STATUS_BAD_PAYLOAD;
-  }
-  if (!rp->enc_alg_len) {
-    SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
-    return SILC_SKE_STATUS_BAD_PAYLOAD;
-  }
-  if (!rp->hash_alg_len) {
-    SILC_LOG_DEBUG(("Hash alg not defined in payload"));
-    return SILC_SKE_STATUS_BAD_PAYLOAD;
-  }
-  if (!rp->hmac_alg_len) {
-    SILC_LOG_DEBUG(("HMAC not defined in payload"));
-    return SILC_SKE_STATUS_BAD_PAYLOAD;
-  }
-
-  /* Allocate security properties */
-  *prop = silc_calloc(1, sizeof(**prop));
-  if (!(*prop))
-    return SILC_SKE_STATUS_OUT_OF_MEMORY;
-
-  /* Allocate our reply start payload */
-  payload = silc_calloc(1, sizeof(*payload));
-  if (!payload) {
-    silc_free(*prop);
-    return SILC_SKE_STATUS_OUT_OF_MEMORY;
-  }
-
-  /* Check version string */
-  ske->remote_version = silc_memdup(rp->version, rp->version_len);
-  status = silc_ske_check_version(ske);
-  if (status != SILC_SKE_STATUS_OK) {
-    ske->status = status;
-    return status;
-  }
-
-  /* Flags are returned unchanged. */
-  (*prop)->flags = payload->flags = rp->flags;
-
-  /* Take cookie, we must return it to sender unmodified. */
-  payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
-  if (!payload->cookie) {
-    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-    return status;
-  }
-  payload->cookie_len = SILC_SKE_COOKIE_LEN;
-  memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
-
-  /* In case IV included flag and session port is set the first 16-bits of
-     cookie will include our session port. */
-  if (rp->flags & SILC_SKE_SP_FLAG_IV_INCLUDED && ske->session_port) {
-    /* Take remote port */
-    SILC_GET16_MSB((*prop)->remote_port, payload->cookie);
-
-    /* Put out port */
-    SILC_PUT16_MSB(ske->session_port, payload->cookie);
-  }
-
-  /* Put our version to our reply */
-  payload->version = strdup(ske->version);
-  if (!payload->version) {
-    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-    return status;
-  }
-  payload->version_len = strlen(ske->version);
-
-  /* Get supported Key Exchange groups */
-  cp = rp->ke_grp_list;
-  if (cp && strchr(cp, ',')) {
-    while(cp) {
-      char *item;
-
-      len = strcspn(cp, ",");
-      item = silc_calloc(len + 1, sizeof(char));
-      if (!item) {
-       ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-       return status;
-      }
-      memcpy(item, cp, len);
-
-      SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
-
-      if (silc_ske_group_get_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
-       SILC_LOG_DEBUG(("Found KE group `%s'", item));
-
-       payload->ke_grp_len = len;
-       payload->ke_grp_list = item;
-       break;
-      }
-
-      cp += len;
-      if (strlen(cp) == 0)
-       cp = NULL;
-      else
-       cp++;
-
-      if (item)
-       silc_free(item);
-    }
-
-    if (!payload->ke_grp_len && !payload->ke_grp_list) {
-      SILC_LOG_DEBUG(("Could not find supported KE group"));
-      silc_free(payload);
-      return SILC_SKE_STATUS_UNKNOWN_GROUP;
-    }
-  } else {
-    SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
-    SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
-
-    payload->ke_grp_len = rp->ke_grp_len;
-    payload->ke_grp_list = strdup(rp->ke_grp_list);
-  }
-
-  /* Save group to security properties */
-  status = silc_ske_group_get_by_name(payload->ke_grp_list, &(*prop)->group);
-  if (status != SILC_SKE_STATUS_OK) {
-    silc_free(payload);
-    return SILC_SKE_STATUS_UNKNOWN_GROUP;
-  }
-
-  /* Get supported PKCS algorithms */
-  cp = rp->pkcs_alg_list;
-  if (cp && strchr(cp, ',')) {
-    while(cp) {
-      char *item;
-
-      len = strcspn(cp, ",");
-      item = silc_calloc(len + 1, sizeof(char));
-      if (!item) {
-       ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-       return status;
-      }
-      memcpy(item, cp, len);
-
-      SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
-
-      if (silc_pkcs_find_algorithm(item, NULL)) {
-       SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
-
-       payload->pkcs_alg_len = len;
-       payload->pkcs_alg_list = item;
-       break;
-      }
-
-      cp += len;
-      if (strlen(cp) == 0)
-       cp = NULL;
-      else
-       cp++;
-
-      if (item)
-       silc_free(item);
-    }
-
-    if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
-      SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
-      silc_free(payload->ke_grp_list);
-      silc_free(payload);
-      return SILC_SKE_STATUS_UNKNOWN_PKCS;
-    }
-  } else {
-    SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
-    SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
-
-    payload->pkcs_alg_len = rp->pkcs_alg_len;
-    payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
-  }
-
-  /* Get supported encryption algorithms */
-  cp = rp->enc_alg_list;
-  if (cp && strchr(cp, ',')) {
-    while(cp) {
-      char *item;
-
-      len = strcspn(cp, ",");
-      item = silc_calloc(len + 1, sizeof(char));
-      if (!item) {
-       ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-       return status;
-      }
-      memcpy(item, cp, len);
-
-      SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
-
-      if (silc_cipher_is_supported(item) == TRUE) {
-       SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
-
-       payload->enc_alg_len = len;
-       payload->enc_alg_list = item;
-       break;
-      }
-
-      cp += len;
-      if (strlen(cp) == 0)
-       cp = NULL;
-      else
-       cp++;
-
-      if (item)
-       silc_free(item);
-    }
-
-    if (!payload->enc_alg_len && !payload->enc_alg_list) {
-      SILC_LOG_DEBUG(("Could not find supported encryption alg"));
-      silc_free(payload->ke_grp_list);
-      silc_free(payload->pkcs_alg_list);
-      silc_free(payload);
-      return SILC_SKE_STATUS_UNKNOWN_CIPHER;
-    }
-  } else {
-    SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
-                   rp->enc_alg_list));
-
-    payload->enc_alg_len = rp->enc_alg_len;
-    payload->enc_alg_list = strdup(rp->enc_alg_list);
-  }
-
-  /* Save selected cipher to security properties */
-  if (silc_cipher_alloc(payload->enc_alg_list, &(*prop)->cipher) == FALSE) {
-    silc_free(payload->ke_grp_list);
-    silc_free(payload->pkcs_alg_list);
-    silc_free(payload);
-    return SILC_SKE_STATUS_UNKNOWN_CIPHER;
-  }
-
-  /* Get supported hash algorithms */
-  cp = rp->hash_alg_list;
-  if (cp && strchr(cp, ',')) {
-    while(cp) {
-      char *item;
-
-      len = strcspn(cp, ",");
-      item = silc_calloc(len + 1, sizeof(char));
-      if (!item) {
-       ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-       return status;
-      }
-      memcpy(item, cp, len);
-
-      SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
-
-      if (silc_hash_is_supported(item) == TRUE) {
-       SILC_LOG_DEBUG(("Found hash alg `%s'", item));
-
-       payload->hash_alg_len = len;
-       payload->hash_alg_list = item;
-       break;
-      }
-
-      cp += len;
-      if (strlen(cp) == 0)
-       cp = NULL;
-      else
-       cp++;
-
-      if (item)
-       silc_free(item);
-    }
-
-    if (!payload->hash_alg_len && !payload->hash_alg_list) {
-      SILC_LOG_DEBUG(("Could not find supported hash alg"));
-      silc_free(payload->ke_grp_list);
-      silc_free(payload->pkcs_alg_list);
-      silc_free(payload->enc_alg_list);
-      silc_free(payload);
-      return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
-    }
-  } else {
-    SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
-                   rp->hash_alg_list));
-
-    payload->hash_alg_len = rp->hash_alg_len;
-    payload->hash_alg_list = strdup(rp->hash_alg_list);
-  }
-
-  /* Save selected hash algorithm to security properties */
-  if (silc_hash_alloc(payload->hash_alg_list, &(*prop)->hash) == FALSE) {
-    silc_free(payload->ke_grp_list);
-    silc_free(payload->pkcs_alg_list);
-    silc_free(payload->enc_alg_list);
-    silc_free(payload);
-    return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
-  }
-
-  /* Get supported HMACs */
-  cp = rp->hmac_alg_list;
-  if (cp && strchr(cp, ',')) {
-    while(cp) {
-      char *item;
-
-      len = strcspn(cp, ",");
-      item = silc_calloc(len + 1, sizeof(char));
-      if (!item) {
-       ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-       return status;
-      }
-      memcpy(item, cp, len);
-
-      SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
-
-      if (silc_hmac_is_supported(item) == TRUE) {
-       SILC_LOG_DEBUG(("Found HMAC `%s'", item));
-
-       payload->hmac_alg_len = len;
-       payload->hmac_alg_list = item;
-       break;
-      }
-
-      cp += len;
-      if (strlen(cp) == 0)
-       cp = NULL;
-      else
-       cp++;
-
-      if (item)
-       silc_free(item);
-    }
-
-    if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
-      SILC_LOG_DEBUG(("Could not find supported HMAC"));
-      silc_free(payload->ke_grp_list);
-      silc_free(payload->pkcs_alg_list);
-      silc_free(payload->enc_alg_list);
-      silc_free(payload->hash_alg_list);
-      silc_free(payload);
-      return SILC_SKE_STATUS_UNKNOWN_HMAC;
-    }
-  } else {
-    SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
-                   rp->hmac_alg_list));
-
-    payload->hmac_alg_len = rp->hmac_alg_len;
-    payload->hmac_alg_list = strdup(rp->hmac_alg_list);
-  }
-
-  /* Save selected HMACc to security properties */
-  if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &(*prop)->hmac) == FALSE) {
-    silc_free(payload->ke_grp_list);
-    silc_free(payload->pkcs_alg_list);
-    silc_free(payload->enc_alg_list);
-    silc_free(payload->hash_alg_list);
-    silc_free(payload);
-    return SILC_SKE_STATUS_UNKNOWN_HMAC;
-  }
-
-  /* Get supported compression algorithms */
-  cp = rp->comp_alg_list;
-  if (cp && strchr(cp, ',')) {
-    while(cp) {
-      char *item;
-
-      len = strcspn(cp, ",");
-      item = silc_calloc(len + 1, sizeof(char));
-      if (!item) {
-       ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-       return status;
-      }
-      memcpy(item, cp, len);
-
-      SILC_LOG_DEBUG(("Proposed Compression `%s'", item));
-
-#if 1
-      if (!strcmp(item, "none")) {
-       SILC_LOG_DEBUG(("Found Compression `%s'", item));
-       payload->comp_alg_len = len;
-       payload->comp_alg_list = item;
-       break;
-      }
-#else
-      if (silc_hmac_is_supported(item) == TRUE) {
-       SILC_LOG_DEBUG(("Found Compression `%s'", item));
-       payload->comp_alg_len = len;
-       payload->comp_alg_list = item;
-       break;
-      }
-#endif
-
-      cp += len;
-      if (strlen(cp) == 0)
-       cp = NULL;
-      else
-       cp++;
-
-      if (item)
-       silc_free(item);
-    }
-  }
-
-  payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
-    2 + payload->version_len +
-    2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
-    2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
-    2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
-
-  /* Save our reply payload */
-  ske->start_payload = payload;
-
-  return SILC_SKE_STATUS_OK;
-}
-
-/* Creates random number such that 1 < rnd < n and at most length
-   of len bits. The rnd sent as argument must be initialized. */
-
-static SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n,
-                                        SilcUInt32 len,
-                                        SilcMPInt *rnd)
-{
-  SilcSKEStatus status = SILC_SKE_STATUS_OK;
-  unsigned char string[2048];
-  SilcUInt32 l;
-
-  if (!len)
-    return SILC_SKE_STATUS_ERROR;
-
-  SILC_LOG_DEBUG(("Creating random number"));
-
-  l = ((len - 1) / 8);
-
-  /* Get the random number as string */
-  if (!silc_rng_get_rn_data(ske->rng, l, string, sizeof(string)))
-    return SILC_SKE_STATUS_OUT_OF_MEMORY;
-
-  /* Decode the string into a MP integer */
-  silc_mp_bin2mp(string, l, rnd);
-  silc_mp_mod_2exp(rnd, rnd, len);
-
-  /* Checks */
-  if (silc_mp_cmp_ui(rnd, 1) < 0)
-    status = SILC_SKE_STATUS_ERROR;
-  if (silc_mp_cmp(rnd, n) >= 0)
-    status = SILC_SKE_STATUS_ERROR;
-
-  memset(string, 'F', l);
-
-  return status;
-}
-
-/* Creates a hash value HASH as defined in the SKE protocol. If the
-   `initiator' is TRUE then this function is used to create the HASH_i
-   hash value defined in the protocol. If it is FALSE then this is used
-   to create the HASH value defined by the protocol. */
-
-static SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
-                                       unsigned char *return_hash,
-                                       SilcUInt32 *return_hash_len,
-                                       int initiator)
-{
-  SilcSKEStatus status = SILC_SKE_STATUS_OK;
-  SilcBuffer buf;
-  unsigned char *e, *f, *KEY, *s_data;
-  SilcUInt32 e_len, f_len, KEY_len, s_len;
-  int ret;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (initiator == FALSE) {
-    s_data = (ske->start_payload_copy ?
-            silc_buffer_data(ske->start_payload_copy) : NULL);
-    s_len = (ske->start_payload_copy ?
-            silc_buffer_len(ske->start_payload_copy) : 0);
-    e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
-    f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
-    KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
-
-    /* Format the buffer used to compute the hash value */
-    buf = silc_buffer_alloc_size(s_len +
-                                ske->ke2_payload->pk_len +
-                                ske->ke1_payload->pk_len +
-                                e_len + f_len + KEY_len);
-    if (!buf)
-      return SILC_SKE_STATUS_OUT_OF_MEMORY;
-
-    /* Initiator is not required to send its public key */
-    if (!ske->ke1_payload->pk_data) {
-      ret =
-       silc_buffer_format(buf,
-                          SILC_STR_DATA(s_data, s_len),
-                          SILC_STR_DATA(ske->ke2_payload->pk_data,
-                                        ske->ke2_payload->pk_len),
-                          SILC_STR_DATA(e, e_len),
-                          SILC_STR_DATA(f, f_len),
-                          SILC_STR_DATA(KEY, KEY_len),
-                          SILC_STR_END);
-    } else {
-      ret =
-       silc_buffer_format(buf,
-                          SILC_STR_DATA(s_data, s_len),
-                          SILC_STR_DATA(ske->ke2_payload->pk_data,
-                                        ske->ke2_payload->pk_len),
-                          SILC_STR_DATA(ske->ke1_payload->pk_data,
-                                        ske->ke1_payload->pk_len),
-                          SILC_STR_DATA(e, e_len),
-                          SILC_STR_DATA(f, f_len),
-                          SILC_STR_DATA(KEY, KEY_len),
-                          SILC_STR_END);
-    }
-    if (ret == -1) {
-      silc_buffer_free(buf);
-      memset(e, 0, e_len);
-      memset(f, 0, f_len);
-      memset(KEY, 0, KEY_len);
-      silc_free(e);
-      silc_free(f);
-      silc_free(KEY);
-      return SILC_SKE_STATUS_ERROR;
-    }
-
-    memset(e, 0, e_len);
-    memset(f, 0, f_len);
-    memset(KEY, 0, KEY_len);
-    silc_free(e);
-    silc_free(f);
-    silc_free(KEY);
-  } else {
-    s_data = (ske->start_payload_copy ?
-            silc_buffer_data(ske->start_payload_copy) : NULL);
-    s_len = (ske->start_payload_copy ?
-            silc_buffer_len(ske->start_payload_copy) : 0);
-    e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
-
-    buf = silc_buffer_alloc_size(s_len + ske->ke1_payload->pk_len + e_len);
-    if (!buf)
-      return SILC_SKE_STATUS_OUT_OF_MEMORY;
-
-    /* Format the buffer used to compute the hash value */
-    ret =
-      silc_buffer_format(buf,
-                        SILC_STR_DATA(s_data, s_len),
-                        SILC_STR_DATA(ske->ke1_payload->pk_data,
-                                      ske->ke1_payload->pk_len),
-                        SILC_STR_DATA(e, e_len),
-                        SILC_STR_END);
-    if (ret == -1) {
-      silc_buffer_free(buf);
-      memset(e, 0, e_len);
-      silc_free(e);
-      return SILC_SKE_STATUS_ERROR;
-    }
-
-    SILC_LOG_HEXDUMP(("hash buf"), buf->data, silc_buffer_len(buf));
-
-    memset(e, 0, e_len);
-    silc_free(e);
-  }
-
-  /* Make the hash */
-  silc_hash_make(ske->prop->hash, buf->data, silc_buffer_len(buf),
-                return_hash);
-  *return_hash_len = silc_hash_len(ske->prop->hash);
-
-  if (initiator == FALSE) {
-    SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
-  } else {
-    SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
-  }
-
-  silc_buffer_free(buf);
-
-  return status;
-}
-
-/* Generate rekey material */
-
-static SilcSKERekeyMaterial
-silc_ske_make_rekey_material(SilcSKE ske, SilcSKEKeyMaterial keymat)
-{
-  SilcSKERekeyMaterial rekey;
-  const char *hash;
-
-  /* Create rekey material */
-  rekey = silc_calloc(1, sizeof(*rekey));
-  if (!rekey)
-    return NULL;
-
-  if (ske->prop) {
-    if (ske->prop->group)
-      rekey->ske_group = silc_ske_group_get_number(ske->prop->group);
-    rekey->pfs = (ske->prop->flags & SILC_SKE_SP_FLAG_PFS ? TRUE : FALSE);
-    hash = silc_hash_get_name(ske->prop->hash);
-    rekey->hash = silc_memdup(hash, strlen(hash));
-    if (!rekey->hash)
-      return NULL;
-  }
-
-  if (rekey->pfs == FALSE) {
-    rekey->send_enc_key = silc_memdup(keymat->send_enc_key,
-                                     keymat->enc_key_len / 8);
-    if (!rekey->send_enc_key) {
-      silc_free(rekey);
-      return NULL;
-    }
-    rekey->enc_key_len = keymat->enc_key_len;
-  }
-
-  return rekey;
-}
-
-/* Assembles security properties */
-
-static SilcSKEStartPayload
-silc_ske_assemble_security_properties(SilcSKE ske,
-                                     SilcSKESecurityPropertyFlag flags,
-                                     const char *version)
-{
-  SilcSKEStartPayload rp;
-  int i;
-
-  SILC_LOG_DEBUG(("Assembling KE Start Payload"));
-
-  rp = silc_calloc(1, sizeof(*rp));
-
-  /* Set flags */
-  rp->flags = (unsigned char)flags;
-
-  /* Set random cookie */
-  rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
-  for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
-    rp->cookie[i] = silc_rng_get_byte_fast(ske->rng);
-  rp->cookie_len = SILC_SKE_COOKIE_LEN;
-
-  /* In case IV included flag and session port is set the first 16-bits of
-     cookie will include our session port. */
-  if (flags & SILC_SKE_SP_FLAG_IV_INCLUDED && ske->session_port)
-    SILC_PUT16_MSB(ske->session_port, rp->cookie);
-
-  /* Put version */
-  rp->version = strdup(version);
-  rp->version_len = strlen(version);
-
-  /* Get supported Key Exhange groups */
-  rp->ke_grp_list = silc_ske_get_supported_groups();
-  rp->ke_grp_len = strlen(rp->ke_grp_list);
-
-  /* Get supported PKCS algorithms */
-  rp->pkcs_alg_list = silc_pkcs_get_supported();
-  rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
-
-  /* Get supported encryption algorithms */
-  rp->enc_alg_list = silc_cipher_get_supported(TRUE);
-  rp->enc_alg_len = strlen(rp->enc_alg_list);
-
-  /* Get supported hash algorithms */
-  rp->hash_alg_list = silc_hash_get_supported();
-  rp->hash_alg_len = strlen(rp->hash_alg_list);
-
-  /* Get supported HMACs */
-  rp->hmac_alg_list = silc_hmac_get_supported();
-  rp->hmac_alg_len = strlen(rp->hmac_alg_list);
-
-  /* XXX */
-  /* Get supported compression algorithms */
-  rp->comp_alg_list = strdup("none");
-  rp->comp_alg_len = strlen("none");
-
-  rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
-    2 + rp->version_len +
-    2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
-    2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
-    2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
-
-  return rp;
-}
-
-/* Packet retransmission callback. */
-
-SILC_TASK_CALLBACK(silc_ske_packet_send_retry)
-{
-  SilcSKE ske = context;
-
-  if (ske->retry_count++ >= SILC_SKE_RETRY_COUNT ||
-      ske->aborted) {
-    SILC_LOG_DEBUG(("Retransmission limit reached, packet was lost"));
-    ske->retry_count = 0;
-    ske->retry_timer = SILC_SKE_RETRY_MIN;
-    silc_free(ske->retrans.data);
-    ske->retrans.data = NULL;
-    ske->status = SILC_SKE_STATUS_TIMEOUT;
-    if (ske->responder)
-      silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
-    else
-      silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
-    silc_fsm_continue_sync(&ske->fsm);
-    return;
-  }
-
-  SILC_LOG_DEBUG(("Retransmitting packet"));
-  silc_ske_packet_send(ske, ske->retrans.type, ske->retrans.flags,
-                      ske->retrans.data, ske->retrans.data_len);
-}
-
-/* Install retransmission timer */
-
-static void silc_ske_install_retransmission(SilcSKE ske)
-{
-  if (!silc_packet_stream_is_udp(ske->stream))
-    return;
-
-  if (ske->retrans.data) {
-    SILC_LOG_DEBUG(("Installing retransmission timer %d secs",
-                   ske->retry_timer));
-    silc_schedule_task_add_timeout(ske->schedule, silc_ske_packet_send_retry,
-                                  ske, ske->retry_timer, 0);
-  }
-  ske->retry_timer = ((ske->retry_timer * SILC_SKE_RETRY_MUL) +
-                     (silc_rng_get_rn16(ske->rng) % SILC_SKE_RETRY_RAND));
-}
-
-/* Sends SILC packet.  Handles retransmissions with UDP streams. */
-
-static SilcBool silc_ske_packet_send(SilcSKE ske,
-                                    SilcPacketType type,
-                                    SilcPacketFlags flags,
-                                    const unsigned char *data,
-                                    SilcUInt32 data_len)
-{
-  SilcBool ret;
-
-  /* Send the packet */
-  ret = silc_packet_send(ske->stream, type, flags, data, data_len);
-
-  if (silc_packet_stream_is_udp(ske->stream) &&
-      type != SILC_PACKET_FAILURE && type != SILC_PACKET_REKEY) {
-    silc_free(ske->retrans.data);
-    ske->retrans.type = type;
-    ske->retrans.flags = flags;
-    ske->retrans.data = silc_memdup(data, data_len);
-    ske->retrans.data_len = data_len;
-    silc_ske_install_retransmission(ske);
-  }
-
-  return ret;
-}
-
-/* Calls completion callback.  Completion is called always in this function
-   and must not be called anywhere else. */
-
-static void silc_ske_completion(SilcSKE ske)
-{
-  /* Call the completion callback */
-  if (!ske->freed && !ske->aborted && ske->callbacks->completed) {
-    if (ske->status != SILC_SKE_STATUS_OK)
-      ske->callbacks->completed(ske, ske->status, NULL, NULL, NULL,
-                               ske->callbacks->context);
-    else
-      ske->callbacks->completed(ske, ske->status, ske->prop, ske->keymat,
-                               ske->rekey, ske->callbacks->context);
-  }
-}
-
-/* SKE FSM destructor. */
-
-static void silc_ske_finished(SilcFSM fsm, void *fsm_context,
-                             void *destructor_context)
-{
-  SilcSKE ske = fsm_context;
-  ske->running = FALSE;
-  if (ske->freed)
-    silc_ske_free(ske);
-}
-
-/* Key exchange timeout task callback */
-
-SILC_TASK_CALLBACK(silc_ske_timeout)
-{
-  SilcSKE ske = context;
-
-  SILC_LOG_DEBUG(("Timeout"));
-
-  ske->packet = NULL;
-  ske->status = SILC_SKE_STATUS_TIMEOUT;
-  if (ske->responder)
-    silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
-  else
-    silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
-
-  silc_fsm_continue_sync(&ske->fsm);
-}
-
-/* Initiator signature callback */
-
-static void silc_ske_initiator_sign_cb(SilcBool success,
-                                      const unsigned char *signature,
-                                      SilcUInt32 signature_len,
-                                      void *context)
-{
-  SilcSKE ske = context;
-
-  ske->key_op = NULL;
-
-  if (ske->aborted) {
-    silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
-    SILC_FSM_CALL_CONTINUE(&ske->fsm);
-    return;
-  }
-
-  ske->ke1_payload->sign_data = silc_memdup(signature, signature_len);
-  if (ske->ke1_payload->sign_data)
-    ske->ke1_payload->sign_len = signature_len;
-
-  SILC_FSM_CALL_CONTINUE(&ske->fsm);
-}
-
-/* Responder signature callback */
-
-static void silc_ske_responder_sign_cb(SilcBool success,
-                                      const unsigned char *signature,
-                                      SilcUInt32 signature_len,
-                                      void *context)
-{
-  SilcSKE ske = context;
-
-  ske->key_op = NULL;
-
-  if (ske->aborted) {
-    silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
-    SILC_FSM_CALL_CONTINUE(&ske->fsm);
-    return;
-  }
-
-  ske->ke2_payload->sign_data = silc_memdup(signature, signature_len);
-  if (ske->ke2_payload->sign_data)
-    ske->ke2_payload->sign_len = signature_len;
-
-  SILC_FSM_CALL_CONTINUE(&ske->fsm);
-}
-
-/* Verify callback */
-
-static void silc_ske_verify_cb(SilcBool success, void *context)
-{
-  SilcSKE ske = context;
-
-  ske->key_op = NULL;
-
-  if (ske->aborted) {
-    if (ske->responder)
-      silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
-    else
-      silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
-    SILC_FSM_CALL_CONTINUE(&ske->fsm);
-    return;
-  }
-
-  if (!success) {
-    SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
-    ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
-    if (ske->responder)
-      silc_fsm_next(&ske->fsm, silc_ske_st_responder_error);
-    else
-      silc_fsm_next(&ske->fsm, silc_ske_st_initiator_error);
-    SILC_FSM_CALL_CONTINUE(&ske->fsm);
-    return;
-  }
-
-  SILC_LOG_DEBUG(("Signature is Ok"));
-  SILC_FSM_CALL_CONTINUE(&ske->fsm);
-}
-
-/******************************* Protocol API *******************************/
-
-/* Allocates new SKE object. */
-
-SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule,
-                      SilcSKR repository, SilcPublicKey public_key,
-                      SilcPrivateKey private_key, void *context)
-{
-  SilcSKE ske;
-
-  SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
-
-  if (!rng || !schedule)
-    return NULL;
-
-  if (!public_key) {
-    SILC_LOG_ERROR(("Public key must be given to silc_ske_alloc"));
-    return NULL;
-  }
-
-  ske = silc_calloc(1, sizeof(*ske));
-  if (!ske)
-    return NULL;
-  ske->status = SILC_SKE_STATUS_OK;
-  ske->rng = rng;
-  ske->repository = repository;
-  ske->user_data = context;
-  ske->schedule = schedule;
-  ske->public_key = public_key;
-  ske->private_key = private_key;
-  ske->retry_timer = SILC_SKE_RETRY_MIN;
-  ske->refcnt = 1;
-
-  return ske;
-}
-
-/* Free's SKE object. */
-
-void silc_ske_free(SilcSKE ske)
-{
-  SILC_LOG_DEBUG(("Freeing Key Exchange object"));
-
-  if (!ske)
-    return;
-
-  if (ske->running) {
-    ske->freed = TRUE;
-
-    if (ske->aborted) {
-      /* If already aborted, destroy the session immediately */
-      ske->packet = NULL;
-      ske->status = SILC_SKE_STATUS_ERROR;
-      if (ske->responder)
-       silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
-      else
-       silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
-      silc_fsm_continue_sync(&ske->fsm);
-    }
-    return;
-  }
-
-  ske->refcnt--;
-  if (ske->refcnt > 0)
-    return;
-
-  /* Free start payload */
-  if (ske->start_payload)
-    silc_ske_payload_start_free(ske->start_payload);
-
-  /* Free KE payload */
-  if (ske->ke1_payload)
-    silc_ske_payload_ke_free(ske->ke1_payload);
-  if (ske->ke2_payload)
-    silc_ske_payload_ke_free(ske->ke2_payload);
-  silc_free(ske->remote_version);
-
-  /* Free rest */
-  if (ske->prop) {
-    if (ske->prop->group)
-      silc_ske_group_free(ske->prop->group);
-    if (ske->prop->cipher)
-      silc_cipher_free(ske->prop->cipher);
-    if (ske->prop->hash)
-      silc_hash_free(ske->prop->hash);
-    if (ske->prop->hmac)
-      silc_hmac_free(ske->prop->hmac);
-    if (ske->prop->public_key)
-      silc_pkcs_public_key_free(ske->prop->public_key);
-    silc_free(ske->prop);
-  }
-  if (ske->keymat)
-    silc_ske_free_key_material(ske->keymat);
-  if (ske->start_payload_copy)
-    silc_buffer_free(ske->start_payload_copy);
-  if (ske->x) {
-    silc_mp_uninit(ske->x);
-    silc_free(ske->x);
-  }
-  if (ske->KEY) {
-    silc_mp_uninit(ske->KEY);
-    silc_free(ske->KEY);
-  }
-  silc_free(ske->retrans.data);
-  silc_free(ske->hash);
-  silc_free(ske->callbacks);
-
-  memset(ske, 'F', sizeof(*ske));
-  silc_free(ske);
-}
-
-/* Return user context */
-
-void *silc_ske_get_context(SilcSKE ske)
-{
-  return ske->user_data;
-}
-
-/* Sets protocol callbacks */
-
-void silc_ske_set_callbacks(SilcSKE ske,
-                           SilcSKEVerifyCb verify_key,
-                           SilcSKECompletionCb completed,
-                           void *context)
-{
-  if (ske->callbacks)
-    silc_free(ske->callbacks);
-  ske->callbacks = silc_calloc(1, sizeof(*ske->callbacks));
-  if (!ske->callbacks)
-    return;
-  ske->callbacks->verify_key = verify_key;
-  ske->callbacks->completed = completed;
-  ske->callbacks->context = context;
-}
-
-
-/******************************** Initiator *********************************/
-
-/* Start protocol.  Send our proposal */
-
-SILC_FSM_STATE(silc_ske_st_initiator_start)
-{
-  SilcSKE ske = fsm_context;
-  SilcBuffer payload_buf;
-  SilcStatus status;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (ske->aborted) {
-    /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Encode the payload */
-  status = silc_ske_payload_start_encode(ske, ske->start_payload,
-                                        &payload_buf);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error encoding Start Payload */
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Save the the payload buffer for future use. It is later used to
-     compute the HASH value. */
-  ske->start_payload_copy = payload_buf;
-
-  /* Send the packet. */
-  if (!silc_ske_packet_send(ske, SILC_PACKET_KEY_EXCHANGE, 0,
-                           silc_buffer_data(payload_buf),
-                           silc_buffer_len(payload_buf))) {
-    /** Error sending packet */
-    SILC_LOG_DEBUG(("Error sending packet"));
-    ske->status = SILC_SKE_STATUS_ERROR;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Add key exchange timeout */
-  silc_schedule_task_add_timeout(ske->schedule, silc_ske_timeout,
-                                ske, ske->timeout, 0);
-
-  /** Wait for responder proposal */
-  SILC_LOG_DEBUG(("Waiting for responder proposal"));
-  silc_fsm_next(fsm, silc_ske_st_initiator_phase1);
-  return SILC_FSM_WAIT;
-}
-
-/* Phase-1.  Receives responder's proposal */
-
-SILC_FSM_STATE(silc_ske_st_initiator_phase1)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcSKEStartPayload payload;
-  SilcSKESecurityProperties prop;
-  SilcSKEDiffieHellmanGroup group = NULL;
-  SilcBuffer packet_buf = &ske->packet->buffer;
-  SilcUInt16 remote_port = 0;
-  SilcID id;
-  int coff = 0;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (ske->packet->type != SILC_PACKET_KEY_EXCHANGE) {
-    SILC_LOG_DEBUG(("Remote retransmitted an old packet"));
-    silc_ske_install_retransmission(ske);
-    silc_packet_free(ske->packet);
-    ske->packet = NULL;
-    return SILC_FSM_WAIT;
-  }
-
-  /* Decode the payload */
-  status = silc_ske_payload_start_decode(ske, packet_buf, &payload);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error decoding Start Payload */
-    silc_packet_free(ske->packet);
-    ske->packet = NULL;
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Get remote ID and set it to stream */
-  if (ske->packet->src_id_len) {
-    silc_id_str2id(ske->packet->src_id, ske->packet->src_id_len,
-                  ske->packet->src_id_type,
-                  (ske->packet->src_id_type == SILC_ID_SERVER ?
-                   (void *)&id.u.server_id : (void *)&id.u.client_id),
-                  (ske->packet->src_id_type == SILC_ID_SERVER ?
-                   sizeof(id.u.server_id) : sizeof(id.u.client_id)));
-    silc_packet_set_ids(ske->stream, 0, NULL, ske->packet->src_id_type,
-                       (ske->packet->src_id_type == SILC_ID_SERVER ?
-                        (void *)&id.u.server_id : (void *)&id.u.client_id));
-  }
-
-  silc_packet_free(ske->packet);
-  ske->packet = NULL;
-
-  /* Check that the cookie is returned unmodified.  In case IV included
-     flag and session port has been set, the first two bytes of cookie
-     are the session port and we ignore them in this check. */
-  if (payload->flags & SILC_SKE_SP_FLAG_IV_INCLUDED && ske->session_port) {
-    /* Take remote port */
-    SILC_GET16_MSB(remote_port, ske->start_payload->cookie);
-    coff = 2;
-  }
-  if (memcmp(ske->start_payload->cookie + coff, payload->cookie + coff,
-            SILC_SKE_COOKIE_LEN - coff)) {
-    /** Invalid cookie */
-    SILC_LOG_ERROR(("Invalid cookie, modified or unsupported feature"));
-    ske->status = SILC_SKE_STATUS_INVALID_COOKIE;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Check version string */
-  ske->remote_version = silc_memdup(payload->version, payload->version_len);
-  status = silc_ske_check_version(ske);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Version mismatch */
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Free our KE Start Payload context, we don't need it anymore. */
-  silc_ske_payload_start_free(ske->start_payload);
-  ske->start_payload = NULL;
-
-  /* Take the selected security properties into use while doing
-     the key exchange.  This is used only while doing the key
-     exchange. */
-  ske->prop = prop = silc_calloc(1, sizeof(*prop));
-  if (!ske->prop)
-    goto err;
-  prop->flags = payload->flags;
-  status = silc_ske_group_get_by_name(payload->ke_grp_list, &group);
-  if (status != SILC_SKE_STATUS_OK)
-    goto err;
-
-  prop->group = group;
-  prop->remote_port = remote_port;
-
-  if (silc_pkcs_find_algorithm(payload->pkcs_alg_list, NULL) == NULL) {
-    status = SILC_SKE_STATUS_UNKNOWN_PKCS;
-    goto err;
-  }
-  if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
-    status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
-    goto err;
-  }
-  if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
-    status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
-    goto err;
-  }
-  if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
-    status = SILC_SKE_STATUS_UNKNOWN_HMAC;
-    goto err;
-  }
-
-  /* Save remote's KE Start Payload */
-  ske->start_payload = payload;
-
-  /** Send KE Payload */
-  silc_fsm_next(fsm, silc_ske_st_initiator_phase2);
-  return SILC_FSM_CONTINUE;
-
- err:
-  if (payload)
-    silc_ske_payload_start_free(payload);
-  if (group)
-    silc_ske_group_free(group);
-  if (prop->cipher)
-    silc_cipher_free(prop->cipher);
-  if (prop->hash)
-    silc_hash_free(prop->hash);
-  if (prop->hmac)
-    silc_hmac_free(prop->hmac);
-  silc_free(prop);
-  ske->prop = NULL;
-
-  if (status == SILC_SKE_STATUS_OK)
-    status = SILC_SKE_STATUS_ERROR;
-
-  /** Error */
-  ske->status = status;
-  silc_fsm_next(fsm, silc_ske_st_initiator_error);
-  return SILC_FSM_CONTINUE;
-}
-
-/* Phase-2.  Send KE payload */
-
-SILC_FSM_STATE(silc_ske_st_initiator_phase2)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcMPInt *x;
-  SilcSKEKEPayload payload;
-  SilcUInt32 pk_len;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  /* Create the random number x, 1 < x < q. */
-  x = silc_calloc(1, sizeof(*x));
-  if (!x){
-    /** Out of memory */
-    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-  silc_mp_init(x);
-  status =
-    silc_ske_create_rnd(ske, &ske->prop->group->group_order,
-                       silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
-                       x);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error generating random number */
-    silc_mp_uninit(x);
-    silc_free(x);
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Encode the result to Key Exchange Payload. */
-
-  payload = silc_calloc(1, sizeof(*payload));
-  if (!payload) {
-    /** Out of memory */
-    silc_mp_uninit(x);
-    silc_free(x);
-    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-  ske->ke1_payload = payload;
-
-  SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
-
-  /* Do the Diffie Hellman computation, e = g ^ x mod p */
-  silc_mp_init(&payload->x);
-  silc_mp_pow_mod(&payload->x, &ske->prop->group->generator, x,
-                 &ske->prop->group->group);
-  ske->x = x;
-
-  /* Get public key */
-  payload->pk_data = silc_pkcs_public_key_encode(NULL, ske->public_key,
-                                                &pk_len);
-  if (!payload->pk_data) {
-    /** Error encoding public key */
-    silc_mp_uninit(x);
-    silc_free(x);
-    ske->x = NULL;
-    silc_mp_uninit(&payload->x);
-    silc_free(payload);
-    ske->ke1_payload = NULL;
-    ske->status = SILC_SKE_STATUS_ERROR;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-  payload->pk_len = pk_len;
-  payload->pk_type = silc_pkcs_get_type(ske->public_key);
-
-  /** Send KE1 packet */
-  silc_fsm_next(fsm, silc_ske_st_initiator_phase2_send);
-
-  /* Compute signature data if we are doing mutual authentication */
-  if (ske->private_key && ske->prop->flags & SILC_SKE_SP_FLAG_MUTUAL) {
-    unsigned char hash[SILC_HASH_MAXLEN];
-    SilcUInt32 hash_len;
-
-    SILC_LOG_DEBUG(("We are doing mutual authentication"));
-    SILC_LOG_DEBUG(("Computing HASH_i value"));
-
-    /* Compute the hash value */
-    memset(hash, 0, sizeof(hash));
-    silc_ske_make_hash(ske, hash, &hash_len, TRUE);
-
-    SILC_LOG_DEBUG(("Signing HASH_i value"));
-
-    /* Sign the hash value */
-    SILC_FSM_CALL(ske->key_op =
-                 silc_pkcs_sign(ske->private_key, hash, hash_len, FALSE,
-                                ske->prop->hash, ske->rng,
-                                silc_ske_initiator_sign_cb, ske));
-    /* NOT REACHED */
-  }
-
-  return SILC_FSM_CONTINUE;
-}
-
-/* Send KE1 packet */
-
-SILC_FSM_STATE(silc_ske_st_initiator_phase2_send)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcBuffer payload_buf;
-  SilcSKEKEPayload payload;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  payload = ske->ke1_payload;
-
-  status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error encoding KE payload */
-    silc_mp_uninit(&payload->x);
-    silc_free(payload->pk_data);
-    silc_free(payload->sign_data);
-    silc_free(payload);
-    ske->ke1_payload = NULL;
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Send the packet. */
-  if (!silc_ske_packet_send(ske, SILC_PACKET_KEY_EXCHANGE_1, 0,
-                           silc_buffer_data(payload_buf),
-                           silc_buffer_len(payload_buf))) {
-    /** Error sending packet */
-    SILC_LOG_DEBUG(("Error sending packet"));
-    ske->status = SILC_SKE_STATUS_ERROR;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  silc_buffer_free(payload_buf);
-
-  /** Waiting responder's KE payload */
-  silc_fsm_next(fsm, silc_ske_st_initiator_phase3);
-  return SILC_FSM_WAIT;
-}
-
-/* Phase-3.  Process responder's KE payload */
-
-SILC_FSM_STATE(silc_ske_st_initiator_phase3)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcSKEKEPayload payload;
-  SilcMPInt *KEY;
-  SilcBuffer packet_buf = &ske->packet->buffer;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (ske->packet->type != SILC_PACKET_KEY_EXCHANGE_2) {
-    SILC_LOG_DEBUG(("Remote retransmitted an old packet"));
-    silc_ske_install_retransmission(ske);
-    silc_packet_free(ske->packet);
-    ske->packet = NULL;
-    return SILC_FSM_WAIT;
-  }
-
-  /* Decode the payload */
-  status = silc_ske_payload_ke_decode(ske, packet_buf, &payload);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error decoding KE payload */
-    silc_packet_free(ske->packet);
-    ske->packet = NULL;
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-  silc_packet_free(ske->packet);
-  ske->packet = NULL;
-  ske->ke2_payload = payload;
-
-  if (!payload->pk_data && (ske->callbacks->verify_key || ske->repository)) {
-    SILC_LOG_DEBUG(("Remote end did not send its public key (or certificate), "
-                   "even though we require it"));
-    ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
-    goto err;
-  }
-
-  SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
-
-  /* Compute the shared secret key */
-  KEY = silc_calloc(1, sizeof(*KEY));
-  silc_mp_init(KEY);
-  silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group);
-  ske->KEY = KEY;
-
-  /* Decode the remote's public key */
-  if (payload->pk_data &&
-      !silc_pkcs_public_key_alloc(payload->pk_type,
-                                 payload->pk_data, payload->pk_len,
-                                 &ske->prop->public_key)) {
-    SILC_LOG_ERROR(("Unsupported/malformed public key received"));
-    status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
-    goto err;
-  }
-
-  if (ske->prop->public_key && (ske->callbacks->verify_key ||
-                               ske->repository)) {
-    SILC_LOG_DEBUG(("Verifying public key"));
-
-    /** Waiting public key verification */
-    silc_fsm_next(fsm, silc_ske_st_initiator_phase4);
-
-    /* If repository is provided, verify the key from there. */
-    if (ske->repository) {
-      SilcSKRFind find;
-
-      find = silc_skr_find_alloc();
-      if (!find) {
-       status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-       goto err;
-      }
-      silc_skr_find_set_pkcs_type(find,
-                                 silc_pkcs_get_type(ske->prop->public_key));
-      silc_skr_find_set_public_key(find, ske->prop->public_key);
-      silc_skr_find_set_usage(find, SILC_SKR_USAGE_KEY_AGREEMENT);
-
-      /* Find key from repository */
-      SILC_FSM_CALL(silc_skr_find(ske->repository, silc_fsm_get_schedule(fsm),
-                                 find, silc_ske_skr_callback, ske));
-    } else {
-      /* Verify from application */
-      SILC_FSM_CALL(ske->callbacks->verify_key(ske, ske->prop->public_key,
-                                              ske->callbacks->context,
-                                              silc_ske_pk_verified, NULL));
-    }
-    /* NOT REACHED */
-  }
-
-  /** Process key material */
-  silc_fsm_next(fsm, silc_ske_st_initiator_phase4);
-  return SILC_FSM_CONTINUE;
-
- err:
-  silc_ske_payload_ke_free(payload);
-  ske->ke2_payload = NULL;
-
-  silc_mp_uninit(ske->KEY);
-  silc_free(ske->KEY);
-  ske->KEY = NULL;
-
-  if (status == SILC_SKE_STATUS_OK)
-    return SILC_SKE_STATUS_ERROR;
-
-  /** Error */
-  ske->status = status;
-  silc_fsm_next(fsm, silc_ske_st_initiator_error);
-  return SILC_FSM_CONTINUE;
-}
-
-/* Process key material */
-
-SILC_FSM_STATE(silc_ske_st_initiator_phase4)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcSKEKEPayload payload;
-  unsigned char hash[SILC_HASH_MAXLEN];
-  SilcUInt32 hash_len;
-
-  if (ske->aborted) {
-    /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Check result of public key verification */
-  if (ske->status != SILC_SKE_STATUS_OK) {
-    /** Public key not verified */
-    SILC_LOG_DEBUG(("Public key verification failed"));
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  payload = ske->ke2_payload;
-
-  /* Compute the HASH value */
-  SILC_LOG_DEBUG(("Computing HASH value"));
-  status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
-  if (status != SILC_SKE_STATUS_OK)
-    goto err;
-  ske->hash = silc_memdup(hash, hash_len);
-  ske->hash_len = hash_len;
-
-  /** Send reply */
-  silc_fsm_next(fsm, silc_ske_st_initiator_phase5);
-
-  if (ske->prop->public_key) {
-    SILC_LOG_DEBUG(("Public key is authentic"));
-    SILC_LOG_DEBUG(("Verifying signature (HASH)"));
-
-    /* Verify signature */
-    SILC_FSM_CALL(ske->key_op =
-                 silc_pkcs_verify(ske->prop->public_key, payload->sign_data,
-                                  payload->sign_len, hash, hash_len, NULL,
-                                  silc_ske_verify_cb, ske));
-    /* NOT REACHED */
-  }
-
-  return SILC_FSM_CONTINUE;
-
- err:
-  memset(hash, 'F', sizeof(hash));
-  silc_ske_payload_ke_free(payload);
-  ske->ke2_payload = NULL;
-
-  silc_mp_uninit(ske->KEY);
-  silc_free(ske->KEY);
-  ske->KEY = NULL;
-
-  if (ske->hash) {
-    memset(ske->hash, 'F', hash_len);
-    silc_free(ske->hash);
-    ske->hash = NULL;
-  }
-
-  if (status == SILC_SKE_STATUS_OK)
-    status = SILC_SKE_STATUS_ERROR;
-
-  /** Error */
-  ske->status = status;
-  silc_fsm_next(fsm, silc_ske_st_initiator_error);
-  return SILC_FSM_CONTINUE;
-}
-
-/* Process key material */
-
-SILC_FSM_STATE(silc_ske_st_initiator_phase5)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  unsigned char tmp[4];
-  SilcUInt32 hash_len;
-  int key_len, block_len;
-
-  ske->status = SILC_SKE_STATUS_OK;
-
-  /* In case we are doing rekey move to finish it.  */
-  if (ske->rekey) {
-    /** Finish rekey */
-    silc_fsm_next(fsm, silc_ske_st_rekey_initiator_done);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Process key material */
-  key_len = silc_cipher_get_key_len(ske->prop->cipher);
-  block_len = silc_cipher_get_block_len(ske->prop->cipher);
-  hash_len = silc_hash_len(ske->prop->hash);
-  ske->keymat = silc_ske_process_key_material(ske, block_len,
-                                             key_len, hash_len,
-                                             &ske->rekey);
-  if (!ske->keymat) {
-    SILC_LOG_ERROR(("Error processing key material"));
-    status = SILC_SKE_STATUS_ERROR;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Send SUCCESS packet */
-  SILC_PUT32_MSB((SilcUInt32)SILC_SKE_STATUS_OK, tmp);
-  if (!silc_ske_packet_send(ske, SILC_PACKET_SUCCESS, 0, tmp, 4)) {
-    /** Error sending packet */
-    SILC_LOG_DEBUG(("Error sending packet"));
-    ske->status = SILC_SKE_STATUS_ERROR;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /** Waiting completion */
-  silc_fsm_next(fsm, silc_ske_st_initiator_end);
-  return SILC_FSM_WAIT;
-}
-
-/* Protocol completed */
-
-SILC_FSM_STATE(silc_ske_st_initiator_end)
-{
-  SilcSKE ske = fsm_context;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (ske->packet->type != SILC_PACKET_SUCCESS) {
-    SILC_LOG_DEBUG(("Remote retransmitted an old packet"));
-    silc_ske_install_retransmission(ske);
-    silc_packet_free(ske->packet);
-    ske->packet = NULL;
-    return SILC_FSM_WAIT;
-  }
-
-  SILC_LOG_DEBUG(("Key exchange completed successfully"));
-
-  silc_packet_free(ske->packet);
-  ske->packet = NULL;
-  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
-  silc_schedule_task_del_by_context(ske->schedule, ske);
-
-  /* Call completion */
-  silc_ske_completion(ske);
-
-  return SILC_FSM_FINISH;
-}
-
-/* Aborted by application */
-
-SILC_FSM_STATE(silc_ske_st_initiator_aborted)
-{
-  SilcSKE ske = fsm_context;
-  unsigned char data[4];
-
-  SILC_LOG_DEBUG(("Aborted by caller"));
-
-  /* Send FAILURE packet */
-  SILC_PUT32_MSB(SILC_SKE_STATUS_ERROR, data);
-  silc_ske_packet_send(ske, SILC_PACKET_FAILURE, 0, data, 4);
-
-  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
-  silc_schedule_task_del_by_context(ske->schedule, ske);
-
-  /* Call completion */
-  silc_ske_completion(ske);
-
-  return SILC_FSM_FINISH;
-}
-
-/* Error occurred.  Send error to remote host */
-
-SILC_FSM_STATE(silc_ske_st_initiator_error)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  unsigned char data[4];
-
-  SILC_LOG_DEBUG(("Error %s (%d) occurred during key exchange",
-                 silc_ske_map_status(ske->status), ske->status));
-
-  status = ske->status;
-  if (status > SILC_SKE_STATUS_INVALID_COOKIE)
-    status = SILC_SKE_STATUS_ERROR;
-
-  /* Send FAILURE packet */
-  SILC_PUT32_MSB((SilcUInt32)status, data);
-  silc_ske_packet_send(ske, SILC_PACKET_FAILURE, 0, data, 4);
-
-  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
-  silc_schedule_task_del_by_context(ske->schedule, ske);
-
-  /* Call completion */
-  silc_ske_completion(ske);
-
-  return SILC_FSM_FINISH;
-}
-
-/* Failure received from remote */
-
-SILC_FSM_STATE(silc_ske_st_initiator_failure)
-{
-  SilcSKE ske = fsm_context;
-  SilcUInt32 error = SILC_SKE_STATUS_ERROR;
-
-  if (ske->packet && ske->packet->type == SILC_PACKET_FAILURE &&
-      silc_buffer_len(&ske->packet->buffer) == 4) {
-    SILC_GET32_MSB(error, ske->packet->buffer.data);
-    ske->status = error;
-    silc_packet_free(ske->packet);
-    ske->packet = NULL;
-  }
-
-  SILC_LOG_DEBUG(("Error %s (%d) received during key exchange",
-                 silc_ske_map_status(ske->status), ske->status));
-
-  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
-  silc_schedule_task_del_by_context(ske->schedule, ske);
-
-  /* Call completion */
-  silc_ske_completion(ske);
-
-  return SILC_FSM_FINISH;
-}
-
-/* Starts the protocol as initiator */
-
-SilcAsyncOperation silc_ske_initiator(SilcSKE ske,
-                                     SilcPacketStream stream,
-                                     SilcSKEParams params,
-                                     SilcSKEStartPayload start_payload)
-{
-  SILC_LOG_DEBUG(("Start SKE as initiator"));
-
-  if (!ske || !stream || !params || !params->version)
-    return NULL;
-
-  if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
-    return NULL;
-
-  if (!silc_fsm_init(&ske->fsm, ske, silc_ske_finished, ske, ske->schedule))
-    return NULL;
-
-  if (params->flags & SILC_SKE_SP_FLAG_IV_INCLUDED)
-    ske->session_port = params->session_port;
-
-  /* Generate security properties if not provided */
-  if (!start_payload) {
-    start_payload = silc_ske_assemble_security_properties(ske,
-                                                         params->flags,
-                                                         params->version);
-    if (!start_payload)
-      return NULL;
-  }
-
-  ske->timeout = params->timeout_secs ? params->timeout_secs : 30;
-  ske->start_payload = start_payload;
-  ske->version = params->version;
-  ske->running = TRUE;
-
-  /* Link to packet stream to get key exchange packets */
-  ske->stream = stream;
-  silc_packet_stream_link(ske->stream, &silc_ske_stream_cbs, ske, 1000000,
-                         SILC_PACKET_KEY_EXCHANGE,
-                         SILC_PACKET_KEY_EXCHANGE_2,
-                         SILC_PACKET_SUCCESS,
-                         SILC_PACKET_FAILURE, -1);
-
-  /* Start SKE as initiator */
-  silc_fsm_start(&ske->fsm, silc_ske_st_initiator_start);
-
-  return &ske->op;
-}
-
-/******************************** Responder *********************************/
-
-/* Start protocol as responder.  Wait initiator's start payload */
-
-SILC_FSM_STATE(silc_ske_st_responder_start)
-{
-  SilcSKE ske = fsm_context;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (ske->aborted) {
-    /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_responder_aborted);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Add key exchange timeout */
-  silc_schedule_task_add_timeout(ske->schedule, silc_ske_timeout,
-                                ske, ske->timeout, 0);
-
-  /** Wait for initiator */
-  silc_fsm_next(fsm, silc_ske_st_responder_phase1);
-  return SILC_FSM_WAIT;
-}
-
-/* Decode initiator's start payload.  Select the security properties from
-   the initiator's start payload and send our reply start payload back. */
-
-SILC_FSM_STATE(silc_ske_st_responder_phase1)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcSKEStartPayload remote_payload = NULL;
-  SilcBuffer packet_buf = &ske->packet->buffer;
-  SilcID id;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  /* Decode the payload */
-  status = silc_ske_payload_start_decode(ske, packet_buf, &remote_payload);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error decoding Start Payload */
-    silc_packet_free(ske->packet);
-    ske->packet = NULL;
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Get remote ID and set it to stream */
-  if (ske->packet->src_id_len) {
-    silc_id_str2id(ske->packet->src_id, ske->packet->src_id_len,
-                  ske->packet->src_id_type,
-                  (ske->packet->src_id_type == SILC_ID_SERVER ?
-                   (void *)&id.u.server_id : (void *)&id.u.client_id),
-                  (ske->packet->src_id_type == SILC_ID_SERVER ?
-                   sizeof(id.u.server_id) : sizeof(id.u.client_id)));
-    silc_packet_set_ids(ske->stream, 0, NULL, ske->packet->src_id_type,
-                       (ske->packet->src_id_type == SILC_ID_SERVER ?
-                        (void *)&id.u.server_id : (void *)&id.u.client_id));
-  }
-
-  /* Take a copy of the payload buffer for future use. It is used to
-     compute the HASH value. */
-  ske->start_payload_copy = silc_buffer_copy(packet_buf);
-
-  silc_packet_free(ske->packet);
-  ske->packet = NULL;
-
-  /* Force the mutual authentication flag if we want to do it. */
-  if (ske->flags & SILC_SKE_SP_FLAG_MUTUAL) {
-    SILC_LOG_DEBUG(("Force mutual authentication"));
-    remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
-  }
-
-  /* Force PFS flag if we require it */
-  if (ske->flags & SILC_SKE_SP_FLAG_PFS) {
-    SILC_LOG_DEBUG(("Force PFS"));
-    remote_payload->flags |= SILC_SKE_SP_FLAG_PFS;
-  }
-
-  /* Disable IV Included flag if requested */
-  if (remote_payload->flags & SILC_SKE_SP_FLAG_IV_INCLUDED &&
-      !(ske->flags & SILC_SKE_SP_FLAG_IV_INCLUDED)) {
-    SILC_LOG_DEBUG(("We do not support IV Included flag"));
-    remote_payload->flags &= ~SILC_SKE_SP_FLAG_IV_INCLUDED;
-  }
-
-  /* Check and select security properties */
-  status = silc_ske_select_security_properties(ske, remote_payload,
-                                              &ske->prop);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error selecting proposal */
-    silc_ske_payload_start_free(remote_payload);
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  silc_ske_payload_start_free(remote_payload);
-
-  /* Encode our reply payload to send the selected security properties */
-  status = silc_ske_payload_start_encode(ske, ske->start_payload,
-                                        &packet_buf);
-  if (status != SILC_SKE_STATUS_OK)
-    goto err;
-
-  /* Send the packet. */
-  if (!silc_ske_packet_send(ske, SILC_PACKET_KEY_EXCHANGE, 0,
-                           silc_buffer_data(packet_buf),
-                           silc_buffer_len(packet_buf)))
-    goto err;
-
-  silc_buffer_free(packet_buf);
-
-  /** Waiting initiator's KE payload */
-  silc_fsm_next(fsm, silc_ske_st_responder_phase2);
-  return SILC_FSM_WAIT;
-
- err:
-  if (ske->prop->group)
-    silc_ske_group_free(ske->prop->group);
-  if (ske->prop->cipher)
-    silc_cipher_free(ske->prop->cipher);
-  if (ske->prop->hash)
-    silc_hash_free(ske->prop->hash);
-  if (ske->prop->hmac)
-    silc_hmac_free(ske->prop->hmac);
-  silc_free(ske->prop);
-  ske->prop = NULL;
-
-  if (status == SILC_SKE_STATUS_OK)
-    status = SILC_SKE_STATUS_ERROR;
-
-  /** Error */
-  ske->status = status;
-  silc_fsm_next(fsm, silc_ske_st_responder_error);
-  return SILC_FSM_CONTINUE;
-}
-
-/* Phase-2.  Decode initiator's KE payload */
-
-SILC_FSM_STATE(silc_ske_st_responder_phase2)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcSKEKEPayload recv_payload;
-  SilcBuffer packet_buf = &ske->packet->buffer;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (ske->packet->type != SILC_PACKET_KEY_EXCHANGE_1) {
-    SILC_LOG_DEBUG(("Remote retransmitted an old packet"));
-    silc_ske_install_retransmission(ske);
-    silc_packet_free(ske->packet);
-    ske->packet = NULL;
-    return SILC_FSM_WAIT;
-  }
-
-  /* Decode Key Exchange Payload */
-  status = silc_ske_payload_ke_decode(ske, packet_buf, &recv_payload);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error decoding KE payload */
-    silc_packet_free(ske->packet);
-    ske->packet = NULL;
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  ske->ke1_payload = recv_payload;
-
-  silc_packet_free(ske->packet);
-  ske->packet = NULL;
-
-  /* Verify the received public key and verify the signature if we are
-     doing mutual authentication. */
-  if (ske->start_payload &&
-      ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
-
-    SILC_LOG_DEBUG(("We are doing mutual authentication"));
-
-    if (!recv_payload->pk_data && (ske->callbacks->verify_key ||
-                                  ske->repository)) {
-      /** Public key not provided */
-      SILC_LOG_ERROR(("Remote end did not send its public key (or "
-                     "certificate), even though we require it"));
-      ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
-      silc_fsm_next(fsm, silc_ske_st_responder_error);
-      return SILC_FSM_CONTINUE;
-    }
-
-    /* Decode the remote's public key */
-    if (recv_payload->pk_data &&
-       !silc_pkcs_public_key_alloc(recv_payload->pk_type,
-                                   recv_payload->pk_data,
-                                   recv_payload->pk_len,
-                                   &ske->prop->public_key)) {
-      /** Error decoding public key */
-      SILC_LOG_ERROR(("Unsupported/malformed public key received"));
-      ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
-      silc_fsm_next(fsm, silc_ske_st_responder_error);
-      return SILC_FSM_CONTINUE;
-    }
-
-    if (ske->prop->public_key && (ske->callbacks->verify_key ||
-                                 ske->repository)) {
-      SILC_LOG_DEBUG(("Verifying public key"));
-
-      /** Waiting public key verification */
-      silc_fsm_next(fsm, silc_ske_st_responder_phase4);
-
-      /* If repository is provided, verify the key from there. */
-      if (ske->repository) {
-       SilcSKRFind find;
-
-       find = silc_skr_find_alloc();
-       if (!find) {
-         ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-         silc_fsm_next(fsm, silc_ske_st_responder_error);
-         return SILC_FSM_CONTINUE;
-       }
-       silc_skr_find_set_pkcs_type(find,
-                                   silc_pkcs_get_type(ske->prop->public_key));
-       silc_skr_find_set_public_key(find, ske->prop->public_key);
-       silc_skr_find_set_usage(find, SILC_SKR_USAGE_KEY_AGREEMENT);
-
-       /* Find key from repository */
-       SILC_FSM_CALL(silc_skr_find(ske->repository,
-                                   silc_fsm_get_schedule(fsm), find,
-                                   silc_ske_skr_callback, ske));
-      } else {
-       /* Verify from application */
-       SILC_FSM_CALL(ske->callbacks->verify_key(ske, ske->prop->public_key,
-                                                ske->callbacks->context,
-                                                silc_ske_pk_verified, NULL));
-      }
-      /* NOT REACHED */
-    }
-  }
-
-  /** Generate KE2 payload */
-  silc_fsm_next(fsm, silc_ske_st_responder_phase4);
-  return SILC_FSM_CONTINUE;
-}
-
-/* Phase-4. Generate KE2 payload, verify signature */
-
-SILC_FSM_STATE(silc_ske_st_responder_phase4)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcSKEKEPayload recv_payload;
-
-  if (ske->aborted) {
-    /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_responder_aborted);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Check result of public key verification */
-  if (ske->status != SILC_SKE_STATUS_OK) {
-    /** Public key not verified */
-    SILC_LOG_DEBUG(("Public key verification failed"));
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  recv_payload = ske->ke1_payload;
-
-  /** Send KE2 packet */
-  silc_fsm_next(fsm, silc_ske_st_responder_phase5);
-
-  /* The public key verification was performed only if the Mutual
-     Authentication flag is set. */
-  if (ske->start_payload &&
-      ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
-    unsigned char hash[SILC_HASH_MAXLEN];
-    SilcUInt32 hash_len;
-
-    SILC_LOG_DEBUG(("Public key is authentic"));
-
-    /* Compute the hash value */
-    status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
-    if (status != SILC_SKE_STATUS_OK) {
-      /** Error computing hash */
-      ske->status = status;
-      silc_fsm_next(fsm, silc_ske_st_responder_error);
-      return SILC_FSM_CONTINUE;
-    }
-
-    SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
-
-    /* Verify signature */
-    SILC_FSM_CALL(ske->key_op =
-                 silc_pkcs_verify(ske->prop->public_key,
-                                  recv_payload->sign_data,
-                                  recv_payload->sign_len,
-                                  hash, hash_len, NULL,
-                                  silc_ske_verify_cb, ske));
-    /* NOT REACHED */
-  }
-
-  return SILC_FSM_CONTINUE;
-}
-
-/* Phase-5.  Send KE2 payload */
-
-SILC_FSM_STATE(silc_ske_st_responder_phase5)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  unsigned char hash[SILC_HASH_MAXLEN], *pk;
-  SilcUInt32 hash_len, pk_len;
-  SilcMPInt *x, *KEY;
-  SilcSKEKEPayload send_payload;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  /* Create the random number x, 1 < x < q. */
-  x = silc_calloc(1, sizeof(*x));
-  silc_mp_init(x);
-  status =
-    silc_ske_create_rnd(ske, &ske->prop->group->group_order,
-                       silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
-                       x);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error generating random number */
-    silc_mp_uninit(x);
-    silc_free(x);
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Save the results for later processing */
-  send_payload = silc_calloc(1, sizeof(*send_payload));
-  ske->x = x;
-  ske->ke2_payload = send_payload;
-
-  SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
-
-  /* Do the Diffie Hellman computation, f = g ^ x mod p */
-  silc_mp_init(&send_payload->x);
-  silc_mp_pow_mod(&send_payload->x, &ske->prop->group->generator, x,
-                 &ske->prop->group->group);
-
-  SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
-
-  /* Compute the shared secret key */
-  KEY = silc_calloc(1, sizeof(*KEY));
-  silc_mp_init(KEY);
-  silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x,
-                 &ske->prop->group->group);
-  ske->KEY = KEY;
-
-  if (ske->public_key && ske->private_key) {
-    SILC_LOG_DEBUG(("Getting public key"));
-
-    /* Get the public key */
-    pk = silc_pkcs_public_key_encode(NULL, ske->public_key, &pk_len);
-    if (!pk) {
-      /** Error encoding public key */
-      status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-      silc_fsm_next(fsm, silc_ske_st_responder_error);
-      return SILC_FSM_CONTINUE;
-    }
-    ske->ke2_payload->pk_data = pk;
-    ske->ke2_payload->pk_len = pk_len;
-  }
-
-  SILC_LOG_DEBUG(("Computing HASH value"));
-
-  /* Compute the hash value */
-  memset(hash, 0, sizeof(hash));
-  status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error computing hash */
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-  ske->hash = silc_memdup(hash, hash_len);
-  ske->hash_len = hash_len;
-
-  /** Send KE2 packet */
-  silc_fsm_next(fsm, silc_ske_st_responder_phase5_send);
-
-  if (ske->public_key && ske->private_key) {
-    SILC_LOG_DEBUG(("Signing HASH value"));
-
-    /* Sign the hash value */
-    SILC_FSM_CALL(ske->key_op =
-                 silc_pkcs_sign(ske->private_key, hash, hash_len, FALSE,
-                                ske->prop->hash, ske->rng,
-                                silc_ske_responder_sign_cb, ske));
-    /* NOT REACHED */
-  }
-
-  return SILC_FSM_CONTINUE;
-}
-
-/* Send KE2 packet */
-
-SILC_FSM_STATE(silc_ske_st_responder_phase5_send)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcBuffer payload_buf;
-
-  ske->ke2_payload->pk_type = silc_pkcs_get_type(ske->public_key);
-
-  /* Encode the Key Exchange Payload */
-  status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
-                                     &payload_buf);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error encoding KE payload */
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Send the packet. */
-  if (!silc_ske_packet_send(ske, SILC_PACKET_KEY_EXCHANGE_2, 0,
-                           payload_buf->data, silc_buffer_len(payload_buf))) {
-    SILC_LOG_DEBUG(("Error sending packet"));
-    ske->status = SILC_SKE_STATUS_ERROR;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  silc_buffer_free(payload_buf);
-
-  /* In case we are doing rekey move to finish it. */
-  if (ske->rekey) {
-    /** Finish rekey */
-    silc_fsm_next(fsm, silc_ske_st_rekey_responder_done);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /** Waiting completion */
-  silc_fsm_next(fsm, silc_ske_st_responder_end);
-  return SILC_FSM_WAIT;
-}
-
-/* Protocol completed */
-
-SILC_FSM_STATE(silc_ske_st_responder_end)
-{
-  SilcSKE ske = fsm_context;
-  unsigned char tmp[4];
-  SilcUInt32 hash_len, key_len, block_len;
-
-  if (ske->packet->type != SILC_PACKET_SUCCESS) {
-    SILC_LOG_DEBUG(("Remote retransmitted an old packet"));
-    silc_ske_install_retransmission(ske);
-    silc_packet_free(ske->packet);
-    ske->packet = NULL;
-    return SILC_FSM_WAIT;
-  }
-  silc_packet_free(ske->packet);
-  ske->packet = NULL;
-
-  /* Process key material */
-  key_len = silc_cipher_get_key_len(ske->prop->cipher);
-  block_len = silc_cipher_get_block_len(ske->prop->cipher);
-  hash_len = silc_hash_len(ske->prop->hash);
-  ske->keymat = silc_ske_process_key_material(ske, block_len,
-                                             key_len, hash_len,
-                                             &ske->rekey);
-  if (!ske->keymat) {
-    /** Error processing key material */
-    ske->status = SILC_SKE_STATUS_ERROR;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Send SUCCESS packet */
-  SILC_PUT32_MSB(SILC_SKE_STATUS_OK, tmp);
-  silc_ske_packet_send(ske, SILC_PACKET_SUCCESS, 0, tmp, 4);
-
-  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
-  silc_schedule_task_del_by_context(ske->schedule, ske);
-
-  /* Call completion */
-  silc_ske_completion(ske);
-
-  return SILC_FSM_FINISH;
-}
-
-/* Aborted by application */
-
-SILC_FSM_STATE(silc_ske_st_responder_aborted)
-{
-  SilcSKE ske = fsm_context;
-  unsigned char tmp[4];
-
-  SILC_LOG_DEBUG(("Key exchange protocol aborted"));
-
-  /* Send FAILURE packet */
-  SILC_PUT32_MSB(SILC_SKE_STATUS_ERROR, tmp);
-  silc_ske_packet_send(ske, SILC_PACKET_FAILURE, 0, tmp, 4);
-
-  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
-  silc_schedule_task_del_by_context(ske->schedule, ske);
-
-  /* Call completion */
-  silc_ske_completion(ske);
-
-  return SILC_FSM_FINISH;
-}
-
-/* Failure received from remote */
-
-SILC_FSM_STATE(silc_ske_st_responder_failure)
-{
-  SilcSKE ske = fsm_context;
-  SilcUInt32 error = SILC_SKE_STATUS_ERROR;
-
-  SILC_LOG_DEBUG(("Key exchange protocol failed"));
-
-  if (ske->packet && ske->packet->type == SILC_PACKET_FAILURE &&
-      silc_buffer_len(&ske->packet->buffer) == 4) {
-    SILC_GET32_MSB(error, ske->packet->buffer.data);
-    ske->status = error;
-    silc_packet_free(ske->packet);
-    ske->packet = NULL;
-  }
-
-  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
-  silc_schedule_task_del_by_context(ske->schedule, ske);
-
-  /* Call completion */
-  silc_ske_completion(ske);
-
-  return SILC_FSM_FINISH;
-}
-
-/* Error occurred */
-
-SILC_FSM_STATE(silc_ske_st_responder_error)
-{
-  SilcSKE ske = fsm_context;
-  unsigned char tmp[4];
-
-  SILC_LOG_DEBUG(("Error %d (%s) during key exchange protocol",
-                 ske->status, silc_ske_map_status(ske->status)));
-
-  /* Send FAILURE packet */
-  if (ske->status > SILC_SKE_STATUS_INVALID_COOKIE)
-    ske->status = SILC_SKE_STATUS_BAD_PAYLOAD;
-  SILC_PUT32_MSB(ske->status, tmp);
-  silc_ske_packet_send(ske, SILC_PACKET_FAILURE, 0, tmp, 4);
-
-  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
-  silc_schedule_task_del_by_context(ske->schedule, ske);
-
-  /* Call completion */
-  silc_ske_completion(ske);
-
-  return SILC_FSM_FINISH;
-}
-
-/* Starts the protocol as responder. */
-
-SilcAsyncOperation silc_ske_responder(SilcSKE ske,
-                                     SilcPacketStream stream,
-                                     SilcSKEParams params)
-{
-  SILC_LOG_DEBUG(("Start SKE as responder"));
-
-  if (!ske || !stream || !params || !params->version)
-    return NULL;
-
-  if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
-    return NULL;
-
-  if (!silc_fsm_init(&ske->fsm, ske, silc_ske_finished, ske, ske->schedule))
-    return NULL;
-
-  ske->responder = TRUE;
-  ske->flags = params->flags;
-  ske->timeout = params->timeout_secs ? params->timeout_secs : 30;
-  if (ske->flags & SILC_SKE_SP_FLAG_IV_INCLUDED)
-    ske->session_port = params->session_port;
-  ske->version = strdup(params->version);
-  if (!ske->version)
-    return NULL;
-  ske->running = TRUE;
-
-  /* Link to packet stream to get key exchange packets */
-  ske->stream = stream;
-  silc_packet_stream_link(ske->stream, &silc_ske_stream_cbs, ske, 1000000,
-                         SILC_PACKET_KEY_EXCHANGE,
-                         SILC_PACKET_KEY_EXCHANGE_1,
-                         SILC_PACKET_SUCCESS,
-                         SILC_PACKET_FAILURE, -1);
-
-  /* Start SKE as responder */
-  silc_fsm_start(&ske->fsm, silc_ske_st_responder_start);
-
-  return &ske->op;
-}
-
-/***************************** Initiator Rekey ******************************/
-
-/* Start rekey */
-
-SILC_FSM_STATE(silc_ske_st_rekey_initiator_start)
-{
-  SilcSKE ske = fsm_context;
-  SilcStatus status;
-
-  SILC_LOG_DEBUG(("Start rekey (%s)", ske->rekey->pfs ? "PFS" : "No PFS"));
-
-  if (ske->aborted) {
-    /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Add rekey exchange timeout */
-  silc_schedule_task_add_timeout(ske->schedule, silc_ske_timeout,
-                                ske, 30, 0);
-
-  ske->prop = silc_calloc(1, sizeof(*ske->prop));
-  if (!ske->prop) {
-    /** No memory */
-    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  if (!silc_hash_alloc(ske->rekey->hash, &ske->prop->hash)) {
-    /** Cannot allocate hash */
-    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Send REKEY packet to start rekey protocol */
-  if (!silc_ske_packet_send(ske, SILC_PACKET_REKEY, 0, NULL, 0)) {
-    /** Error sending packet */
-    SILC_LOG_DEBUG(("Error sending packet"));
-    ske->status = SILC_SKE_STATUS_ERROR;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* If doing rekey without PFS, move directly to the end of the protocol. */
-  if (!ske->rekey->pfs) {
-    /** Rekey without PFS */
-    silc_fsm_next(fsm, silc_ske_st_rekey_initiator_done);
-    return SILC_FSM_CONTINUE;
-  }
-
-  status = silc_ske_group_get_by_number(ske->rekey->ske_group,
-                                       &ske->prop->group);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Unknown group */
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /** Rekey with PFS */
-  silc_fsm_next(fsm, silc_ske_st_initiator_phase2);
-  return SILC_FSM_CONTINUE;
-}
-
-/* Sends REKEY_DONE packet to finish the protocol. */
-
-SILC_FSM_STATE(silc_ske_st_rekey_initiator_done)
-{
-  SilcSKE ske = fsm_context;
-  SilcCipher send_key;
-  SilcHmac hmac_send;
-  SilcHash hash;
-  SilcUInt32 key_len, block_len, hash_len, x_len;
-  unsigned char *pfsbuf;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  silc_packet_get_keys(ske->stream, &send_key, NULL, &hmac_send, NULL);
-  key_len = silc_cipher_get_key_len(send_key);
-  block_len = silc_cipher_get_block_len(send_key);
-  hash = ske->prop->hash;
-  hash_len = silc_hash_len(hash);
-
-  /* Process key material */
-  if (ske->rekey->pfs) {
-    /* PFS */
-    pfsbuf = silc_mp_mp2bin(ske->KEY, 0, &x_len);
-    if (pfsbuf) {
-      ske->keymat = silc_ske_process_key_material_data(pfsbuf, x_len,
-                                                      block_len, key_len,
-                                                      hash_len, hash);
-      memset(pfsbuf, 0, x_len);
-      silc_free(pfsbuf);
-    }
-  } else {
-    /* No PFS */
-    ske->keymat =
-      silc_ske_process_key_material_data(ske->rekey->send_enc_key,
-                                        ske->rekey->enc_key_len / 8,
-                                        block_len, key_len,
-                                        hash_len, hash);
-  }
-
-  if (!ske->keymat) {
-    SILC_LOG_ERROR(("Error processing key material"));
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  ske->prop->cipher = send_key;
-  ske->prop->hmac = hmac_send;
-
-  /* Get sending keys */
-  if (!silc_ske_set_keys(ske, ske->keymat, ske->prop, &send_key, NULL,
-                        &hmac_send, NULL, NULL)) {
-    /** Cannot get keys */
-    ske->status = SILC_SKE_STATUS_ERROR;
-    ske->prop->cipher = NULL;
-    ske->prop->hmac = NULL;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  ske->prop->cipher = NULL;
-  ske->prop->hmac = NULL;
-
-  /* Set the new keys into use.  This will also send REKEY_DONE packet.  Any
-     packet sent after this call will be protected with the new keys. */
-  if (!silc_packet_set_keys(ske->stream, send_key, NULL, hmac_send, NULL,
-                           TRUE)) {
-    /** Cannot set keys */
-    SILC_LOG_DEBUG(("Cannot set new keys, error sending REKEY_DONE"));
-    ske->status = SILC_SKE_STATUS_ERROR;
-    silc_cipher_free(send_key);
-    silc_hmac_free(hmac_send);
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /** Wait for REKEY_DONE */
-  silc_fsm_next(fsm, silc_ske_st_rekey_initiator_end);
-  return SILC_FSM_WAIT;
-}
-
-/* Rekey protocol end */
-
-SILC_FSM_STATE(silc_ske_st_rekey_initiator_end)
-{
-  SilcSKE ske = fsm_context;
-  SilcCipher receive_key;
-  SilcHmac hmac_receive;
-  SilcSKERekeyMaterial rekey;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (ske->packet->type != SILC_PACKET_REKEY_DONE) {
-    SILC_LOG_DEBUG(("Remote retransmitted an old packet"));
-    silc_packet_free(ske->packet);
-    ske->packet = NULL;
-    return SILC_FSM_WAIT;
-  }
-
-  silc_packet_get_keys(ske->stream, NULL, &receive_key, NULL, &hmac_receive);
-  ske->prop->cipher = receive_key;
-  ske->prop->hmac = hmac_receive;
-
-  /* Get receiving keys */
-  if (!silc_ske_set_keys(ske, ske->keymat, ske->prop, NULL, &receive_key,
-                        NULL, &hmac_receive, NULL)) {
-    /** Cannot get keys */
-    ske->status = SILC_SKE_STATUS_ERROR;
-    ske->prop->cipher = NULL;
-    ske->prop->hmac = NULL;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Set new receiving keys into use.  All packets received after this will
-     be decrypted with the new keys. */
-  if (!silc_packet_set_keys(ske->stream, NULL, receive_key, NULL,
-                           hmac_receive, FALSE)) {
-    /** Cannot set keys */
-    SILC_LOG_DEBUG(("Cannot set new keys"));
-    ske->status = SILC_SKE_STATUS_ERROR;
-    silc_cipher_free(receive_key);
-    silc_hmac_free(hmac_receive);
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  SILC_LOG_DEBUG(("Rekey completed successfully"));
-
-  /* Generate new rekey material */
-  rekey = silc_ske_make_rekey_material(ske, ske->keymat);
-  if (!rekey) {
-    /** No memory */
-    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-    ske->prop->cipher = NULL;
-    ske->prop->hmac = NULL;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-  rekey->pfs = ske->rekey->pfs;
-  ske->rekey = rekey;
-
-  ske->prop->cipher = NULL;
-  ske->prop->hmac = NULL;
-  silc_packet_free(ske->packet);
-  ske->packet = NULL;
-  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
-  silc_schedule_task_del_by_context(ske->schedule, ske);
-
-  /* Call completion */
-  silc_ske_completion(ske);
-
-  return SILC_FSM_FINISH;
-}
-
-/* Starts rekey protocol as initiator */
-
-SilcAsyncOperation
-silc_ske_rekey_initiator(SilcSKE ske,
-                        SilcPacketStream stream,
-                        SilcSKERekeyMaterial rekey)
-{
-  SILC_LOG_DEBUG(("Start SKE rekey as initator"));
-
-  if (!ske || !stream || !rekey) {
-    SILC_LOG_ERROR(("Missing arguments to silc_ske_rekey_initiator"));
-    SILC_ASSERT(rekey);
-    return NULL;
-  }
-
-  if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
-    return NULL;
-
-  if (!silc_fsm_init(&ske->fsm, ske, silc_ske_finished, ske, ske->schedule))
-    return NULL;
-
-  ske->rekey = rekey;
-  ske->responder = FALSE;
-  ske->running = TRUE;
-  ske->rekeying = TRUE;
-
-  /* Link to packet stream to get key exchange packets */
-  ske->stream = stream;
-  silc_packet_stream_link(ske->stream, &silc_ske_stream_cbs, ske, 1000000,
-                         SILC_PACKET_REKEY,
-                         SILC_PACKET_REKEY_DONE,
-                         SILC_PACKET_KEY_EXCHANGE_2,
-                         SILC_PACKET_SUCCESS,
-                         SILC_PACKET_FAILURE, -1);
-
-  /* Start SKE rekey as initiator */
-  silc_fsm_start(&ske->fsm, silc_ske_st_rekey_initiator_start);
-
-  return &ske->op;
-}
-
-/***************************** Responder Rekey ******************************/
-
-/* Wait for initiator's packet */
-
-SILC_FSM_STATE(silc_ske_st_rekey_responder_wait)
-{
-  SilcSKE ske = fsm_context;
-
-  SILC_LOG_DEBUG(("Start rekey (%s)", ske->rekey->pfs ? "PFS" : "No PFS"));
-
-  if (ske->aborted) {
-    /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_responder_aborted);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Add rekey exchange timeout */
-  silc_schedule_task_add_timeout(ske->schedule, silc_ske_timeout,
-                                ske, 30, 0);
-
-  silc_fsm_next(fsm, silc_ske_st_rekey_responder_start);
-
-  /* If REKEY packet already received process it directly */
-  if (ske->packet && ske->packet->type == SILC_PACKET_REKEY)
-    return SILC_FSM_CONTINUE;
-
-  /* Wait for REKEY */
-  return SILC_FSM_WAIT;
-}
-
-/* Process initiator's REKEY packet */
-
-SILC_FSM_STATE(silc_ske_st_rekey_responder_start)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (ske->packet->type != SILC_PACKET_REKEY) {
-    ske->status = SILC_SKE_STATUS_ERROR;
-    silc_packet_free(ske->packet);
-    ske->packet = NULL;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  ske->prop = silc_calloc(1, sizeof(*ske->prop));
-  if (!ske->prop) {
-    /** No memory */
-    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  if (!silc_hash_alloc(ske->rekey->hash, &ske->prop->hash)) {
-    /** Cannot allocate hash */
-    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* If doing rekey without PFS, move directly to the end of the protocol. */
-  if (!ske->rekey->pfs) {
-    /** Rekey without PFS */
-    silc_fsm_next(fsm, silc_ske_st_rekey_responder_done);
-    return SILC_FSM_CONTINUE;
-  }
-
-  status = silc_ske_group_get_by_number(ske->rekey->ske_group,
-                                       &ske->prop->group);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Unknown group */
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /** Rekey with PFS */
-  silc_fsm_next(fsm, silc_ske_st_responder_phase2);
-  return SILC_FSM_WAIT;
-}
-
-/* Sends REKEY_DONE packet to finish the protocol. */
-
-SILC_FSM_STATE(silc_ske_st_rekey_responder_done)
-{
-  SilcSKE ske = fsm_context;
-  SilcCipher send_key;
-  SilcHmac hmac_send;
-  SilcHash hash;
-  SilcUInt32 key_len, block_len, hash_len, x_len;
-  unsigned char *pfsbuf;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  silc_packet_get_keys(ske->stream, &send_key, NULL, &hmac_send, NULL);
-  key_len = silc_cipher_get_key_len(send_key);
-  block_len = silc_cipher_get_block_len(send_key);
-  hash = ske->prop->hash;
-  hash_len = silc_hash_len(hash);
-
-  /* Process key material */
-  if (ske->rekey->pfs) {
-    /* PFS */
-    pfsbuf = silc_mp_mp2bin(ske->KEY, 0, &x_len);
-    if (pfsbuf) {
-      ske->keymat = silc_ske_process_key_material_data(pfsbuf, x_len,
-                                                      block_len, key_len,
-                                                      hash_len, hash);
-      memset(pfsbuf, 0, x_len);
-      silc_free(pfsbuf);
-    }
-  } else {
-    /* No PFS */
-    ske->keymat =
-      silc_ske_process_key_material_data(ske->rekey->send_enc_key,
-                                        ske->rekey->enc_key_len / 8,
-                                        block_len, key_len,
-                                        hash_len, hash);
-  }
-
-  if (!ske->keymat) {
-    SILC_LOG_ERROR(("Error processing key material"));
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  ske->prop->cipher = send_key;
-  ske->prop->hmac = hmac_send;
-
-  /* Get sending keys */
-  if (!silc_ske_set_keys(ske, ske->keymat, ske->prop, &send_key, NULL,
-                        &hmac_send, NULL, NULL)) {
-    /** Cannot get keys */
-    ske->status = SILC_SKE_STATUS_ERROR;
-    ske->prop->cipher = NULL;
-    ske->prop->hmac = NULL;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  ske->prop->cipher = NULL;
-  ske->prop->hmac = NULL;
-
-  /* Set the new keys into use.  This will also send REKEY_DONE packet.  Any
-     packet sent after this call will be protected with the new keys. */
-  if (!silc_packet_set_keys(ske->stream, send_key, NULL, hmac_send, NULL,
-                           TRUE)) {
-    /** Cannot set keys */
-    SILC_LOG_DEBUG(("Cannot set new keys, error sending REKEY_DONE"));
-    ske->status = SILC_SKE_STATUS_ERROR;
-    silc_cipher_free(send_key);
-    silc_hmac_free(hmac_send);
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /** Wait for REKEY_DONE */
-  silc_fsm_next(fsm, silc_ske_st_rekey_responder_end);
-  return SILC_FSM_WAIT;
-}
-
-/* Rekey protocol end */
-
-SILC_FSM_STATE(silc_ske_st_rekey_responder_end)
-{
-  SilcSKE ske = fsm_context;
-  SilcCipher receive_key;
-  SilcHmac hmac_receive;
-  SilcSKERekeyMaterial rekey;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (ske->packet->type != SILC_PACKET_REKEY_DONE) {
-    SILC_LOG_DEBUG(("Remote retransmitted an old packet"));
-    silc_packet_free(ske->packet);
-    ske->packet = NULL;
-    return SILC_FSM_WAIT;
-  }
-
-  silc_packet_get_keys(ske->stream, NULL, &receive_key, NULL, &hmac_receive);
-  ske->prop->cipher = receive_key;
-  ske->prop->hmac = hmac_receive;
-
-  /* Get receiving keys */
-  if (!silc_ske_set_keys(ske, ske->keymat, ske->prop, NULL, &receive_key,
-                        NULL, &hmac_receive, NULL)) {
-    /** Cannot get keys */
-    ske->status = SILC_SKE_STATUS_ERROR;
-    ske->prop->cipher = NULL;
-    ske->prop->hmac = NULL;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Set new receiving keys into use.  All packets received after this will
-     be decrypted with the new keys. */
-  if (!silc_packet_set_keys(ske->stream, NULL, receive_key, NULL,
-                           hmac_receive, FALSE)) {
-    /** Cannot set keys */
-    SILC_LOG_DEBUG(("Cannot set new keys"));
-    ske->status = SILC_SKE_STATUS_ERROR;
-    ske->prop->cipher = NULL;
-    ske->prop->hmac = NULL;
-    silc_cipher_free(receive_key);
-    silc_hmac_free(hmac_receive);
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  SILC_LOG_DEBUG(("Rekey completed successfully"));
-
-  /* Generate new rekey material */
-  rekey = silc_ske_make_rekey_material(ske, ske->keymat);
-  if (!rekey) {
-    /** No memory */
-    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-    ske->prop->cipher = NULL;
-    ske->prop->hmac = NULL;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-  rekey->pfs = ske->rekey->pfs;
-  ske->rekey = rekey;
-
-  ske->prop->cipher = NULL;
-  ske->prop->hmac = NULL;
-  silc_packet_free(ske->packet);
-  ske->packet = NULL;
-  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
-  silc_schedule_task_del_by_context(ske->schedule, ske);
-
-  /* Call completion */
-  silc_ske_completion(ske);
-
-  return SILC_FSM_FINISH;
-}
-
-/* Starts rekey protocol as responder */
-
-SilcAsyncOperation
-silc_ske_rekey_responder(SilcSKE ske,
-                        SilcPacketStream stream,
-                        SilcSKERekeyMaterial rekey,
-                        SilcPacket packet)
-{
-  SILC_LOG_DEBUG(("Start SKE rekey as responder"));
-
-  if (!ske || !stream || !rekey)
-    return NULL;
-
-  if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
-    return NULL;
-
-  if (!silc_fsm_init(&ske->fsm, ske, silc_ske_finished, ske, ske->schedule))
-    return NULL;
-
-  ske->rekey = rekey;
-  ske->responder = TRUE;
-  ske->running = TRUE;
-  ske->rekeying = TRUE;
-  ske->packet = packet;
-
-  /* Link to packet stream to get key exchange packets */
-  ske->stream = stream;
-  silc_packet_stream_link(ske->stream, &silc_ske_stream_cbs, ske, 1000000,
-                         SILC_PACKET_REKEY,
-                         SILC_PACKET_REKEY_DONE,
-                         SILC_PACKET_KEY_EXCHANGE_1,
-                         SILC_PACKET_SUCCESS,
-                         SILC_PACKET_FAILURE, -1);
-
-  /* Start SKE rekey as responder */
-  silc_fsm_start_sync(&ske->fsm, silc_ske_st_rekey_responder_wait);
-
-  return &ske->op;
-}
-
-/* Processes the provided key material `data' as the SILC protocol
-   specification defines. */
-
-SilcSKEKeyMaterial
-silc_ske_process_key_material_data(unsigned char *data,
-                                  SilcUInt32 data_len,
-                                  SilcUInt32 req_iv_len,
-                                  SilcUInt32 req_enc_key_len,
-                                  SilcUInt32 req_hmac_key_len,
-                                  SilcHash hash)
-{
-  SilcBuffer buf;
-  unsigned char hashd[SILC_HASH_MAXLEN];
-  SilcUInt32 hash_len = req_hmac_key_len;
-  SilcUInt32 enc_key_len = req_enc_key_len / 8;
-  SilcSKEKeyMaterial key;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
-    return NULL;
-
-  key = silc_calloc(1, sizeof(*key));
-  if (!key)
-    return NULL;
-
-  buf = silc_buffer_alloc_size(1 + data_len);
-  if (!buf)
-    return NULL;
-  silc_buffer_format(buf,
-                    SILC_STR_UI_CHAR(0),
-                    SILC_STR_DATA(data, data_len),
-                    SILC_STR_END);
-
-  /* Take IVs */
-  memset(hashd, 0, sizeof(hashd));
-  buf->data[0] = 0;
-  silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
-  key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
-  memcpy(key->send_iv, hashd, req_iv_len);
-  memset(hashd, 0, sizeof(hashd));
-  buf->data[0] = 1;
-  silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
-  key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
-  memcpy(key->receive_iv, hashd, req_iv_len);
-  key->iv_len = req_iv_len;
-
-  /* Take the encryption keys. If requested key size is more than
-     the size of hash length we will distribute more key material
-     as protocol defines. */
-  buf->data[0] = 2;
-  if (enc_key_len > hash_len) {
-    SilcBuffer dist;
-    unsigned char k1[SILC_HASH_MAXLEN], k2[SILC_HASH_MAXLEN],
-       k3[SILC_HASH_MAXLEN];
-    unsigned char *dtmp;
-
-    /* XXX */
-    if (enc_key_len > (3 * hash_len))
-      return NULL;
-
-    /* Take first round */
-    memset(k1, 0, sizeof(k1));
-    silc_hash_make(hash, buf->data, silc_buffer_len(buf), k1);
-
-    /* Take second round */
-    dist = silc_buffer_alloc_size(data_len + hash_len);
-    if (!dist)
-      return NULL;
-    silc_buffer_format(dist,
-                      SILC_STR_DATA(data, data_len),
-                      SILC_STR_DATA(k1, hash_len),
-                      SILC_STR_END);
-    memset(k2, 0, sizeof(k2));
-    silc_hash_make(hash, dist->data, silc_buffer_len(dist), k2);
-
-    /* Take third round */
-    dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
-    silc_buffer_pull_tail(dist, hash_len);
-    silc_buffer_pull(dist, data_len + hash_len);
-    silc_buffer_format(dist,
-                      SILC_STR_DATA(k2, hash_len),
-                      SILC_STR_END);
-    silc_buffer_push(dist, data_len + hash_len);
-    memset(k3, 0, sizeof(k3));
-    silc_hash_make(hash, dist->data, silc_buffer_len(dist), k3);
-
-    /* Then, save the keys */
-    dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
-    memcpy(dtmp, k1, hash_len);
-    memcpy(dtmp + hash_len, k2, hash_len);
-    memcpy(dtmp + hash_len + hash_len, k3, hash_len);
-
-    key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
-    memcpy(key->send_enc_key, dtmp, enc_key_len);
-    key->enc_key_len = req_enc_key_len;
-
-    memset(dtmp, 0, (3 * hash_len));
-    memset(k1, 0, sizeof(k1));
-    memset(k2, 0, sizeof(k2));
-    memset(k3, 0, sizeof(k3));
-    silc_free(dtmp);
-    silc_buffer_clear(dist);
-    silc_buffer_free(dist);
-  } else {
-    /* Take normal hash as key */
-    memset(hashd, 0, sizeof(hashd));
-    silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
-    key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
-    memcpy(key->send_enc_key, hashd, enc_key_len);
-    key->enc_key_len = req_enc_key_len;
-  }
-
-  buf->data[0] = 3;
-  if (enc_key_len > hash_len) {
-    SilcBuffer dist;
-    unsigned char k1[SILC_HASH_MAXLEN], k2[SILC_HASH_MAXLEN],
-       k3[SILC_HASH_MAXLEN];
-    unsigned char *dtmp;
-
-    /* XXX */
-    if (enc_key_len > (3 * hash_len))
-      return NULL;
-
-    /* Take first round */
-    memset(k1, 0, sizeof(k1));
-    silc_hash_make(hash, buf->data, silc_buffer_len(buf), k1);
-
-    /* Take second round */
-    dist = silc_buffer_alloc_size(data_len + hash_len);
-    if (!dist)
-      return NULL;
-    silc_buffer_format(dist,
-                      SILC_STR_DATA(data, data_len),
-                      SILC_STR_DATA(k1, hash_len),
-                      SILC_STR_END);
-    memset(k2, 0, sizeof(k2));
-    silc_hash_make(hash, dist->data, silc_buffer_len(dist), k2);
-
-    /* Take third round */
-    dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
-    silc_buffer_pull_tail(dist, hash_len);
-    silc_buffer_pull(dist, data_len + hash_len);
-    silc_buffer_format(dist,
-                      SILC_STR_DATA(k2, hash_len),
-                      SILC_STR_END);
-    silc_buffer_push(dist, data_len + hash_len);
-    memset(k3, 0, sizeof(k3));
-    silc_hash_make(hash, dist->data, silc_buffer_len(dist), k3);
-
-    /* Then, save the keys */
-    dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
-    memcpy(dtmp, k1, hash_len);
-    memcpy(dtmp + hash_len, k2, hash_len);
-    memcpy(dtmp + hash_len + hash_len, k3, hash_len);
-
-    key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
-    memcpy(key->receive_enc_key, dtmp, enc_key_len);
-    key->enc_key_len = req_enc_key_len;
-
-    memset(dtmp, 0, (3 * hash_len));
-    memset(k1, 0, sizeof(k1));
-    memset(k2, 0, sizeof(k2));
-    memset(k3, 0, sizeof(k3));
-    silc_free(dtmp);
-    silc_buffer_clear(dist);
-    silc_buffer_free(dist);
-  } else {
-    /* Take normal hash as key */
-    memset(hashd, 0, sizeof(hashd));
-    silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
-    key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
-    memcpy(key->receive_enc_key, hashd, enc_key_len);
-    key->enc_key_len = req_enc_key_len;
-  }
-
-  /* Take HMAC keys */
-  memset(hashd, 0, sizeof(hashd));
-  buf->data[0] = 4;
-  silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
-  key->send_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
-  memcpy(key->send_hmac_key, hashd, req_hmac_key_len);
-  memset(hashd, 0, sizeof(hashd));
-  buf->data[0] = 5;
-  silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
-  key->receive_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
-  memcpy(key->receive_hmac_key, hashd, req_hmac_key_len);
-  key->hmac_key_len = req_hmac_key_len;
-  memset(hashd, 0, sizeof(hashd));
-
-  silc_buffer_clear(buf);
-  silc_buffer_free(buf);
-
-  SILC_LOG_HEXDUMP(("enc"), key->send_enc_key, key->enc_key_len / 8);
-
-  return key;
-}
-
-/* Processes negotiated key material as protocol specifies. This returns
-   the actual keys to be used in the SILC. */
-
-SilcSKEKeyMaterial
-silc_ske_process_key_material(SilcSKE ske,
-                             SilcUInt32 req_iv_len,
-                             SilcUInt32 req_enc_key_len,
-                             SilcUInt32 req_hmac_key_len,
-                             SilcSKERekeyMaterial *rekey)
-{
-  SilcBuffer buf;
-  unsigned char *tmpbuf;
-  SilcUInt32 klen;
-  SilcSKEKeyMaterial key;
-
-  /* Encode KEY to binary data */
-  tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
-
-  buf = silc_buffer_alloc_size(klen + ske->hash_len);
-  if (!buf)
-    return NULL;
-  silc_buffer_format(buf,
-                    SILC_STR_DATA(tmpbuf, klen),
-                    SILC_STR_DATA(ske->hash, ske->hash_len),
-                    SILC_STR_END);
-
-  /* Process the key material */
-  key = silc_ske_process_key_material_data(buf->data, silc_buffer_len(buf),
-                                          req_iv_len, req_enc_key_len,
-                                          req_hmac_key_len,
-                                          ske->prop->hash);
-
-  memset(tmpbuf, 0, klen);
-  silc_free(tmpbuf);
-  silc_buffer_clear(buf);
-  silc_buffer_free(buf);
-
-  if (rekey) {
-    *rekey = silc_ske_make_rekey_material(ske, key);
-    if (!(*rekey))
-      return NULL;
-  }
-
-  return key;
-}
-
-/* Free key material structure */
-
-void silc_ske_free_key_material(SilcSKEKeyMaterial key)
-{
-  if (!key)
-    return;
-
-  if (key->send_iv)
-    silc_free(key->send_iv);
-  if (key->receive_iv)
-    silc_free(key->receive_iv);
-  if (key->send_enc_key) {
-    memset(key->send_enc_key, 0, key->enc_key_len / 8);
-    silc_free(key->send_enc_key);
-  }
-  if (key->receive_enc_key) {
-    memset(key->receive_enc_key, 0, key->enc_key_len / 8);
-    silc_free(key->receive_enc_key);
-  }
-  if (key->send_hmac_key) {
-    memset(key->send_hmac_key, 0, key->hmac_key_len);
-    silc_free(key->send_hmac_key);
-  }
-  if (key->receive_hmac_key) {
-    memset(key->receive_hmac_key, 0, key->hmac_key_len);
-    silc_free(key->receive_hmac_key);
-  }
-  silc_free(key);
-}
-
-/* Free rekey material */
-
-void silc_ske_free_rekey_material(SilcSKERekeyMaterial rekey)
-{
-  if (!rekey)
-    return;
-  if (rekey->send_enc_key) {
-    memset(rekey->send_enc_key, 0, rekey->enc_key_len / 8);
-    silc_free(rekey->send_enc_key);
-  }
-  silc_free(rekey->hash);
-  silc_free(rekey);
-}
-
-/* Set keys into use */
-
-SilcBool silc_ske_set_keys(SilcSKE ske,
-                          SilcSKEKeyMaterial keymat,
-                          SilcSKESecurityProperties prop,
-                          SilcCipher *ret_send_key,
-                          SilcCipher *ret_receive_key,
-                          SilcHmac *ret_hmac_send,
-                          SilcHmac *ret_hmac_receive,
-                          SilcHash *ret_hash)
-{
-  unsigned char iv[SILC_HASH_MAXLEN];
-  SilcBool iv_included = (prop->flags & SILC_SKE_SP_FLAG_IV_INCLUDED);
-
-  /* Allocate ciphers to be used in the communication */
-  if (ret_send_key) {
-    if (!silc_cipher_alloc((char *)silc_cipher_get_name(prop->cipher),
-                          ret_send_key))
-      return FALSE;
-  }
-  if (ret_receive_key) {
-    if (!silc_cipher_alloc((char *)silc_cipher_get_name(prop->cipher),
-                          ret_receive_key))
-      return FALSE;
-  }
-
-  /* Allocate HMACs */
-  if (ret_hmac_send) {
-    if (!silc_hmac_alloc((char *)silc_hmac_get_name(prop->hmac), NULL,
-                        ret_hmac_send))
-      return FALSE;
-  }
-  if (ret_hmac_receive) {
-    if (!silc_hmac_alloc((char *)silc_hmac_get_name(prop->hmac), NULL,
-                        ret_hmac_receive))
-      return FALSE;
-  }
-
-  /* Allocate hash */
-  if (ret_hash) {
-    if (!silc_hash_alloc(silc_hash_get_name(prop->hash), ret_hash))
-      return FALSE;
-  }
-
-  /* Set key material */
-  memset(iv, 0, sizeof(iv));
-  if (ske->responder) {
-    if (ret_send_key) {
-      silc_cipher_set_key(*ret_send_key, keymat->receive_enc_key,
-                         keymat->enc_key_len, TRUE);
-
-      if (silc_cipher_get_mode(*ret_send_key) == SILC_CIPHER_MODE_CTR) {
-       /* Counter mode */
-       if (!ske->rekeying) {
-         /* Set IV. */
-         memcpy(iv, ske->hash, 4);
-         if (!iv_included)
-           memcpy(iv + 4, keymat->receive_iv, 8);
-       } else {
-         /* Rekey, recompute the truncated hash value. */
-         silc_hash_make(prop->hash, keymat->receive_iv, 8, iv);
-         if (!iv_included)
-           memcpy(iv + 4, keymat->receive_iv, 8);
-         else
-           memset(iv + 4, 0, 12);
-       }
-
-        silc_cipher_set_iv(*ret_send_key, iv);
-      } else {
-       /* Other modes */
-       silc_cipher_set_iv(*ret_send_key, keymat->receive_iv);
-      }
-    }
-    if (ret_receive_key) {
-      silc_cipher_set_key(*ret_receive_key, keymat->send_enc_key,
-                         keymat->enc_key_len, FALSE);
-
-      if (silc_cipher_get_mode(*ret_receive_key) == SILC_CIPHER_MODE_CTR) {
-       /* Counter mode */
-       if (!ske->rekeying) {
-         /* Set IV. */
-         memcpy(iv, ske->hash, 4);
-         if (!iv_included)
-           memcpy(iv + 4, keymat->send_iv, 8);
-       } else {
-         /* Rekey, recompute the truncated hash value. */
-         silc_hash_make(prop->hash, keymat->send_iv, 8, iv);
-         if (!iv_included)
-           memcpy(iv + 4, keymat->send_iv, 8);
-         else
-           memset(iv + 4, 0, 12);
-       }
-
-        silc_cipher_set_iv(*ret_receive_key, iv);
-      } else {
-       /* Other modes */
-       silc_cipher_set_iv(*ret_receive_key, keymat->send_iv);
-      }
-    }
-    if (ret_hmac_send)
-      silc_hmac_set_key(*ret_hmac_send, keymat->receive_hmac_key,
-                       keymat->hmac_key_len);
-    if (ret_hmac_receive)
-      silc_hmac_set_key(*ret_hmac_receive, keymat->send_hmac_key,
-                       keymat->hmac_key_len);
-  } else {
-    if (ret_send_key) {
-      silc_cipher_set_key(*ret_send_key, keymat->send_enc_key,
-                         keymat->enc_key_len, TRUE);
-
-      if (silc_cipher_get_mode(*ret_send_key) == SILC_CIPHER_MODE_CTR) {
-       /* Counter mode */
-       if (!ske->rekeying) {
-         /* Set IV. */
-         memcpy(iv, ske->hash, 4);
-         if (!iv_included)
-           memcpy(iv + 4, keymat->send_iv, 8);
-       } else {
-         /* Rekey, recompute the truncated hash value. */
-         silc_hash_make(prop->hash, keymat->send_iv, 8, iv);
-         if (!iv_included)
-           memcpy(iv + 4, keymat->send_iv, 8);
-         else
-           memset(iv + 4, 0, 12);
-       }
-
-       silc_cipher_set_iv(*ret_send_key, iv);
-      } else {
-       /* Other modes */
-       silc_cipher_set_iv(*ret_send_key, keymat->send_iv);
-      }
-    }
-    if (ret_receive_key) {
-      silc_cipher_set_key(*ret_receive_key, keymat->receive_enc_key,
-                         keymat->enc_key_len, FALSE);
-
-      if (silc_cipher_get_mode(*ret_receive_key) == SILC_CIPHER_MODE_CTR) {
-       /* Counter mode */
-       if (!ske->rekeying) {
-         /* Set IV.  If IV Included flag was negotiated we only set the
-            truncated hash value. */
-         memcpy(iv, ske->hash, 4);
-         if (!iv_included)
-           memcpy(iv + 4, keymat->receive_iv, 8);
-       } else {
-         /* Rekey, recompute the truncated hash value. */
-         silc_hash_make(prop->hash, keymat->receive_iv, 8, iv);
-         if (!iv_included)
-           memcpy(iv + 4, keymat->receive_iv, 8);
-         else
-           memset(iv + 4, 0, 12);
-       }
-
-       silc_cipher_set_iv(*ret_receive_key, iv);
-      } else {
-       /* Other modes */
-       silc_cipher_set_iv(*ret_receive_key, keymat->receive_iv);
-      }
-    }
-    if (ret_hmac_send)
-      silc_hmac_set_key(*ret_hmac_send, keymat->send_hmac_key,
-                       keymat->hmac_key_len);
-    if (ret_hmac_receive)
-      silc_hmac_set_key(*ret_hmac_receive, keymat->receive_hmac_key,
-                       keymat->hmac_key_len);
-  }
-
-  return TRUE;
-}
-
-const char *silc_ske_status_string[] =
-{
-  /* Official */
-  "Ok",
-  "Unexpected error occurred",
-  "Bad payload in packet",
-  "Unsupported group",
-  "Unsupported cipher",
-  "Unsupported PKCS",
-  "Unsupported hash function",
-  "Unsupported HMAC",
-  "Unsupported public key (or certificate)",
-  "Incorrect signature",
-  "Bad or unsupported version",
-  "Invalid cookie",
-
-  /* Other errors */
-  "Remote did not provide public key",
-  "Bad reserved field in packet",
-  "Bad payload length in packet",
-  "Error computing signature",
-  "System out of memory",
-  "Key exchange timeout",
-
-  NULL
-};
-
-/* Maps status to readable string and returns the string. If string is not
-   found and empty character string ("") is returned. */
-
-const char *silc_ske_map_status(SilcSKEStatus status)
-{
-  int i;
-
-  for (i = 0; silc_ske_status_string[i]; i++)
-    if (status == i)
-      return silc_ske_status_string[i];
-
-  return "";
-}
-
-/* Parses remote host's version string. */
-
-SilcBool silc_ske_parse_version(SilcSKE ske,
-                               SilcUInt32 *protocol_version,
-                               char **protocol_version_string,
-                               SilcUInt32 *software_version,
-                               char **software_version_string,
-                               char **vendor_version)
-{
-  return silc_parse_version_string(ske->remote_version,
-                                  protocol_version,
-                                  protocol_version_string,
-                                  software_version,
-                                  software_version_string,
-                                  vendor_version);
-}
-
-/* Get security properties */
-
-SilcSKESecurityProperties silc_ske_get_security_properties(SilcSKE ske)
-{
-  return ske->prop;
-}
-
-/* Get key material */
-
-SilcSKEKeyMaterial silc_ske_get_key_material(SilcSKE ske)
-{
-  return ske->keymat;
-}