Initial code commit for Toolkit 1.1.
[silc.git] / lib / silcske / silcske.c
index a6b23c857918cbf090182b3cfc8f86644c266f7d..26690f7a86d8727c7f106598fe49c748b83bddce 100644 (file)
@@ -4,13 +4,12 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2000 - 2001 Pekka Riikonen
+  Copyright (C) 2000 - 2005 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
+  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
 #include "silcske.h"
 #include "groups_internal.h"
 
+/* Static functions */
+static SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n,
+                                        SilcUInt32 len,
+                                        SilcMPInt *rnd);
+static SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
+                                       unsigned char *return_hash,
+                                       SilcUInt32 *return_hash_len,
+                                       int initiator);
+
 /* Structure to hold all SKE callbacks. */
 struct SilcSKECallbacksStruct {
   SilcSKESendPacketCb send_packet;
@@ -35,14 +43,18 @@ struct SilcSKECallbacksStruct {
 
 /* Allocates new SKE object. */
 
-SilcSKE silc_ske_alloc()
+SilcSKE silc_ske_alloc(SilcRng rng, void *context)
 {
   SilcSKE ske;
 
   SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
 
   ske = silc_calloc(1, sizeof(*ske));
+  if (!ske)
+    return NULL;
   ske->status = SILC_SKE_STATUS_OK;
+  ske->rng = rng;
+  ske->user_data = context;
   ske->users = 1;
 
   return ske;
@@ -71,6 +83,7 @@ void silc_ske_free(SilcSKE ske)
       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) {
@@ -98,15 +111,17 @@ void silc_ske_free(SilcSKE ske)
     }
     silc_free(ske->hash);
     silc_free(ske->callbacks);
+
+    memset(ske, 'F', sizeof(*ske));
     silc_free(ske);
   }
 }
 
-/* Sets the callback functions for the SKE session. 
+/* Sets the callback functions for the SKE session.
 
    The `send_packet' callback is a function that sends the packet to
    network. The SKE library will call it at any time packet needs to
-   be sent to the remote host. 
+   be sent to the remote host.
 
    The `payload_receive' callback is called when the remote host's Key
    Exchange Start Payload has been processed.  The payload is saved
@@ -118,8 +133,8 @@ void silc_ske_free(SilcSKE ske)
    That is why the application must call the completion callback when the
    verification process has been completed. The library then calls the user
    callback (`proto_continue'), if it is provided to indicate that the SKE
-   protocol may continue. 
-   
+   protocol may continue.
+
    The `proto_continue' callback is called to indicate that it is
    safe to continue the execution of the SKE protocol after executing
    an asynchronous operation, such as calling the `verify_key' callback
@@ -130,7 +145,7 @@ void silc_ske_free(SilcSKE ske)
    The `check_version' callback is called to verify the remote host's
    version. The application may check its own version against the remote
    host's version and determine whether supporting the remote host
-   is possible. 
+   is possible.
 
    The `context' is passed as argument to all of the above callback
    functions. */
@@ -146,6 +161,8 @@ void silc_ske_set_callbacks(SilcSKE ske,
   if (ske->callbacks)
     silc_free(ske->callbacks);
   ske->callbacks = silc_calloc(1, sizeof(*ske->callbacks));
+  if (!ske->callbacks)
+    return;
   ske->callbacks->send_packet = send_packet;
   ske->callbacks->payload_receive = payload_receive;
   ske->callbacks->verify_key = verify_key;
@@ -184,17 +201,15 @@ SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
   if (status != SILC_SKE_STATUS_OK)
     return status;
 
-  /* 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(payload_buf);
-  ske->start_payload = start_payload;
-
   /* Send the packet. */
   if (ske->callbacks->send_packet)
-    (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, 
+    (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
                                   ske->callbacks->context);
 
-  silc_buffer_free(payload_buf);
+  /* Save the the payload buffer for future use. It is later used to
+     compute the HASH value. */
+  ske->start_payload_copy = payload_buf;
+  ske->start_payload = start_payload;
 
   return status;
 }
@@ -204,7 +219,7 @@ SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
    security properties selected by the responder from our payload
    sent in the silc_ske_initiator_start function. */
 
-SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, 
+SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
                                         SilcBuffer start_payload)
 {
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
@@ -225,7 +240,7 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
   /* Check that the cookie is returned unmodified */
   if (memcmp(ske->start_payload->cookie, payload->cookie,
             ske->start_payload->cookie_len)) {
-    SILC_LOG_DEBUG(("Responder modified our cookie and it must not do it"));
+    SILC_LOG_ERROR(("Responder modified our cookie and it must not do it"));
     ske->status = SILC_SKE_STATUS_INVALID_COOKIE;
     silc_ske_payload_start_free(ske->start_payload);
     return status;
@@ -233,7 +248,7 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
 
   /* Check version string */
   if (ske->callbacks->check_version) {
-    status = ske->callbacks->check_version(ske, payload->version, 
+    status = ske->callbacks->check_version(ske, payload->version,
                                           payload->version_len,
                                           ske->callbacks->context);
     if (status != SILC_SKE_STATUS_OK) {
@@ -247,10 +262,12 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
   silc_ske_payload_start_free(ske->start_payload);
 
   /* Take the selected security properties into use while doing
-     the key exchange. This is used only while doing the key 
+     the key exchange. This is used only while doing the key
      exchange. The same data is returned to upper levels by calling
      the callback function. */
   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)
@@ -311,26 +328,31 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
   return status;
 }
 
-/* This function creates random number x, such that 1 < x < q and 
-   computes e = g ^ x mod p and sends the result to the remote end in 
+/* This function creates random number x, such that 1 < x < q and
+   computes e = g ^ x mod p and sends the result to the remote end in
    Key Exchange Payload. */
 
 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
                                         SilcPublicKey public_key,
-                                        SilcPrivateKey private_key)
+                                        SilcPrivateKey private_key,
+                                        SilcSKEPKType pk_type)
 {
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
   SilcBuffer payload_buf;
   SilcMPInt *x;
   SilcSKEKEPayload *payload;
-  uint32 pk_len;
+  SilcUInt32 pk_len;
 
   SILC_LOG_DEBUG(("Start"));
 
   /* Create the random number x, 1 < x < q. */
   x = silc_calloc(1, sizeof(*x));
+  if (!x){
+    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+    return ske->status;
+  }
   silc_mp_init(x);
-  status = 
+  status =
     silc_ske_create_rnd(ske, &ske->prop->group->group_order,
                        silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
                        x);
@@ -344,13 +366,19 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
   /* Encode the result to Key Exchange Payload. */
 
   payload = silc_calloc(1, sizeof(*payload));
+  if (!payload) {
+    silc_mp_uninit(x);
+    silc_free(x);
+    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+    return ske->status;
+  }
   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, 
+  silc_mp_pow_mod(&payload->x, &ske->prop->group->generator, x,
                  &ske->prop->group->group);
 
   /* Get public key */
@@ -361,17 +389,18 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
       silc_free(x);
       silc_mp_uninit(&payload->x);
       silc_free(payload);
+      ske->ke1_payload = NULL;
       ske->status = SILC_SKE_STATUS_OK;
       return ske->status;
     }
     payload->pk_len = pk_len;
   }
