Added silc_ske_get_key_material.
[silc.git] / lib / silcske / silcske.c
index a8cab636958c8ee017cb5e1680ba871229ff6e41..dcd8aad49034b8f3c55a99cfbd7957dd34842005 100644 (file)
@@ -34,13 +34,6 @@ struct SilcSKECallbacksStruct {
 
 /************************ Static utility functions **************************/
 
-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);
 SilcSKEKeyMaterial
 silc_ske_process_key_material(SilcSKE ske,
                              SilcUInt32 req_iv_len,
@@ -394,8 +387,7 @@ silc_ske_select_security_properties(SilcSKE ske,
   }
 
   /* Save selected cipher to security properties */
-  if (silc_cipher_alloc(payload->enc_alg_list,
-                       &(*prop)->cipher) == FALSE) {
+  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);
@@ -453,8 +445,7 @@ silc_ske_select_security_properties(SilcSKE ske,
   }
 
   /* Save selected hash algorithm to security properties */
-  if (silc_hash_alloc(ske->start_payload->hash_alg_list,
-                     &(*prop)->hash) == FALSE) {
+  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);
@@ -514,8 +505,7 @@ silc_ske_select_security_properties(SilcSKE ske,
   }
 
   /* Save selected HMACc to security properties */
-  if (silc_hmac_alloc(ske->start_payload->hmac_alg_list, NULL,
-                     &(*prop)->hmac) == FALSE) {
+  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);
@@ -819,9 +809,14 @@ SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule,
 
   SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
 
-  if (!rng || !schedule || !public_key)
+  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;
@@ -842,46 +837,52 @@ void silc_ske_free(SilcSKE ske)
 {
   SILC_LOG_DEBUG(("Freeing Key Exchange object"));
 
-  if (ske) {
-    /* 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);
-      silc_free(ske->prop);
-    }
-    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->hash);
-    silc_free(ske->callbacks);
+  if (!ske)
+    return;
 
-    memset(ske, 'F', sizeof(*ske));
-    silc_free(ske);
+  if (ske->running) {
+    ske->freed = TRUE;
+    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);
+      silc_free(ske->prop);
+  }
+  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->hash);
+  silc_free(ske->callbacks);
+
+  memset(ske, 'F', sizeof(*ske));
+  silc_free(ske);
 }
 
 /* Return user context */
@@ -957,6 +958,7 @@ SILC_FSM_STATE(silc_ske_st_initiator_start)
                        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;
@@ -978,7 +980,7 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase1)
   SilcSKEStatus status;
   SilcSKEStartPayload payload;
   SilcSKESecurityProperties prop;
-  SilcSKEDiffieHellmanGroup group;
+  SilcSKEDiffieHellmanGroup group = NULL;
   SilcBuffer packet_buf = &ske->packet->buffer;
   SilcUInt16 remote_port = 0;
   SilcID id;
@@ -1090,9 +1092,8 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase1)
  err:
   if (payload)
     silc_ske_payload_start_free(payload);
-
-  silc_ske_group_free(group);
-
+  if (group)
+    silc_ske_group_free(group);
   if (prop->cipher)
     silc_cipher_free(prop->cipher);
   if (prop->hash)
@@ -1241,6 +1242,7 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase2)
                        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;
@@ -1328,6 +1330,7 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase3)
       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, find,
@@ -1432,6 +1435,7 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase4)
   SILC_PUT32_MSB((SilcUInt32)SILC_SKE_STATUS_OK, hash);
   if (!silc_packet_send(ske->stream, SILC_PACKET_SUCCESS, 0, hash, 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;
@@ -1491,9 +1495,10 @@ SILC_FSM_STATE(silc_ske_st_initiator_end)
   /* Call the completion callback */
   if (ske->callbacks->completed)
     ske->callbacks->completed(ske, ske->status, ske->prop, ske->keymat,
-                             ske->rekey, ske->user_data);
+                             ske->rekey, ske->callbacks->context);
 
   silc_packet_free(ske->packet);
+  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
 
   return SILC_FSM_FINISH;
 }
