Fixed counter mode encryption/decryption.
[silc.git] / lib / silcske / silcske.c
index a6ec27545cee316205ab21ca9aa710001fc6bff3..a726174339bde711d2108432905668a7fbc5fb37 100644 (file)
@@ -110,8 +110,10 @@ static SilcBool silc_ske_packet_receive(SilcPacketEngine engine,
       silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
   }
 
-  /* Handle rekey synchronously */
-  if (ske->rekeying)
+  /* 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);
@@ -176,22 +178,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 */
@@ -966,15 +959,11 @@ static SilcBool silc_ske_packet_send(SilcSKE ske,
   return ret;
 }
 
-/* SKE FSM destructor.  We call completion callback here.  All SKE
-   machines go here and call the completion.  Completion must not be called
-   from any other place. */
+/* Calls completion callback.  Completion is called always in this function
+   and must not be called anywhere else. */
 
-static void silc_ske_finished(SilcFSM fsm, void *fsm_context,
-                             void *destructor_context)
+static void silc_ske_completion(SilcSKE ske)
 {
-  SilcSKE ske = fsm_context;
-
   /* Call the completion callback */
   if (!ske->freed && !ske->aborted && ske->callbacks->completed) {
     if (ske->status != SILC_SKE_STATUS_OK)
@@ -984,7 +973,14 @@ static void silc_ske_finished(SilcFSM fsm, void *fsm_context,
       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);
@@ -1089,6 +1085,8 @@ void silc_ske_free(SilcSKE ske)
       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)
@@ -1722,6 +1720,9 @@ SILC_FSM_STATE(silc_ske_st_initiator_end)
   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;
 }
 
@@ -1741,6 +1742,9 @@ SILC_FSM_STATE(silc_ske_st_initiator_aborted)
   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;
 }
 
@@ -1766,6 +1770,9 @@ SILC_FSM_STATE(silc_ske_st_initiator_error)
   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;
 }
 
@@ -1789,16 +1796,18 @@ SILC_FSM_STATE(silc_ske_st_initiator_failure)
   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)
+SilcAsyncOperation silc_ske_initiator(SilcSKE ske,
+                                     SilcPacketStream stream,
+                                     SilcSKEParams params,
+                                     SilcSKEStartPayload start_payload)
 {
   SILC_LOG_DEBUG(("Start SKE as initiator"));
 
@@ -2297,6 +2306,9 @@ SILC_FSM_STATE(silc_ske_st_responder_end)
   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;
 }
 
@@ -2316,6 +2328,9 @@ SILC_FSM_STATE(silc_ske_st_responder_aborted)
   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;
 }
 
@@ -2338,6 +2353,9 @@ SILC_FSM_STATE(silc_ske_st_responder_failure)
   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;
 }
 
@@ -2360,15 +2378,17 @@ SILC_FSM_STATE(silc_ske_st_responder_error)
   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)
+SilcAsyncOperation silc_ske_responder(SilcSKE ske,
+                                     SilcPacketStream stream,
+                                     SilcSKEParams params)
 {
   SILC_LOG_DEBUG(("Start SKE as responder"));
 
@@ -2605,6 +2625,9 @@ SILC_FSM_STATE(silc_ske_st_rekey_initiator_end)
   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;
 }
 
@@ -2993,6 +3016,7 @@ SilcBool silc_ske_set_keys(SilcSKE ske,
                           SilcHash *ret_hash)
 {
   unsigned char iv[32];
+  SilcBool iv_included = (prop->flags & SILC_SKE_SP_FLAG_IV_INCLUDED);
 
   /* Allocate ciphers to be used in the communication */
   if (ret_send_key) {
@@ -3027,7 +3051,7 @@ SilcBool silc_ske_set_keys(SilcSKE ske,
 
       if (silc_cipher_get_mode(*ret_send_key) == SILC_CIPHER_MODE_CTR) {
         memcpy(iv, ske->hash, 4);
-        memcpy(iv + 4, keymat->receive_iv, 4);
+        memcpy(iv + 4, keymat->receive_iv, iv_included ? 4 : 8);
         silc_cipher_set_iv(*ret_send_key, iv);
       } else {
        silc_cipher_set_iv(*ret_send_key, keymat->receive_iv);
@@ -3039,7 +3063,7 @@ SilcBool silc_ske_set_keys(SilcSKE ske,
 
       if (silc_cipher_get_mode(*ret_receive_key) == SILC_CIPHER_MODE_CTR) {
         memcpy(iv, ske->hash, 4);
-        memcpy(iv + 4, keymat->send_iv, 4);
+        memcpy(iv + 4, keymat->send_iv, iv_included ? 4 : 8);
         silc_cipher_set_iv(*ret_receive_key, iv);
       } else {
        silc_cipher_set_iv(*ret_receive_key, keymat->send_iv);
@@ -3058,7 +3082,7 @@ SilcBool silc_ske_set_keys(SilcSKE ske,
 
       if (silc_cipher_get_mode(*ret_send_key) == SILC_CIPHER_MODE_CTR) {
         memcpy(iv, ske->hash, 4);
-        memcpy(iv + 4, keymat->send_iv, 4);
+        memcpy(iv + 4, keymat->send_iv, iv_included ? 4 : 8);
        silc_cipher_set_iv(*ret_send_key, iv);
       } else {
        silc_cipher_set_iv(*ret_send_key, keymat->send_iv);
@@ -3070,7 +3094,7 @@ SilcBool silc_ske_set_keys(SilcSKE ske,
 
       if (silc_cipher_get_mode(*ret_receive_key) == SILC_CIPHER_MODE_CTR) {
         memcpy(iv, ske->hash, 4);
-        memcpy(iv + 4, keymat->receive_iv, 4);
+        memcpy(iv + 4, keymat->receive_iv, iv_included ? 4 : 8);
        silc_cipher_set_iv(*ret_receive_key, iv);
       } else {
        silc_cipher_set_iv(*ret_receive_key, keymat->receive_iv);