-  payload->pk_type = SILC_SKE_PK_TYPE_SILC;
+  payload->pk_type = pk_type;
 
   /* Compute signature data if we are doing mutual authentication */
   if (private_key && ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
-    unsigned char hash[32], sign[1024];
-    uint32 hash_len, sign_len;
+    unsigned char hash[SILC_HASH_MAXLEN], sign[2048 + 1];
+    SilcUInt32 hash_len, sign_len;
 
     SILC_LOG_DEBUG(("We are doing mutual authentication"));
     SILC_LOG_DEBUG(("Computing HASH_i value"));
@@ -381,15 +410,24 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
     silc_ske_make_hash(ske, hash, &hash_len, TRUE);
 
     SILC_LOG_DEBUG(("Signing HASH_i value"));
-    
+
     /* Sign the hash value */
-    silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
+    silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
                                   private_key->prv_len);
-    silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
-    payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
-    memcpy(payload->sign_data, sign, sign_len);
-    memset(sign, 0, sizeof(sign));
+    if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 ||
+       !silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) {
+      silc_mp_uninit(x);
+      silc_free(x);
+      silc_mp_uninit(&payload->x);
+      silc_free(payload->pk_data);
+      silc_free(payload);
+      ske->ke1_payload = NULL;
+      ske->status = SILC_SKE_STATUS_SIGNATURE_ERROR;
+      return ske->status;
+    }
+    payload->sign_data = silc_memdup(sign, sign_len);
     payload->sign_len = sign_len;
+    memset(sign, 0, sizeof(sign));
   }
 
   status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
@@ -398,7 +436,9 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
     silc_free(x);
     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;
     return status;
   }
@@ -407,8 +447,8 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
 
   /* Send the packet. */
   if (ske->callbacks->send_packet)
-    (*ske->callbacks->send_packet)(ske, payload_buf, 
-                                  SILC_PACKET_KEY_EXCHANGE_1, 
+    (*ske->callbacks->send_packet)(ske, payload_buf,
+                                  SILC_PACKET_KEY_EXCHANGE_1,
                                   ske->callbacks->context);
 
   silc_buffer_free(payload_buf);
@@ -424,8 +464,8 @@ static void silc_ske_initiator_finish_final(SilcSKE ske,
                                            void *context)
 {
   SilcSKEKEPayload *payload;
-  unsigned char hash[32];
-  uint32 hash_len;
+  unsigned char hash[SILC_HASH_MAXLEN];
+  SilcUInt32 hash_len;
   SilcPublicKey public_key = NULL;
 
   /* If the SKE was freed during the async call then free it really now,
@@ -455,9 +495,10 @@ static void silc_ske_initiator_finish_final(SilcSKE ske,
 
   if (payload->pk_data) {
     /* Decode the public key */
-    if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len, 
+    if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
                                     &public_key)) {
       status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
+      SILC_LOG_ERROR(("Unsupported/malformed public key received"));
       if (ske->callbacks->proto_continue)
        ske->callbacks->proto_continue(ske, ske->callbacks->context);
       return;
@@ -470,25 +511,22 @@ static void silc_ske_initiator_finish_final(SilcSKE ske,
     if (status != SILC_SKE_STATUS_OK)
       goto err;
 
-    ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
-    memcpy(ske->hash, hash, hash_len);
+    ske->hash = silc_memdup(hash, hash_len);
     ske->hash_len = hash_len;
 
     SILC_LOG_DEBUG(("Verifying signature (HASH)"));
 
     /* Verify signature */
     silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
-    if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data, 
+    if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data,
                         payload->sign_len, hash, hash_len) == FALSE) {
-      
-      SILC_LOG_DEBUG(("Signature don't match"));
-      
+      SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
       status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
       goto err;
     }
 
     SILC_LOG_DEBUG(("Signature is Ok"));
