updates.
[silc.git] / apps / silcd / protocol.c
index abb40e715f55cb9b80213a772a2e0e457faf90fc..19d521a38ee7e740a747625a908ff47076fa8bc8 100644 (file)
@@ -124,14 +124,15 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske,
   }
 
   /* Save HMAC key to be used in the communication. */
-  if (!silc_hmac_alloc(hmac->hmac->name, NULL, &idata->hmac)) {
+  if (!silc_hmac_alloc(hmac->hmac->name, NULL, &idata->hmac_send)) {
     silc_cipher_free(idata->send_key);
     silc_cipher_free(idata->receive_key);
     silc_hash_free(idata->hash);
     silc_free(conn_data);
     return FALSE;
   }
-  silc_hmac_set_key(idata->hmac, keymat->hmac_key, keymat->hmac_key_len);
+  silc_hmac_set_key(idata->hmac_send, keymat->hmac_key, keymat->hmac_key_len);
+  idata->hmac_receive = idata->hmac_send;
 
   sock->user_data = (void *)conn_data;
 
@@ -144,6 +145,8 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
                                     uint32 len)
 {
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
+  char *cp;
+  int maj = 0, min = 0, build = 0, maj2, min2, build2;
 
   SILC_LOG_INFO(("%s (%s) is version %s", ske->sock->hostname,
                 ske->sock->ip, version));
@@ -154,11 +157,44 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
 
   /* Check software version */
 
-  if (len < strlen(silc_version_string))
+  cp = version + 9;
+  if (!cp)
     status = SILC_SKE_STATUS_BAD_VERSION;
 
-  /* XXX for now there is no other tests due to the abnormal version
-     string that is used */
+  maj = atoi(cp);
+  cp = strchr(cp, '.');
+  if (cp) {
+    min = atoi(cp + 1);
+    cp++;
+  }
+  if (cp) {
+    cp = strchr(cp, '.');
+    if (cp)
+      build = atoi(cp + 1);
+  }
+
+  cp = silc_version_string + 9;
+  if (!cp)
+    status = SILC_SKE_STATUS_BAD_VERSION;
+
+  maj2 = atoi(cp);
+  cp = strchr(cp, '.');
+  if (cp) {
+    min2 = atoi(cp + 1);
+    cp++;
+  }
+  if (cp) {
+    cp = strchr(cp, '.');
+    if (cp)
+      build2 = atoi(cp + 1);
+  }
+
+  if (maj != maj2)
+    status = SILC_SKE_STATUS_BAD_VERSION;
+#if 0
+  if (min < min2)
+    status = SILC_SKE_STATUS_BAD_VERSION;
+#endif
 
   return status;
 }