@@ -1510,6 +1515,7 @@ SILC_FSM_STATE(silc_ske_st_initiator_aborted)
   /* Send FAILURE packet */
   SILC_PUT32_MSB(SILC_SKE_STATUS_ERROR, data);
   silc_packet_send(ske->stream, SILC_PACKET_FAILURE, 0, data, 4);
+  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
 
   return SILC_FSM_FINISH;
 }
@@ -1535,7 +1541,10 @@ SILC_FSM_STATE(silc_ske_st_initiator_error)
 
   /* Call the completion callback */
   if (ske->callbacks->completed)
-    ske->callbacks->completed(ske, ske->status, NULL, NULL, NULL, NULL);
+    ske->callbacks->completed(ske, ske->status, NULL, NULL, NULL,
+                             ske->callbacks->context);
+
+  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
 
   return SILC_FSM_FINISH;
 }
@@ -1551,7 +1560,10 @@ SILC_FSM_STATE(silc_ske_st_initiator_failure)
 
   /* Call the completion callback */
   if (ske->callbacks->completed)
-    ske->callbacks->completed(ske, ske->status, NULL, NULL, NULL, NULL);
+    ske->callbacks->completed(ske, ske->status, NULL, NULL, NULL,
+                             ske->callbacks->context);
+
+  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
 
   return SILC_FSM_FINISH;
 }
@@ -1562,7 +1574,10 @@ static void silc_ske_initiator_finished(SilcFSM fsm, void *fsm_context,
                                        void *destructor_context)
 {
   SilcSKE ske = fsm_context;
-  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
+
+  ske->running = FALSE;
+  if (ske->freed)
+    silc_ske_free(ske);
 }
 
 /* Starts the protocol as initiator */
@@ -1599,6 +1614,7 @@ silc_ske_initiator(SilcSKE ske,
 
   ske->start_payload = start_payload;
   ske->version = params->version;
+  ske->running = TRUE;
 
   /* Link to packet stream to get key exchange packets */
   ske->stream = stream;
@@ -1849,6 +1865,7 @@ SILC_FSM_STATE(silc_ske_st_responder_phase2)
        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, find,
@@ -2040,6 +2057,7 @@ SILC_FSM_STATE(silc_ske_st_responder_phase5)
   /* Send the packet. */
   if (!silc_packet_send(ske->stream, 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;
@@ -2157,7 +2175,6 @@ SILC_FSM_STATE(silc_ske_st_responder_error)
     ske->status = SILC_SKE_STATUS_BAD_PAYLOAD;
   SILC_PUT32_MSB(ske->status, tmp);
   silc_packet_send(ske->stream, SILC_PACKET_FAILURE, 0, tmp, 4);
-
   silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
 
   return SILC_FSM_FINISH;
@@ -2167,7 +2184,11 @@ SILC_FSM_STATE(silc_ske_st_responder_error)
 static void silc_ske_responder_finished(SilcFSM fsm, void *fsm_context,
                                        void *destructor_context)
 {
+  SilcSKE ske = fsm_context;
 
+  ske->running = FALSE;
+  if (ske->freed)
+    silc_ske_free(ske);
 }
 
 /* Starts the protocol as responder. */
@@ -2197,6 +2218,7 @@ silc_ske_responder(SilcSKE ske,
   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;
@@ -2619,12 +2641,6 @@ SilcBool silc_ske_set_keys(SilcSKE ske,
       return FALSE;
   }
 
-  SILC_LOG_INFO(("Security properties: %s %s %s %s",
-                ret_send_key ? silc_cipher_get_name(*ret_send_key) : "??",
-                ret_hmac_send ? silc_hmac_get_name(*ret_hmac_send) : "??",
-                ret_hash ? silc_hash_get_name(*ret_hash) : "??",
-                ske->prop->flags & SILC_SKE_SP_FLAG_PFS ? "PFS" : ""));
-
   return TRUE;
 }
 
@@ -2691,3 +2707,10 @@ 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;
+}