-    
+
     silc_pkcs_public_key_free(public_key);
     memset(hash, 'F', hash_len);
   }
@@ -531,9 +569,9 @@ static void silc_ske_initiator_finish_final(SilcSKE ske,
 
 /* Receives Key Exchange Payload from responder consisting responders
    public key, f, and signature. This function verifies the public key,
-   computes the secret shared key and verifies the signature. 
+   computes the secret shared key and verifies the signature.
 
-   The `callback' will be called to indicate that the caller may
+   The `proto_continue' will be called to indicate that the caller may
    continue with the SKE protocol.  The caller must not continue
    before the SKE libary has called that callback.  If this function
    returns an error the callback will not be called.  It is called
@@ -543,7 +581,7 @@ static void silc_ske_initiator_finish_final(SilcSKE ske,
 
    This calls the `verify_key' callback to verify the received public
    key or certificate. If the `verify_key' is provided then the remote
-   must send public key and it is considered to be an error if remote 
+   must send public key and it is considered to be an error if remote
    does not send its public key. If caller is performing a re-key with
    SKE then the `verify_key' is usually not provided when it is not also
    required for the remote to send its public key. */
@@ -582,12 +620,12 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
 
   if (payload->pk_data && ske->callbacks->verify_key) {
     SILC_LOG_DEBUG(("Verifying public key"));
-    
+
     ske->users++;
     (*ske->callbacks->verify_key)(ske, payload->pk_data, payload->pk_len,
-                                payload->pk_type, ske->callbacks->context,
-                                silc_ske_initiator_finish_final, NULL);
-    
+                                 payload->pk_type, ske->callbacks->context,
+                                 silc_ske_initiator_finish_final, NULL);
+
     /* We will continue to the final state after the public key has
        been verified by the caller. */
     return SILC_SKE_STATUS_PENDING;
@@ -617,14 +655,14 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
 /* Starts Key Exchange protocol for responder. Responder receives
    Key Exchange Start Payload from initiator consisting of all the
    security properties the initiator supports. This function decodes
-   the payload and parses the payload further and selects the right 
+   the payload and parses the payload further and selects the right
    security properties. */
 
 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
                                       SilcSocketConnection sock,
-                                      char *version,
+                                      const char *version,
                                       SilcBuffer start_payload,
-                                      bool mutual_auth)
+                                      SilcSKESecurityPropertyFlag flags)
 {
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
   SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
@@ -646,11 +684,24 @@ SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
   ske->start_payload_copy = silc_buffer_copy(start_payload);
 
   /* Force the mutual authentication flag if we want to do it. */
-  if (mutual_auth) {
+  if (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 (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 &&
+      !(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;
+  }
+
   /* Parse and select the security properties from the payload */
   payload = silc_calloc(1, sizeof(*payload));
   status = silc_ske_select_security_properties(ske, version,
@@ -671,8 +722,7 @@ SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
  err:
   if (remote_payload)
     silc_ske_payload_start_free(remote_payload);
-  if (payload)
-    silc_free(payload);
+  silc_free(payload);
 
   if (status == SILC_SKE_STATUS_OK)
     return SILC_SKE_STATUS_ERROR;
@@ -681,11 +731,10 @@ SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
   return status;
 }
 
-/* The selected security properties from the initiator payload is now 
+/* The selected security properties from the initiator payload is now
    encoded into Key Exchange Start Payload and sent to the initiator. */
 
-SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske, 
-                                        SilcSKEStartPayload *start_payload)
+SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske)
 {
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
   SilcBuffer payload_buf;
@@ -697,45 +746,46 @@ SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
   /* Allocate security properties from the payload. These are allocated
      only for this negotiation and will be free'd after KE is over. */
   ske->prop = prop = silc_calloc(1, sizeof(*prop));
-  prop->flags = start_payload->flags;
-  status = silc_ske_group_get_by_name(start_payload->ke_grp_list, &group);
+  prop->flags = ske->start_payload->flags;
+  status = silc_ske_group_get_by_name(ske->start_payload->ke_grp_list, &group);
   if (status != SILC_SKE_STATUS_OK)
     goto err;
 
   prop->group = group;
 
-  if (silc_pkcs_alloc(start_payload->pkcs_alg_list, 
+  if (silc_pkcs_alloc(ske->start_payload->pkcs_alg_list,
                      &prop->pkcs) == FALSE) {
     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
     goto err;
   }
 
-  if (silc_cipher_alloc(start_payload->enc_alg_list, 
+  if (silc_cipher_alloc(ske->start_payload->enc_alg_list,
                        &prop->cipher) == FALSE) {
     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
     goto err;
   }
 
-  if (silc_hash_alloc(start_payload->hash_alg_list,
+  if (silc_hash_alloc(ske->start_payload->hash_alg_list,
                      &prop->hash) == FALSE) {
     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
     goto err;
   }
 
-  if (silc_hmac_alloc(start_payload->hmac_alg_list, NULL,
+  if (silc_hmac_alloc(ske->start_payload->hmac_alg_list, NULL,
                      &prop->hmac) == FALSE) {
     status = SILC_SKE_STATUS_UNKNOWN_HMAC;
     goto err;
   }
 
   /* Encode the payload */
-  status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
+  status = silc_ske_payload_start_encode(ske, ske->start_payload,
+                                        &payload_buf);
   if (status != SILC_SKE_STATUS_OK)
     goto err;
 
   /* Send the packet. */
   if (ske->callbacks->send_packet)
-    (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, 
+    (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
                                   ske->callbacks->context);
 
   silc_buffer_free(payload_buf);
@@ -801,17 +851,18 @@ static void silc_ske_responder_phase2_final(SilcSKE ske,
 
   /* The public key verification was performed only if the Mutual
      Authentication flag is set. */
-  if (ske->start_payload && 
+  if (ske->start_payload &&
       ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
     SilcPublicKey public_key = NULL;
-    unsigned char hash[32];
-    uint32 hash_len;
+    unsigned char hash[SILC_HASH_MAXLEN];
+    SilcUInt32 hash_len;
 
     /* Decode the public key */
-    if (!silc_pkcs_public_key_decode(recv_payload->pk_data, 
-                                    recv_payload->pk_len, 
+    if (!silc_pkcs_public_key_decode(recv_payload->pk_data,
+                                    recv_payload->pk_len,
                                     &public_key)) {
       ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
+      SILC_LOG_ERROR(("Unsupported/malformed public key received"));
       if (ske->callbacks->proto_continue)
        ske->callbacks->proto_continue(ske, ske->callbacks->context);
       return;
@@ -829,22 +880,20 @@ static void silc_ske_responder_phase2_final(SilcSKE ske,
     }
 
     SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
-    
+
     /* Verify signature */
     silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
-    if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data, 
+    if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data,
                         recv_payload->sign_len, hash, hash_len) == FALSE) {
-      
-      SILC_LOG_DEBUG(("Signature don't match"));
-      
+      SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
       ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
       if (ske->callbacks->proto_continue)
        ske->callbacks->proto_continue(ske, ske->callbacks->context);
       return;
     }
-    
+
     SILC_LOG_DEBUG(("Signature is Ok"));
-    
+
     silc_pkcs_public_key_free(public_key);
     memset(hash, 'F', hash_len);
   }
@@ -852,7 +901,7 @@ static void silc_ske_responder_phase2_final(SilcSKE ske,
   /* Create the random number x, 1 < x < q. */
   x = silc_calloc(1, sizeof(*x));
   silc_mp_init(x);
-  status = 
+  status =
     silc_ske_create_rnd(ske, &ske->prop->group->group_order,
                        silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
                        x);
@@ -874,9 +923,9 @@ static void silc_ske_responder_phase2_final(SilcSKE ske,
 
   /* 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, 
+  silc_mp_pow_mod(&send_payload->x, &ske->prop->group->generator, x,
                  &ske->prop->group->group);
-  
+
   /* Call the callback. The caller may now continue with the SKE protocol. */
   ske->status = SILC_SKE_STATUS_OK;
   if (ske->callbacks->proto_continue)
@@ -884,12 +933,12 @@ static void silc_ske_responder_phase2_final(SilcSKE ske,
 }
 
 /* This function receives the Key Exchange Payload from the initiator.
-   This also performs the mutual authentication if required. Then, this 
+   This also performs the mutual authentication if required. Then, this
    function first generated a random number x, such that 1 < x < q
    and computes f = g ^ x mod p. This then puts the result f to a Key
-   Exchange Payload. 
+   Exchange Payload.
 
-   The `callback' will be called to indicate that the caller may
+   The `proto_continue' will be called to indicate that the caller may
    continue with the SKE protocol.  The caller must not continue
    before the SKE libary has called that callback.  If this function
    returns an error the callback will not be called.  It is called
@@ -921,13 +970,13 @@ SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
 
   /* Verify the received public key and verify the signature if we are
      doing mutual authentication. */
-  if (ske->start_payload && 
+  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) {
-      SILC_LOG_DEBUG(("Remote end did not send its public key (or "
+      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;
       return status;
@@ -937,9 +986,9 @@ SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
       SILC_LOG_DEBUG(("Verifying public key"));
 
       ske->users++;
-      (*ske->callbacks->verify_key)(ske, recv_payload->pk_data, 
+      (*ske->callbacks->verify_key)(ske, recv_payload->pk_data,
                                    recv_payload->pk_len,
-                                   recv_payload->pk_type, 
+                                   recv_payload->pk_type,
                                    ske->callbacks->context,
                                    silc_ske_responder_phase2_final, NULL);
 
@@ -968,8 +1017,8 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
   SilcBuffer payload_buf;
   SilcMPInt *KEY;
-  unsigned char hash[32], sign[1024], *pk;
-  uint32 hash_len, sign_len, pk_len;
+  unsigned char hash[SILC_HASH_MAXLEN], sign[2048 + 1], *pk;
+  SilcUInt32 hash_len, sign_len, pk_len;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -978,44 +1027,46 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
   /* 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, 
+  silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x,
                  &ske->prop->group->group);
   ske->KEY = KEY;
 
   if (public_key && private_key) {
     SILC_LOG_DEBUG(("Getting public key"));
-    
+
     /* Get the public key */
     pk = silc_pkcs_public_key_encode(public_key, &pk_len);
     if (!pk) {
-      status = SILC_SKE_STATUS_ERROR;
+      status = SILC_SKE_STATUS_OUT_OF_MEMORY;
       goto err;
     }
     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)
       goto err;
 
-    ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
-    memcpy(ske->hash, hash, hash_len);
+    ske->hash = silc_memdup(hash, hash_len);
     ske->hash_len = hash_len;
-    
+
     SILC_LOG_DEBUG(("Signing HASH value"));
-    
+
     /* Sign the hash value */
-    silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
+    silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
                                   private_key->prv_len);
-    silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
-    ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
-    memcpy(ske->ke2_payload->sign_data, sign, sign_len);
-    memset(sign, 0, sizeof(sign));
+    if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 ||
+       !silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) {
+      status = SILC_SKE_STATUS_SIGNATURE_ERROR;
+      goto err;
+    }
+    ske->ke2_payload->sign_data = silc_memdup(sign, sign_len);
     ske->ke2_payload->sign_len = sign_len;
+    memset(sign, 0, sizeof(sign));
   }
   ske->ke2_payload->pk_type = pk_type;
 
@@ -1027,7 +1078,7 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
 
   /* Send the packet. */
   if (ske->callbacks->send_packet)
-    (*ske->callbacks->send_packet)(ske, payload_buf, 
+    (*ske->callbacks->send_packet)(ske, payload_buf,
                                   SILC_PACKET_KEY_EXCHANGE_2,
                                   ske->callbacks->context);
 
@@ -1054,22 +1105,18 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
 
 SilcSKEStatus silc_ske_end(SilcSKE ske)
 {
-  SilcBuffer packet;
+  SilcBufferStruct packet;
+  unsigned char data[4];
 
   SILC_LOG_DEBUG(("Start"));
 
-  packet = silc_buffer_alloc(4);
-  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-  silc_buffer_format(packet,
-                    SILC_STR_UI_INT((uint32)SILC_SKE_STATUS_OK),
-                    SILC_STR_END);
+  SILC_PUT32_MSB((SilcUInt32)SILC_SKE_STATUS_OK, data);
+  silc_buffer_set(&packet, data, 4);
 
   if (ske->callbacks->send_packet)
-    (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_SUCCESS, 
+    (*ske->callbacks->send_packet)(ske, &packet, SILC_PACKET_SUCCESS,
                                   ske->callbacks->context);
 
-  silc_buffer_free(packet);
-
   return SILC_SKE_STATUS_OK;
 }
 
@@ -1079,22 +1126,21 @@ SilcSKEStatus silc_ske_end(SilcSKE ske)
 
 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status)
 {
-  SilcBuffer packet;
+  SilcBufferStruct packet;
+  unsigned char data[4];
 
   SILC_LOG_DEBUG(("Start"));
 
-  packet = silc_buffer_alloc(4);
-  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-  silc_buffer_format(packet,
-                    SILC_STR_UI_INT((uint32)status),
-                    SILC_STR_END);
+  if (status > SILC_SKE_STATUS_INVALID_COOKIE)
+    status = SILC_SKE_STATUS_BAD_PAYLOAD;
+
+  SILC_PUT32_MSB((SilcUInt32)status, data);
+  silc_buffer_set(&packet, data, 4);
 
   if (ske->callbacks->send_packet)
-    (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_FAILURE, 
+    (*ske->callbacks->send_packet)(ske, &packet, SILC_PACKET_FAILURE,
                                   ske->callbacks->context);
 
-  silc_buffer_free(packet);
-
   return SILC_SKE_STATUS_OK;
 }
 
@@ -1105,10 +1151,10 @@ SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status)
    as, this function is called by the caller of the protocol and not
    by the protocol itself. */
 
-SilcSKEStatus 
+SilcSKEStatus
 silc_ske_assemble_security_properties(SilcSKE ske,
-                                     unsigned char flags,
-                                     char *version,
+                                     SilcSKESecurityPropertyFlag flags,
+                                     const char *version,
                                      SilcSKEStartPayload **return_payload)
 {
   SilcSKEStartPayload *rp;
@@ -1119,12 +1165,12 @@ silc_ske_assemble_security_properties(SilcSKE ske,
   rp = silc_calloc(1, sizeof(*rp));
 
   /* Set flags */
-  rp->flags = 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(ske->rng);
+    rp->cookie[i] = silc_rng_get_byte_fast(ske->rng);
   rp->cookie_len = SILC_SKE_COOKIE_LEN;
 
   /* Put version */
@@ -1153,13 +1199,13 @@ silc_ske_assemble_security_properties(SilcSKE ske,
 
   /* XXX */
   /* Get supported compression algorithms */
-  rp->comp_alg_list = strdup("");
-  rp->comp_alg_len = 0;
+  rp->comp_alg_list = strdup("none");
+  rp->comp_alg_len = strlen("none");
 
-  rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
+  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->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_payload = rp;
@@ -1167,12 +1213,12 @@ silc_ske_assemble_security_properties(SilcSKE ske,
   return SILC_SKE_STATUS_OK;
 }
 
-/* Selects the supported security properties from the remote end's Key 
+/* Selects the supported security properties from the remote end's Key
    Exchange Start Payload. */
 
-SilcSKEStatus 
+SilcSKEStatus
 silc_ske_select_security_properties(SilcSKE ske,
-                                   char *version,
+                                   const char *version,
                                    SilcSKEStartPayload *payload,
                                    SilcSKEStartPayload *remote_payload)
 {
@@ -1187,7 +1233,7 @@ silc_ske_select_security_properties(SilcSKE ske,
 
   /* Check version string */
   if (ske->callbacks->check_version) {
-    status = ske->callbacks->check_version(ske, rp->version, 
+    status = ske->callbacks->check_version(ske, rp->version,
                                           rp->version_len,
                                           ske->callbacks->context);
     if (status != SILC_SKE_STATUS_OK) {
@@ -1196,6 +1242,8 @@ silc_ske_select_security_properties(SilcSKE ske,
     }
   }
 
+  ske->remote_version = silc_memdup(rp->version, rp->version_len);
+
   /* Flags are returned unchanged. */
   payload->flags = rp->flags;
 
@@ -1478,9 +1526,8 @@ silc_ske_select_security_properties(SilcSKE ske,
     payload->hmac_alg_list = strdup(rp->hmac_alg_list);
   }
 
-#if 0
   /* Get supported compression algorithms */
-  cp = rp->hash_alg_list;
+  cp = rp->comp_alg_list;
   if (cp && strchr(cp, ',')) {
     while(cp) {
       char *item;
@@ -1489,15 +1536,23 @@ silc_ske_select_security_properties(SilcSKE ske,
       item = silc_calloc(len + 1, sizeof(char));
       memcpy(item, cp, len);
 
-      SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
+      SILC_LOG_DEBUG(("Proposed Compression `%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;
+#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)
@@ -1508,25 +1563,12 @@ silc_ske_select_security_properties(SilcSKE ske,
       if (item)
        silc_free(item);
     }
-
-    if (!payload->hash_alg_len && !payload->hash_alg_list) {
-      SILC_LOG_DEBUG(("Could not find supported hash alg"));
-      silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
-      silc_free(payload->ke_grp_list);
-      silc_free(payload->pkcs_alg_list);
-      silc_free(payload->enc_alg_list);
-      silc_free(payload);
-      return;
-    }
-  } else {
-
   }
-#endif
 
-  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 + 
+  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;
 
   return SILC_SKE_STATUS_OK;
@@ -1535,32 +1577,37 @@ silc_ske_select_security_properties(SilcSKE ske,
 /* Creates random number such that 1 < rnd < n and at most length
    of len bits. The rnd sent as argument must be initialized. */
 
-SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n, 
-                                 uint32 len, 
-                                 SilcMPInt *rnd)
+static SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n,
+                                        SilcUInt32 len,
+                                        SilcMPInt *rnd)
 {
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
   unsigned char *string;
+  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 */
-  string = silc_rng_get_rn_data(ske->rng, (len / 8));
+  string = silc_rng_get_rn_data(ske->rng, l);
   if (!string)
-    return SILC_SKE_STATUS_ERROR;
+    return SILC_SKE_STATUS_OUT_OF_MEMORY;
 
   /* Decode the string into a MP integer */
-  silc_mp_bin2mp(string, (len / 8), rnd);
+  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', (len / 8));
+  memset(string, 'F', l);
   silc_free(string);
 
   return status;
@@ -1571,15 +1618,15 @@ SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n,
    hash value defined in the protocol. If it is FALSE then this is used
    to create the HASH value defined by the protocol. */
 
-SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
-                                unsigned char *return_hash,
-                                uint32 *return_hash_len,
-                                int initiator)
+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;
-  uint32 e_len, f_len, KEY_len;
+  SilcUInt32 e_len, f_len, KEY_len;
   int ret;
 
   SILC_LOG_DEBUG(("Start"));
@@ -1588,64 +1635,44 @@ SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
     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 */
-    /* XXX Backward support for 0.6.1 */
-    if (ske->backward_version == 1) {
-      SILC_LOG_DEBUG(("*********** Using old KE payload"));
-      buf = silc_buffer_alloc(ske->start_payload_copy->len + 
-                             ske->ke2_payload->pk_len + e_len + 
-                             f_len + KEY_len);
-      silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
-
-      ret = 
+    buf = silc_buffer_alloc_size(ske->start_payload_copy->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_UI_XNSTRING(ske->start_payload_copy->data,
-                                               ske->start_payload_copy->len),
-                          SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data, 
+                          SILC_STR_UI_XNSTRING(ske->start_payload_copy->
+                                               data,
+                                               ske->start_payload_copy->
+                                               len),
+                          SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data,
                                                ske->ke2_payload->pk_len),
                           SILC_STR_UI_XNSTRING(e, e_len),
                           SILC_STR_UI_XNSTRING(f, f_len),
                           SILC_STR_UI_XNSTRING(KEY, KEY_len),
                           SILC_STR_END);
     } else {
-      /* Initiator is not required to send its public key */
-      SILC_LOG_DEBUG(("*********** Using new KE payload"));
-      buf = silc_buffer_alloc(ske->start_payload_copy->len + 
-                             ske->ke2_payload->pk_len + 
-                             ske->ke1_payload->pk_len + 
-                             e_len + f_len + KEY_len);
-      silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
-
-      if (!ske->ke1_payload->pk_data) {
-       ret = 
-         silc_buffer_format(buf,
-                            SILC_STR_UI_XNSTRING(ske->start_payload_copy->
-                                                 data,
-                                                 ske->start_payload_copy->
-                                                 len),
-                            SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data, 
-                                                 ske->ke2_payload->pk_len),
-                            SILC_STR_UI_XNSTRING(e, e_len),
-                            SILC_STR_UI_XNSTRING(f, f_len),
-                            SILC_STR_UI_XNSTRING(KEY, KEY_len),
-                            SILC_STR_END);
-      } else {
-       ret = 
-         silc_buffer_format(buf,
-                            SILC_STR_UI_XNSTRING(ske->start_payload_copy->
-                                                 data,
-                                                 ske->start_payload_copy->
-                                                 len),
-                            SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data, 
-                                                 ske->ke2_payload->pk_len),
-                            SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data, 
-                                                 ske->ke1_payload->pk_len),
-                            SILC_STR_UI_XNSTRING(e, e_len),
-                            SILC_STR_UI_XNSTRING(f, f_len),
-                            SILC_STR_UI_XNSTRING(KEY, KEY_len),
-                            SILC_STR_END);
-      }
+      ret =
+       silc_buffer_format(buf,
+                          SILC_STR_UI_XNSTRING(ske->start_payload_copy->
+                                               data,
+                                               ske->start_payload_copy->
+                                               len),
+                          SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data,
+                                               ske->ke2_payload->pk_len),
+                          SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data,
+                                               ske->ke1_payload->pk_len),
+                          SILC_STR_UI_XNSTRING(e, e_len),
+                          SILC_STR_UI_XNSTRING(f, f_len),
+                          SILC_STR_UI_XNSTRING(KEY, KEY_len),
+                          SILC_STR_END);
     }
     if (ret == -1) {
       silc_buffer_free(buf);
@@ -1667,16 +1694,17 @@ SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
   } else {
     e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
 
-    buf = silc_buffer_alloc(ske->start_payload_copy->len + 
-                           ske->ke1_payload->pk_len + e_len);
-    silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
-    
+    buf = silc_buffer_alloc_size(ske->start_payload_copy->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 = 
+    ret =
       silc_buffer_format(buf,
                         SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
                                              ske->start_payload_copy->len),
-                        SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data, 
+                        SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data,
                                              ske->ke1_payload->pk_len),
                         SILC_STR_UI_XNSTRING(e, e_len),
                         SILC_STR_END);
@@ -1693,7 +1721,7 @@ SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
 
   /* Make the hash */
   silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
-  *return_hash_len = ske->prop->hash->hash->hash_len;
+  *return_hash_len = silc_hash_len(ske->prop->hash);
 
   if (initiator == FALSE) {
     SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
@@ -1706,30 +1734,31 @@ SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
   return status;
 }
 
-/* Processes the provided key material `data' as the SILC protocol 
+/* Processes the provided key material `data' as the SILC protocol
    specification defines. */
 
-SilcSKEStatus 
+SilcSKEStatus
 silc_ske_process_key_material_data(unsigned char *data,
-                                  uint32 data_len,
-                                  uint32 req_iv_len,
-                                  uint32 req_enc_key_len,
-                                  uint32 req_hmac_key_len,
+                                  SilcUInt32 data_len,
+                                  SilcUInt32 req_iv_len,
+                                  SilcUInt32 req_enc_key_len,
+                                  SilcUInt32 req_hmac_key_len,
                                   SilcHash hash,
                                   SilcSKEKeyMaterial *key)
 {
   SilcBuffer buf;
-  unsigned char hashd[32];
-  uint32 hash_len = req_hmac_key_len;
-  uint32 enc_key_len = req_enc_key_len / 8;
+  unsigned char hashd[SILC_HASH_MAXLEN];
+  SilcUInt32 hash_len = req_hmac_key_len;
+  SilcUInt32 enc_key_len = req_enc_key_len / 8;
 
   SILC_LOG_DEBUG(("Start"));
 
   if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
     return SILC_SKE_STATUS_ERROR;
 
-  buf = silc_buffer_alloc(1 + data_len);
-  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+  buf = silc_buffer_alloc_size(1 + data_len);
+  if (!buf)
+    return SILC_SKE_STATUS_OUT_OF_MEMORY;
   silc_buffer_format(buf,
                     SILC_STR_UI_CHAR(0),
                     SILC_STR_UI_XNSTRING(data, data_len),
@@ -1754,20 +1783,22 @@ silc_ske_process_key_material_data(unsigned char *data,
   buf->data[0] = 2;
   if (enc_key_len > hash_len) {
     SilcBuffer dist;
-    unsigned char k1[32], k2[32], k3[32];
+    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 SILC_SKE_STATUS_ERROR;
-    
+
     /* Take first round */
     memset(k1, 0, sizeof(k1));
     silc_hash_make(hash, buf->data, buf->len, k1);
-    
+
     /* Take second round */
-    dist = silc_buffer_alloc(data_len + hash_len);
-    silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
+    dist = silc_buffer_alloc_size(data_len + hash_len);
+    if (!dist)
+      return SILC_SKE_STATUS_OUT_OF_MEMORY;
     silc_buffer_format(dist,
                       SILC_STR_UI_XNSTRING(data, data_len),
                       SILC_STR_UI_XNSTRING(k1, hash_len),
@@ -1801,6 +1832,7 @@ silc_ske_process_key_material_data(unsigned char *data,
     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 */
@@ -1814,27 +1846,29 @@ silc_ske_process_key_material_data(unsigned char *data,
   buf->data[0] = 3;
   if (enc_key_len > hash_len) {
     SilcBuffer dist;
-    unsigned char k1[32], k2[32], k3[32];
+    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 SILC_SKE_STATUS_ERROR;
-    
+
     /* Take first round */
     memset(k1, 0, sizeof(k1));
     silc_hash_make(hash, buf->data, buf->len, k1);
-    
+
     /* Take second round */
-    dist = silc_buffer_alloc(data_len + hash_len);
-    silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
+    dist = silc_buffer_alloc_size(data_len + hash_len);
+    if (!dist)
+      return SILC_SKE_STATUS_OUT_OF_MEMORY;
     silc_buffer_format(dist,
                       SILC_STR_UI_XNSTRING(data, data_len),
                       SILC_STR_UI_XNSTRING(k1, hash_len),
                       SILC_STR_END);
     memset(k2, 0, sizeof(k2));
     silc_hash_make(hash, dist->data, dist->len, k2);
-    
+
     /* Take third round */
     dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
     silc_buffer_pull_tail(dist, hash_len);
@@ -1861,6 +1895,7 @@ silc_ske_process_key_material_data(unsigned char *data,
     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 */
@@ -1885,6 +1920,7 @@ silc_ske_process_key_material_data(unsigned char *data,
   key->hmac_key_len = req_hmac_key_len;
   memset(hashd, 0, sizeof(hashd));
 
+  silc_buffer_clear(buf);
   silc_buffer_free(buf);
 
   return SILC_SKE_STATUS_OK;
@@ -1893,22 +1929,23 @@ silc_ske_process_key_material_data(unsigned char *data,
 /* Processes negotiated key material as protocol specifies. This returns
    the actual keys to be used in the SILC. */
 
-SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, 
-                                           uint32 req_iv_len,
-                                           uint32 req_enc_key_len,
-                                           uint32 req_hmac_key_len,
+SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
+                                           SilcUInt32 req_iv_len,
+                                           SilcUInt32 req_enc_key_len,
+                                           SilcUInt32 req_hmac_key_len,
                                            SilcSKEKeyMaterial *key)
 {
   SilcSKEStatus status;
   SilcBuffer buf;
   unsigned char *tmpbuf;
-  uint32 klen;
+  SilcUInt32 klen;
 
   /* Encode KEY to binary data */
   tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
 
-  buf = silc_buffer_alloc(klen + ske->hash_len);
-  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+  buf = silc_buffer_alloc_size(klen + ske->hash_len);
+  if (!buf)
+    return SILC_SKE_STATUS_OUT_OF_MEMORY;
   silc_buffer_format(buf,
                     SILC_STR_UI_XNSTRING(tmpbuf, klen),
                     SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
@@ -1917,11 +1954,12 @@ SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
   /* Process the key material */
   status = silc_ske_process_key_material_data(buf->data, buf->len,
                                              req_iv_len, req_enc_key_len,
-                                             req_hmac_key_len, 
+                                             req_hmac_key_len,
                                              ske->prop->hash, key);
 
   memset(tmpbuf, 0, klen);
   silc_free(tmpbuf);
+  silc_buffer_clear(buf);
   silc_buffer_free(buf);
 
   return status;
@@ -1957,7 +1995,7 @@ void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
   silc_free(key);
 }
 
-const char *silc_ske_status_string[] = 
+const char *silc_ske_status_string[] =
 {
   /* Official */
   "Ok",
@@ -1979,7 +2017,8 @@ const char *silc_ske_status_string[] =
   "Key exchange protocol is not active",
   "Bad reserved field in packet",
   "Bad payload length in packet",
-  "Incorrect hash",
+  "Error computing signature",
+  "System out of memory",
 
   NULL
 };
@@ -1997,3 +2036,20 @@ const char *silc_ske_map_status(SilcSKEStatus status)
 
   return "";
 }
+
+/* Parses remote host's version string. */
+
+bool 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);
+}