updates
[silc.git] / lib / silcske / silcske.c
index 0d0e4ff314709ee0980b53e6c7b908be5b36b08f..6cf7c952b887eaa4054b4b44210b09d8527a904e 100644 (file)
@@ -2,7 +2,7 @@
 
   silcske.c
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
   Copyright (C) 2000 - 2001 Pekka Riikonen
 
 /* $Id$ */
 
 #include "silcincludes.h"
-#include "payload_internal.h"
+#include "silcske.h"
 #include "groups_internal.h"
 
-/* Structure to hold all SKE callbacks-> */
+/* Structure to hold all SKE callbacks. */
 struct SilcSKECallbacksStruct {
   SilcSKESendPacketCb send_packet;
   SilcSKECb payload_receive;
@@ -86,8 +86,6 @@ void silc_ske_free(SilcSKE ske)
     }
     if (ske->start_payload_copy)
       silc_buffer_free(ske->start_payload_copy);
-    if (ske->pk)
-      silc_free(ske->pk);
     if (ske->x) {
       silc_mp_uninit(ske->x);
       silc_free(ske->x);
@@ -161,7 +159,8 @@ void silc_ske_set_callbacks(SilcSKE ske,
    configured security properties. This payload is then sent to the
    remote end for further processing. This payload must be sent as
    argument to the function, however, it must not be encoded
-   already, it is done by this function.
+   already, it is done by this function. The caller must not free
+   the `start_payload' since the SKE library will save it.
 
    The packet sending is done by calling a callback function. Caller
    must provide a routine to send the packet. */
@@ -186,11 +185,12 @@ SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
   /* 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->context);
+                                  ske->callbacks->context);
 
   silc_buffer_free(payload_buf);
 
@@ -216,9 +216,22 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
   status = silc_ske_payload_start_decode(ske, start_payload, &payload);
   if (status != SILC_SKE_STATUS_OK) {
     ske->status = status;
+    silc_ske_payload_start_free(ske->start_payload);
+    return status;
+  }
+
+  /* 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"));
+    ske->status = SILC_SKE_STATUS_INVALID_COOKIE;
+    silc_ske_payload_start_free(ske->start_payload);
     return status;
   }
 
+  /* Free our KE Start Payload context, we don't need it anymore. */
+  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 
      exchange. The same data is returned to upper levels by calling
@@ -251,6 +264,7 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
     goto err;
   }
 
+  /* Save remote's KE Start Payload */
   ske->start_payload = payload;
 
   /* Return the received payload by calling the callback function. */
@@ -293,7 +307,7 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
 {
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
   SilcBuffer payload_buf;
-  SilcMPInt *x, e;
+  SilcMPInt *x;
   SilcSKEKEPayload *payload;
   uint32 pk_len;
 
@@ -303,7 +317,7 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
   x = silc_calloc(1, sizeof(*x));
   silc_mp_init(x);
   status = 
-    silc_ske_create_rnd(ske, ske->prop->group->group_order,
+    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) {
@@ -313,19 +327,17 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
     return status;
   }
 
-  SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
-
-  /* Do the Diffie Hellman computation, e = g ^ x mod p */
-  silc_mp_init(&e);
-  silc_mp_pow_mod(&e, &ske->prop->group->generator, x, 
-                 &ske->prop->group->group);
-
   /* Encode the result to Key Exchange Payload. */
 
   payload = silc_calloc(1, sizeof(*payload));
   ske->ke1_payload = payload;
 
-  payload->x = e;
+  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);
 
   /* Get public key */
   if (public_key) {
@@ -333,7 +345,7 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
     if (!payload->pk_data) {
       silc_mp_uninit(x);
       silc_free(x);
-      silc_mp_uninit(&e);
+      silc_mp_uninit(&payload->x);
       silc_free(payload);
       ske->status = SILC_SKE_STATUS_OK;
       return ske->status;
@@ -370,7 +382,7 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
   if (status != SILC_SKE_STATUS_OK) {
     silc_mp_uninit(x);
     silc_free(x);
-    silc_mp_uninit(&e);
+    silc_mp_uninit(&payload->x);
     silc_free(payload->pk_data);
     silc_free(payload);
     ske->status = status;
@@ -382,8 +394,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->context);
+                                  SILC_PACKET_KEY_EXCHANGE_1, 
+                                  ske->callbacks->context);
 
   silc_buffer_free(payload_buf);
 
@@ -407,18 +419,17 @@ static void silc_ske_initiator_finish_final(SilcSKE ske,
   if (ske->status == SILC_SKE_STATUS_FREED) {
     silc_ske_free(ske);
     return;
-  } else {
-    ske->users--;
   }
 
-  payload = ske->ke2_payload;
-
   /* If the caller returns PENDING status SKE library will assume that
      the caller will re-call this callback when it is not anymore in
      PENDING status. */
   if (status == SILC_SKE_STATUS_PENDING)
     return;
 
+  ske->users--;
+  payload = ske->ke2_payload;
+
   /* If the status is an error then the public key that was verified
      by the caller is not authentic. */
   if (status != SILC_SKE_STATUS_OK) {
@@ -744,25 +755,24 @@ static void silc_ske_responder_phase2_final(SilcSKE ske,
                                            void *context)
 {
   SilcSKEKEPayload *recv_payload, *send_payload;
-  SilcMPInt *x, f;
+  SilcMPInt *x;
 
   /* If the SKE was freed during the async call then free it really now,
      otherwise just decrement the reference counter. */
   if (ske->status == SILC_SKE_STATUS_FREED) {
     silc_ske_free(ske);
     return;
-  } else {
-    ske->users--;
   }
 
-  recv_payload = ske->ke1_payload;
-
   /* If the caller returns PENDING status SKE library will assume that
      the caller will re-call this callback when it is not anymore in
      PENDING status. */
   if (status == SILC_SKE_STATUS_PENDING)
     return;
 
+  ske->users--;
+  recv_payload = ske->ke1_payload;
+
   /* If the status is an error then the public key that was verified
      by the caller is not authentic. */
   if (status != SILC_SKE_STATUS_OK) {
@@ -826,7 +836,7 @@ static void silc_ske_responder_phase2_final(SilcSKE ske,
   x = silc_calloc(1, sizeof(*x));
   silc_mp_init(x);
   status = 
-    silc_ske_create_rnd(ske, ske->prop->group->group_order,
+    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) {
@@ -838,19 +848,18 @@ static void silc_ske_responder_phase2_final(SilcSKE ske,
     return;
   }
 
-  SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
-
-  /* Do the Diffie Hellman computation, f = g ^ x mod p */
-  silc_mp_init(&f);
-  silc_mp_pow_mod(&f, &ske->prop->group->generator, x, 
-                 &ske->prop->group->group);
-  
   /* Save the results for later processing */
   send_payload = silc_calloc(1, sizeof(*send_payload));
-  send_payload->x = f;
   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);
+  
   /* Call the callback. The caller may now continue with the SKE protocol. */
   ske->status = SILC_SKE_STATUS_OK;
   if (ske->callbacks->proto_continue)
@@ -912,10 +921,10 @@ SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
 
       ske->users++;
       (*ske->callbacks->verify_key)(ske, recv_payload->pk_data, 
-                                  recv_payload->pk_len,
-                                  recv_payload->pk_type, 
-                                  ske->callbacks->context,
-                                  silc_ske_responder_phase2_final, NULL);
+                                   recv_payload->pk_len,
+                                   recv_payload->pk_type, 
+                                   ske->callbacks->context,
+                                   silc_ske_responder_phase2_final, NULL);
 
       /* We will continue to the final state after the public key has
         been verified by the caller. */
@@ -1000,8 +1009,9 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
 
   /* Send the packet. */
   if (ske->callbacks->send_packet)
-    (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2,
-                                 ske->callbacks->context);
+    (*ske->callbacks->send_packet)(ske, payload_buf, 
+                                  SILC_PACKET_KEY_EXCHANGE_2,
+                                  ske->callbacks->context);
 
   silc_buffer_free(payload_buf);
 
@@ -1038,7 +1048,7 @@ SilcSKEStatus silc_ske_end(SilcSKE ske)
 
   if (ske->callbacks->send_packet)
     (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_SUCCESS, 
-                                 ske->callbacks->context);
+                                  ske->callbacks->context);
 
   silc_buffer_free(packet);
 
@@ -1125,7 +1135,7 @@ silc_ske_assemble_security_properties(SilcSKE ske,
 
   /* XXX */
   /* Get supported compression algorithms */
-  rp->comp_alg_list = "";
+  rp->comp_alg_list = strdup("");
   rp->comp_alg_len = 0;
 
   rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
@@ -1171,7 +1181,7 @@ silc_ske_select_security_properties(SilcSKE ske,
   /* Flags are returned unchanged. */
   payload->flags = rp->flags;
 
-  /* Take cookie */
+  /* Take cookie, we must return it to sender unmodified. */
   payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
   payload->cookie_len = SILC_SKE_COOKIE_LEN;
   memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
@@ -1507,7 +1517,7 @@ 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, 
+SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n, 
                                  uint32 len, 
                                  SilcMPInt *rnd)
 {
@@ -1529,7 +1539,7 @@ SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt n,
   if (silc_mp_cmp_ui(rnd, 1) < 0)
     status = SILC_SKE_STATUS_ERROR;
 
-  if (silc_mp_cmp(rnd, &n) >= 0)
+  if (silc_mp_cmp(rnd, n) >= 0)
     status = SILC_SKE_STATUS_ERROR;
 
   memset(string, 'F', (len / 8));
@@ -1562,15 +1572,17 @@ SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
     KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
     
     buf = silc_buffer_alloc(ske->start_payload_copy->len + 
-                           ske->pk_len + e_len + f_len + KEY_len);
+                           ske->ke2_payload->pk_len + e_len + 
+                           f_len + KEY_len);
     silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
-    
+
     /* Format the buffer used to compute the hash value */
     ret = 
       silc_buffer_format(buf,
                         SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
                                              ske->start_payload_copy->len),
-                        SILC_STR_UI_XNSTRING(ske->pk, ske->pk_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),
@@ -1596,7 +1608,7 @@ SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
     e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
 
     buf = silc_buffer_alloc(ske->start_payload_copy->len + 
-                           ske->pk_len + e_len);
+                           ske->ke1_payload->pk_len + e_len);
     silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
     
     /* Format the buffer used to compute the hash value */
@@ -1604,7 +1616,8 @@ SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
       silc_buffer_format(buf,
                         SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
                                              ske->start_payload_copy->len),
-                        SILC_STR_UI_XNSTRING(ske->pk, ske->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_END);
     if (ret == -1) {
@@ -1634,7 +1647,7 @@ SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
 }
 
 /* Processes the provided key material `data' as the SILC protocol 
-   specification specifies. */
+   specification defines. */
 
 SilcSKEStatus 
 silc_ske_process_key_material_data(unsigned char *data,