Removed protocol version check during connecting (unnecessary).
[silc.git] / lib / silcske / silcske.c
index f554e3b0f6becccf430e63864f85b59d43d11df2..780a9d2faf21fe34aa4ab94251839cceeaee2796 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2000 - 2006 Pekka Riikonen
+  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
@@ -55,6 +55,7 @@ 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_TASK_CALLBACK(silc_ske_packet_send_retry);
 
 SilcSKEKeyMaterial
 silc_ske_process_key_material(SilcSKE ske,
@@ -81,7 +82,8 @@ static SilcBool silc_ske_packet_receive(SilcPacketEngine engine,
   /* Clear retransmission */
   ske->retry_timer = SILC_SKE_RETRY_MIN;
   ske->retry_count = 0;
-  silc_schedule_task_del_by_context(ske->schedule, ske);
+  silc_schedule_task_del_by_callback(ske->schedule,
+                                    silc_ske_packet_send_retry);
 
   /* Signal for new packet */
   ske->packet = packet;
@@ -174,22 +176,13 @@ static void silc_ske_skr_callback(SilcSKR repository,
 
 static SilcSKEStatus silc_ske_check_version(SilcSKE ske)
 {
-  SilcUInt32 l_protocol_version = 0, r_protocol_version = 0;
   SilcUInt32 r_software_version = 0;
 
   if (!ske->remote_version || !ske->version)
     return SILC_SKE_STATUS_BAD_VERSION;
 
-  if (!silc_parse_version_string(ske->remote_version, &r_protocol_version,
-                                NULL, &r_software_version, NULL, NULL))
-    return SILC_SKE_STATUS_BAD_VERSION;
-
-  if (!silc_parse_version_string(ske->version, &l_protocol_version,
-                                NULL, NULL, NULL, NULL))
-    return SILC_SKE_STATUS_BAD_VERSION;
-
-  /* If remote is too new, don't connect */
-  if (l_protocol_version < r_protocol_version)
+  if (!silc_parse_version_string(ske->remote_version, NULL, NULL,
+                                &r_software_version, NULL, NULL))
     return SILC_SKE_STATUS_BAD_VERSION;
 
   /* Backwards compatibility checks */
@@ -988,6 +981,24 @@ static void silc_ske_finished(SilcFSM fsm, void *fsm_context,
     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);
+}
+
 /******************************* Protocol API *******************************/
 
 /* Allocates new SKE object. */
@@ -1034,6 +1045,17 @@ void silc_ske_free(SilcSKE ske)
 
   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;
   }
 
@@ -1148,10 +1170,12 @@ SILC_FSM_STATE(silc_ske_st_initiator_start)
     return SILC_FSM_CONTINUE;
   }
 
-  /* XXX timeout */
+  /* 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 reponder proposal"));
+  SILC_LOG_DEBUG(("Waiting for responder proposal"));
   silc_fsm_next(fsm, silc_ske_st_initiator_phase1);
   return SILC_FSM_WAIT;
 }
@@ -1386,7 +1410,7 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase2)
 
     /* Sign the hash value */
     if (!silc_pkcs_sign(ske->private_key, hash, hash_len, sign,
-                       sizeof(sign) - 1, &sign_len, NULL)) {
+                       sizeof(sign) - 1, &sign_len, FALSE, ske->prop->hash)) {
       /** Error computing signature */
       silc_mp_uninit(x);
       silc_free(x);
@@ -1790,6 +1814,7 @@ silc_ske_initiator(SilcSKE ske,
       return NULL;
   }
 
+  ske->timeout = params->timeout_secs ? params->timeout_secs : 30;
   ske->start_payload = start_payload;
   ske->version = params->version;
   ske->running = TRUE;
@@ -1824,8 +1849,9 @@ SILC_FSM_STATE(silc_ske_st_responder_start)
     return SILC_FSM_CONTINUE;
   }
 
-  /* Start timeout */
-  /* XXX */
+  /* 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);
@@ -2185,7 +2211,7 @@ SILC_FSM_STATE(silc_ske_st_responder_phase5)
 
     /* Sign the hash value */
     if (!silc_pkcs_sign(ske->private_key, hash, hash_len, sign,
-                       sizeof(sign) - 1, &sign_len, NULL)) {
+                       sizeof(sign) - 1, &sign_len, FALSE, ske->prop->hash)) {
       /** Error computing signature */
       status = SILC_SKE_STATUS_SIGNATURE_ERROR;
       silc_fsm_next(fsm, silc_ske_st_responder_error);
@@ -2348,6 +2374,7 @@ silc_ske_responder(SilcSKE ske,
 
   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);
@@ -2386,7 +2413,9 @@ SILC_FSM_STATE(silc_ske_st_rekey_initiator_start)
     return SILC_FSM_CONTINUE;
   }
 
-  /* XXX timeout */
+  /* 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) {
@@ -2954,6 +2983,8 @@ SilcBool silc_ske_set_keys(SilcSKE ske,
                           SilcHmac *ret_hmac_receive,
                           SilcHash *ret_hash)
 {
+  unsigned char iv[32];
+
   /* Allocate ciphers to be used in the communication */
   if (ret_send_key) {
     if (!silc_cipher_alloc((char *)silc_cipher_get_name(prop->cipher),
@@ -2979,16 +3010,31 @@ SilcBool silc_ske_set_keys(SilcSKE ske,
   }
 
   /* 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);
-      silc_cipher_set_iv(*ret_send_key, keymat->receive_iv);
+
+      if (silc_cipher_get_mode(*ret_send_key) == SILC_CIPHER_MODE_CTR) {
+        memcpy(iv, ske->hash, 4);
+        memcpy(iv + 4, keymat->receive_iv, 4);
+        silc_cipher_set_iv(*ret_send_key, iv);
+      } else {
+       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);
-      silc_cipher_set_iv(*ret_receive_key, keymat->send_iv);
+
+      if (silc_cipher_get_mode(*ret_receive_key) == SILC_CIPHER_MODE_CTR) {
+        memcpy(iv, ske->hash, 4);
+        memcpy(iv + 4, keymat->send_iv, 4);
+        silc_cipher_set_iv(*ret_receive_key, iv);
+      } else {
+       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,
@@ -3000,12 +3046,26 @@ SilcBool silc_ske_set_keys(SilcSKE ske,
     if (ret_send_key) {
       silc_cipher_set_key(*ret_send_key, keymat->send_enc_key,
                          keymat->enc_key_len, TRUE);
-      silc_cipher_set_iv(*ret_send_key, keymat->send_iv);
+
+      if (silc_cipher_get_mode(*ret_send_key) == SILC_CIPHER_MODE_CTR) {
+        memcpy(iv, ske->hash, 4);
+        memcpy(iv + 4, keymat->send_iv, 4);
+       silc_cipher_set_iv(*ret_send_key, iv);
+      } else {
+       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);
-      silc_cipher_set_iv(*ret_receive_key, keymat->receive_iv);
+
+      if (silc_cipher_get_mode(*ret_receive_key) == SILC_CIPHER_MODE_CTR) {
+        memcpy(iv, ske->hash, 4);
+        memcpy(iv + 4, keymat->receive_iv, 4);
+       silc_cipher_set_iv(*ret_receive_key, iv);
+      } else {
+       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,
@@ -3046,6 +3106,7 @@ const char *silc_ske_status_string[] =
   "Bad payload length in packet",
   "Error computing signature",
   "System out of memory",
+  "Key exchange timeout",
 
   NULL
 };