@@ -636,14 +672,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
 
        /* Remote end is client */
        if (conn_type == SILC_SOCKET_TYPE_CLIENT) {
-         SilcServerConfigSectionClientConnection *client = NULL;
-         client = silc_server_config_find_client_conn(server->config,
-                                                      ctx->sock->ip,
-                                                      ctx->sock->port);
-         if (!client)
-           client = silc_server_config_find_client_conn(server->config,
-                                                        ctx->sock->hostname,
-                                                        ctx->sock->port);
+         SilcServerConfigSectionClientConnection *client = ctx->cconfig;
          
          if (client) {
            switch(client->auth_meth) {
@@ -705,15 +734,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
        
        /* Remote end is server */
        if (conn_type == SILC_SOCKET_TYPE_SERVER) {
-         SilcServerConfigSectionServerConnection *serv = NULL;
-         serv = silc_server_config_find_server_conn(server->config,
-                                                    ctx->sock->ip,
-                                                    ctx->sock->port);
-         if (!serv)
-           serv = silc_server_config_find_server_conn(server->config,
-                                                      ctx->sock->hostname,
-                                                      ctx->sock->port);
-
+         SilcServerConfigSectionServerConnection *serv = ctx->sconfig;
+         
          if (serv) {
            switch(serv->auth_meth) {
            case SILC_AUTH_NONE:
@@ -774,15 +796,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
        
        /* Remote end is router */
        if (conn_type == SILC_SOCKET_TYPE_ROUTER) {
-         SilcServerConfigSectionServerConnection *serv = NULL;
-         serv = silc_server_config_find_router_conn(server->config,
-                                                    ctx->sock->ip,
-                                                    ctx->sock->port);
-         if (!serv)
-           serv = silc_server_config_find_router_conn(server->config,
-                                                      ctx->sock->hostname,
-                                                      ctx->sock->port);
-         
+         SilcServerConfigSectionServerConnection *serv = ctx->rconfig;
+
          if (serv) {
            switch(serv->auth_meth) {
            case SILC_AUTH_NONE:
@@ -1005,49 +1020,67 @@ static void
 silc_server_protocol_rekey_validate(SilcServer server,
                                    SilcServerRekeyInternalContext *ctx,
                                    SilcIDListData idata,
-                                   SilcSKEKeyMaterial *keymat)
+                                   SilcSKEKeyMaterial *keymat,
+                                   bool send)
 {
   if (ctx->responder == TRUE) {
-    silc_cipher_set_key(idata->send_key, keymat->receive_enc_key, 
-                       keymat->enc_key_len);
-    silc_cipher_set_iv(idata->send_key, keymat->receive_iv);
-    silc_cipher_set_key(idata->receive_key, keymat->send_enc_key, 
-                       keymat->enc_key_len);
-    silc_cipher_set_iv(idata->receive_key, keymat->send_iv);
+    if (send) {
+      silc_cipher_set_key(idata->send_key, keymat->receive_enc_key, 
+                         keymat->enc_key_len);
+      silc_cipher_set_iv(idata->send_key, keymat->receive_iv);
+    } else {
+      silc_cipher_set_key(idata->receive_key, keymat->send_enc_key, 
+                         keymat->enc_key_len);
+      silc_cipher_set_iv(idata->receive_key, keymat->send_iv);
+    }
   } else {
-    silc_cipher_set_key(idata->send_key, keymat->send_enc_key, 
-                       keymat->enc_key_len);
-    silc_cipher_set_iv(idata->send_key, keymat->send_iv);
-    silc_cipher_set_key(idata->receive_key, keymat->receive_enc_key, 
-                       keymat->enc_key_len);
-    silc_cipher_set_iv(idata->receive_key, keymat->receive_iv);
+    if (send) {
+      silc_cipher_set_key(idata->send_key, keymat->send_enc_key, 
+                         keymat->enc_key_len);
+      silc_cipher_set_iv(idata->send_key, keymat->send_iv);
+    } else {
+      silc_cipher_set_key(idata->receive_key, keymat->receive_enc_key, 
+                         keymat->enc_key_len);
+      silc_cipher_set_iv(idata->receive_key, keymat->receive_iv);
+    }
   }
 
-  silc_hmac_set_key(idata->hmac, keymat->hmac_key, keymat->hmac_key_len);
+  if (send) {
+    silc_hmac_alloc(idata->hmac_send->hmac->name, NULL, &idata->hmac_send);
+    silc_hmac_set_key(idata->hmac_send, keymat->hmac_key, 
+                     keymat->hmac_key_len);
+  } else {
+    silc_hmac_free(idata->hmac_receive);
+    idata->hmac_receive = idata->hmac_send;
+  }
 
   /* Save the current sending encryption key */
-  memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
-  silc_free(idata->rekey->send_enc_key);
-  idata->rekey->send_enc_key = 
-    silc_calloc(keymat->enc_key_len / 8,
-               sizeof(*idata->rekey->send_enc_key));
-  memcpy(idata->rekey->send_enc_key, keymat->send_enc_key, 
-        keymat->enc_key_len / 8);
-  idata->rekey->enc_key_len = keymat->enc_key_len / 8;
+  if (!send) {
+    memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
+    silc_free(idata->rekey->send_enc_key);
+    idata->rekey->send_enc_key = 
+      silc_calloc(keymat->enc_key_len / 8,
+                 sizeof(*idata->rekey->send_enc_key));
+    memcpy(idata->rekey->send_enc_key, keymat->send_enc_key, 
+          keymat->enc_key_len / 8);
+    idata->rekey->enc_key_len = keymat->enc_key_len / 8;
+  }
 }
 
 /* This function actually re-generates (when not using PFS) the keys and
    takes them into use. */
 
 void silc_server_protocol_rekey_generate(SilcServer server,
-                                        SilcServerRekeyInternalContext *ctx)
+                                        SilcServerRekeyInternalContext *ctx,
+                                        bool send)
 {
   SilcIDListData idata = (SilcIDListData)ctx->sock->user_data;
   SilcSKEKeyMaterial *keymat;
   uint32 key_len = silc_cipher_get_key_len(idata->send_key);
   uint32 hash_len = idata->hash->hash->hash_len;
 
-  SILC_LOG_DEBUG(("Generating new session keys (no PFS)"));
+  SILC_LOG_DEBUG(("Generating new %s session keys (no PFS)",
+                 send ? "sending" : "receiving"));
 
   /* Generate the new key */
   keymat = silc_calloc(1, sizeof(*keymat));
@@ -1057,7 +1090,7 @@ void silc_server_protocol_rekey_generate(SilcServer server,
                                     idata->hash, keymat);
 
   /* Set the keys into use */
-  silc_server_protocol_rekey_validate(server, ctx, idata, keymat);
+  silc_server_protocol_rekey_validate(server, ctx, idata, keymat, send);
 
   silc_ske_free_key_material(keymat);
 }
@@ -1067,7 +1100,8 @@ void silc_server_protocol_rekey_generate(SilcServer server,
 
 void 
 silc_server_protocol_rekey_generate_pfs(SilcServer server,
-                                       SilcServerRekeyInternalContext *ctx)
+                                       SilcServerRekeyInternalContext *ctx,
+                                       bool send)
 {
   SilcIDListData idata = (SilcIDListData)ctx->sock->user_data;
   SilcSKEKeyMaterial *keymat;
@@ -1076,7 +1110,8 @@ silc_server_protocol_rekey_generate_pfs(SilcServer server,
   unsigned char *tmpbuf;
   uint32 klen;
 
-  SILC_LOG_DEBUG(("Generating new session keys (with PFS)"));
+  SILC_LOG_DEBUG(("Generating new %s session keys (with PFS)",
+                 send ? "sending" : "receiving"));
 
   /* Encode KEY to binary data */
   tmpbuf = silc_mp_mp2bin(ctx->ske->KEY, 0, &klen);
@@ -1087,7 +1122,7 @@ silc_server_protocol_rekey_generate_pfs(SilcServer server,
                                     idata->hash, keymat);
 
   /* Set the keys into use */
-  silc_server_protocol_rekey_validate(server, ctx, idata, keymat);
+  silc_server_protocol_rekey_validate(server, ctx, idata, keymat, send);
 
   memset(tmpbuf, 0, klen);
   silc_free(tmpbuf);
@@ -1110,7 +1145,7 @@ silc_server_protocol_rekey_send_packet(SilcSKE ske,
 
   /* Send the packet immediately */
   silc_server_packet_send(server, ctx->sock,
-                         type, 0, packet->data, packet->len, TRUE);
+                         type, 0, packet->data, packet->len, FALSE);
 }
 
 /* Performs re-key as defined in the SILC protocol specification. */
@@ -1186,6 +1221,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
          silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY_DONE,
                                  0, NULL, 0, FALSE);
 
+         /* After we send REKEY_DONE we must set the sending encryption
+            key to the new key since all packets after this packet must
+            encrypted with the new key. */
+         silc_server_protocol_rekey_generate(server, ctx, TRUE);
+
          /* The protocol ends in next stage. */
          protocol->state = SILC_PROTOCOL_STATE_END;
        }
@@ -1197,7 +1237,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
 
        /* Start the re-key by sending the REKEY packet */
        silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY,
-                               0, NULL, 0, TRUE);
+                               0, NULL, 0, FALSE);
 
        if (ctx->pfs == TRUE) {
          /* 
@@ -1232,9 +1272,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
           * Do normal and simple re-key.
           */
 
-         /* The protocol ends in next stage. We have sent the REKEY packet
-            and now we just wait that the responder send REKEY_DONE and
-            the we'll generate the new key, simple. */
+         /* Send the REKEY_DONE to indicate we will take new keys into use 
+            now. */ 
+         silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY_DONE,
+                                 0, NULL, 0, FALSE);
+
+         /* After we send REKEY_DONE we must set the sending encryption
+            key to the new key since all packets after this packet must
+            encrypted with the new key. */
+         silc_server_protocol_rekey_generate(server, ctx, TRUE);
+
+         /* The protocol ends in next stage. */
          protocol->state = SILC_PROTOCOL_STATE_END;
        }
       }
@@ -1298,6 +1346,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
     silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY_DONE,
                            0, NULL, 0, FALSE);
     
+    /* After we send REKEY_DONE we must set the sending encryption
+       key to the new key since all packets after this packet must
+       encrypted with the new key. */
+    silc_server_protocol_rekey_generate_pfs(server, ctx, TRUE);
+
     /* The protocol ends in next stage. */
     protocol->state = SILC_PROTOCOL_STATE_END;
     break;
@@ -1313,14 +1366,9 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
       protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 0);
     }
 
-    if (ctx->responder == FALSE) {
-      if (ctx->pfs == FALSE) {
-       /* Send the REKEY_DONE to indicate we will take new keys into use 
-          now. */ 
-       silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY_DONE,
-                               0, NULL, 0, FALSE);
-      }
-    }
+    /* We received the REKEY_DONE packet and all packets after this is
+       encrypted with the new key so set the decryption key to the new key */
+    silc_server_protocol_rekey_generate(server, ctx, FALSE);
 
     /* Protocol has ended, call the final callback */
     if (protocol->final_callback)