updates.
authorPekka Riikonen <priikone@silcnet.org>
Tue, 16 Oct 2001 22:06:51 +0000 (22:06 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 16 Oct 2001 22:06:51 +0000 (22:06 +0000)
24 files changed:
CHANGES
apps/silcd/idlist.c
apps/silcd/packet_receive.c
apps/silcd/packet_send.c
apps/silcd/packet_send.h
apps/silcd/protocol.c
apps/silcd/server.c
apps/silcd/server.h
apps/silcd/server_backup.c
doc/draft-riikonen-silc-pp-04.nroff
lib/silcclient/client.c
lib/silcclient/client.h
lib/silcclient/client_channel.c
lib/silcclient/client_prvmsg.c
lib/silcclient/protocol.c
lib/silccore/silcchannel.c
lib/silccore/silcpacket.c
lib/silccore/silcpacket.h
lib/silccore/silcprivate.c
lib/silccrypt/silccipher.h
lib/silccrypt/silchmac.c
lib/silccrypt/silchmac.h
lib/silcske/silcske.c
lib/silcske/silcske.h

diff --git a/CHANGES b/CHANGES
index 25649f7f9b2675796da0b9b71e753bc28b00472c..427f1110b7e45d5e295c9c1f9cb3653451b2747a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,21 @@
+Tue Oct 16 20:45:49 EDT 2001  Pekka Riikonen <priikone@silcnet.org>
+
+       * Changed the SILC packet header to have the first two bytes
+         (the packet length) encrypted.  Affected files aroung the
+         code tree, lib/silccore/silcpacket.[ch].  Removed the
+         SilcPacketCheckDecrypt callback.  It is not needed anymore
+         since the silc_packet_receive_process will determine now
+         whether the packet is normal or special.
+
+       * Implemented the unidirectional MAC keys.  Affected files
+         lib/silcske/silcske.c, silcd/protocol.c and
+         lib/silcclient/protocol.c.
+
+       * Implemented the packet sequence number to the MAC computation.
+         Affected files lib/silccore/silcpacket.c, silcd/protocol.c,
+         silcd/packet_send.c, silcd/server.c, lib/silcclient/client.c,
+         lib/silcclient/protocol.c.
+
 Mon Oct 15 17:42:55 EDT 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Allow backup router to announce servers.  All servers
index 527b49ea6a8fa535dae296544ef26b69ee7a1d90..4a72bcb9f95ce557bbb25a0131e990b9c4b538d3 100644 (file)
@@ -66,8 +66,10 @@ void silc_idlist_del_data(void *entry)
     }
     silc_free(idata->rekey);
   }
-  if (idata->hmac_send)                /* Same as idata->hmac_receive */
+  if (idata->hmac_send)
     silc_hmac_free(idata->hmac_send);
+  if (idata->hmac_receive)
+    silc_hmac_free(idata->hmac_receive);
   if (idata->public_key)
     silc_pkcs_public_key_free(idata->public_key);
 }
index 983d44f3015253cb313353c4c1ce61d1cb70547f..5c73655e4b7e01bd6d8761f5ec17c409c430257f 100644 (file)
@@ -71,7 +71,8 @@ void silc_server_notify(SilcServer server,
     if (dst_sock)
       /* Relay the packet */
       silc_server_relay_packet(server, dst_sock, idata->send_key,
-                              idata->hmac_receive, packet, TRUE);
+                              idata->hmac_receive, idata->psn_send++,
+                              packet, TRUE);
   }
 
   /* Parse the Notify Payload */
@@ -1161,7 +1162,8 @@ void silc_server_private_message(SilcServer server,
 
   /* Send the private message */
   silc_server_send_private_message(server, dst_sock, idata->send_key,
-                                  idata->hmac_send, packet);
+                                  idata->hmac_send, idata->psn_send++,
+                                  packet);
 }
 
 /* Received private message key packet.. This packet is never for us. It is to
@@ -1193,7 +1195,7 @@ void silc_server_private_message_key(SilcServer server,
 
   /* Relay the packet */
   silc_server_relay_packet(server, dst_sock, idata->send_key,
-                          idata->hmac_send, packet, FALSE);
+                          idata->hmac_send, idata->psn_send++, packet, FALSE);
 }
 
 /* Processes incoming command reply packet. The command reply packet may
@@ -1257,8 +1259,8 @@ void silc_server_command_reply(SilcServer server,
     idata = (SilcIDListData)client;
     
     /* Encrypt packet */
-    silc_packet_encrypt(idata->send_key, idata->hmac_send, dst_sock->outbuf, 
-                       buffer->len);
+    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
+                       dst_sock->outbuf, buffer->len);
     
     /* Send the packet */
     silc_server_packet_send_real(server, dst_sock, TRUE);
@@ -2344,7 +2346,8 @@ void silc_server_key_agreement(SilcServer server,
 
   /* Relay the packet */
   silc_server_relay_packet(server, dst_sock, idata->send_key,
-                          idata->hmac_send, packet, FALSE);
+                          idata->hmac_send, idata->psn_send++,
+                          packet, FALSE);
 }
 
 /* Received connection auth request packet that is used during connection
index a73493608c4acd0a77abecc4c4a7d09b3bf2a8b8..81305e729b37ca5e12618ee4a8e2b1614343fcec 100644 (file)
@@ -140,8 +140,10 @@ void silc_server_packet_send_dest(SilcServer server,
   SilcIDListData idata = (SilcIDListData)sock->user_data;
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
+  uint32 sequence = 0;
   unsigned char *dst_id_data = NULL;
   uint32 dst_id_len = 0;
+  int block_len = 0;
 
   /* If disconnecting, ignore the data */
   if (SILC_IS_DISCONNECTING(sock))
@@ -158,6 +160,13 @@ void silc_server_packet_send_dest(SilcServer server,
     dst_id_len = silc_id_get_len(dst_id, dst_id_type);
   }
 
+  if (idata) {
+    cipher = idata->send_key;
+    hmac = idata->hmac_send;
+    sequence = idata->psn_send++;
+    block_len = silc_cipher_get_block_len(cipher);
+  }
+
   /* Set the packet context pointers */
   packetdata.type = type;
   packetdata.flags = flags;
@@ -169,7 +178,7 @@ void silc_server_packet_send_dest(SilcServer server,
   packetdata.dst_id_type = dst_id_type;
   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
     packetdata.src_id_len + dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
 
   /* Prepare outgoing data buffer for packet sending */
   silc_packet_send_prepare(sock, 
@@ -188,17 +197,13 @@ void silc_server_packet_send_dest(SilcServer server,
     silc_buffer_put(sock->outbuf, data, data_len);
 
   /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
-
-  if (idata) {
-    cipher = idata->send_key;
-    hmac = idata->hmac_send;
-  }
+  silc_packet_assemble(&packetdata, cipher);
 
   /* Encrypt the packet */
-  silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+  silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, sock->outbuf->len);
 
-  SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
+  SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence, 
+                   sock->outbuf->len),
                   sock->outbuf->data, sock->outbuf->len);
 
   /* Now actually send the packet */
@@ -234,10 +239,12 @@ void silc_server_packet_send_srcdest(SilcServer server,
   SilcIDListData idata;
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
+  uint32 sequence = 0;
   unsigned char *dst_id_data = NULL;
   uint32 dst_id_len = 0;
   unsigned char *src_id_data = NULL;
   uint32 src_id_len = 0;
+  int block_len = 0;
 
   SILC_LOG_DEBUG(("Sending packet, type %d", type));
 
@@ -254,6 +261,13 @@ void silc_server_packet_send_srcdest(SilcServer server,
     src_id_len = silc_id_get_len(src_id, src_id_type);
   }
 
+  if (idata) {
+    cipher = idata->send_key;
+    hmac = idata->hmac_send;
+    sequence = idata->psn_send++;
+    block_len = silc_cipher_get_block_len(cipher);
+  }
+
   /* Set the packet context pointers */
   packetdata.type = type;
   packetdata.flags = flags;
@@ -265,7 +279,7 @@ void silc_server_packet_send_srcdest(SilcServer server,
   packetdata.dst_id_type = dst_id_type;
   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
     packetdata.src_id_len + dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
 
   /* Prepare outgoing data buffer for packet sending */
   silc_packet_send_prepare(sock, 
@@ -284,17 +298,13 @@ void silc_server_packet_send_srcdest(SilcServer server,
     silc_buffer_put(sock->outbuf, data, data_len);
 
   /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
-
-  if (idata) {
-    cipher = idata->send_key;
-    hmac = idata->hmac_send;
-  }
+  silc_packet_assemble(&packetdata, cipher);
 
   /* Encrypt the packet */
-  silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+  silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, sock->outbuf->len);
 
-  SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
+  SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence, 
+                   sock->outbuf->len),
                   sock->outbuf->data, sock->outbuf->len);
 
   /* Now actually send the packet */
@@ -330,10 +340,11 @@ void silc_server_packet_broadcast(SilcServer server,
     silc_buffer_push(buffer, buffer->data - buffer->head);
     silc_packet_send_prepare(sock, 0, 0, buffer->len); 
     silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
-    silc_packet_encrypt(idata->send_key, idata->hmac_send, 
+    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
                        sock->outbuf, sock->outbuf->len);
 
-    SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
+    SILC_LOG_HEXDUMP(("Broadcasted packet (%d), len %d", idata->psn_send - 1,
+                     sock->outbuf->len),
                     sock->outbuf->data, sock->outbuf->len);
 
     /* Now actually send the packet */
@@ -364,10 +375,11 @@ void silc_server_packet_route(SilcServer server,
   silc_buffer_push(buffer, buffer->data - buffer->head);
   silc_packet_send_prepare(sock, 0, 0, buffer->len); 
   silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
-  silc_packet_encrypt(idata->send_key, idata->hmac_send, 
+  silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
                      sock->outbuf, sock->outbuf->len);
 
-  SILC_LOG_HEXDUMP(("Routed packet, len %d", sock->outbuf->len),
+  SILC_LOG_HEXDUMP(("Routed packet (%d), len %d", idata->psn_send - 1, 
+                   sock->outbuf->len),
                   sock->outbuf->data, sock->outbuf->len);
 
   /* Now actually send the packet */
@@ -385,14 +397,27 @@ silc_server_packet_send_to_channel_real(SilcServer server,
                                        SilcPacketContext *packet,
                                        SilcCipher cipher,
                                        SilcHmac hmac,
+                                       uint32 sequence,
                                        unsigned char *data,
                                        uint32 data_len,
-                                       int channel_message,
+                                       bool channel_message,
                                        bool force_send)
 {
+  int block_len = 0;
   packet->truelen = data_len + SILC_PACKET_HEADER_LEN + 
     packet->src_id_len + packet->dst_id_len;
 
+  if (cipher) {
+    block_len = silc_cipher_get_block_len(cipher);
+
+    if (channel_message)
+      packet->padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+                                          packet->src_id_len +
+                                          packet->dst_id_len), block_len);
+    else
+      packet->padlen = SILC_PACKET_PADLEN(packet->truelen, block_len);
+  }
+
   /* Prepare outgoing data buffer for packet sending */
   silc_packet_send_prepare(sock, 
                           SILC_PACKET_HEADER_LEN +
@@ -407,15 +432,17 @@ silc_server_packet_send_to_channel_real(SilcServer server,
      is encrypted with normal session key shared with the client, unless
      the `channel_message' is TRUE. */
   silc_buffer_put(sock->outbuf, data, data_len);
-  silc_packet_assemble(packet);
+  silc_packet_assemble(packet, cipher);
   if (channel_message)
-    silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
-                       packet->src_id_len + packet->dst_id_len +
-                       packet->padlen);
+    silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, 
+                       SILC_PACKET_HEADER_LEN + packet->src_id_len + 
+                       packet->dst_id_len + packet->padlen);
   else
-    silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+    silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, 
+                       sock->outbuf->len);
     
-  SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
+  SILC_LOG_HEXDUMP(("Channel packet (%d), len %d", sequence, 
+                   sock->outbuf->len),
                   sock->outbuf->data, sock->outbuf->len);
 
   /* Now actually send the packet */
@@ -465,9 +492,6 @@ void silc_server_packet_send_to_channel(SilcServer server,
   packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
   packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
   packetdata.dst_id_type = SILC_ID_CHANNEL;
-  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
-    packetdata.src_id_len + packetdata.dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
 
   /* If there are global users in the channel we will send the message
      first to our router for further routing. */
@@ -486,6 +510,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, 
                                              idata->hmac_send, 
+                                             idata->psn_send++,
                                              data, data_len, FALSE, 
                                              force_send);
     }
@@ -532,6 +557,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, 
                                              idata->hmac_send, 
+                                             idata->psn_send++,
                                              data, data_len, FALSE, 
                                              force_send);
 
@@ -556,6 +582,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
     silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                            idata->send_key, 
                                            idata->hmac_send, 
+                                           idata->psn_send++, 
                                            data, data_len, FALSE, 
                                            force_send);
   }
@@ -667,9 +694,6 @@ void silc_server_packet_relay_to_channel(SilcServer server,
   packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
   packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
   packetdata.dst_id_type = SILC_ID_CHANNEL;
-  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
-                                         packetdata.src_id_len +
-                                         packetdata.dst_id_len));
 
   /* If there are global users in the channel we will send the message
      first to our router for further routing. */
@@ -689,6 +713,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, 
                                              idata->hmac_send, 
+                                             idata->psn_send++, 
                                              data, data_len, TRUE, 
                                              force_send);
     }
@@ -814,6 +839,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, 
                                              idata->hmac_send, 
+                                             idata->psn_send++, 
                                              data, data_len, TRUE, 
                                              force_send);
 
@@ -838,6 +864,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
     silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                            idata->send_key, 
                                            idata->hmac_send, 
+                                           idata->psn_send++, 
                                            data, data_len, TRUE, 
                                            force_send);
   }
@@ -892,6 +919,7 @@ void silc_server_send_private_message(SilcServer server,
                                      SilcSocketConnection dst_sock,
                                      SilcCipher cipher,
                                      SilcHmac hmac,
+                                     uint32 sequence,
                                      SilcPacketContext *packet)
 {
   SilcBuffer buffer = packet->buffer;
@@ -905,7 +933,7 @@ void silc_server_send_private_message(SilcServer server,
     silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
 
     /* Re-encrypt packet */
-    silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, buffer->len);
+    silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf, buffer->len);
 
     /* Send the packet */
     silc_server_packet_send_real(server, dst_sock, FALSE);
@@ -918,7 +946,7 @@ void silc_server_send_private_message(SilcServer server,
     silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
 
     /* Encrypt header */
-    silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, 
+    silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf, 
                        SILC_PACKET_HEADER_LEN + packet->src_id_len + 
                        packet->dst_id_len + packet->padlen);
 
@@ -1391,6 +1419,7 @@ void silc_server_send_notify_on_channels(SilcServer server,
   uint32 data_len;
   bool force_send = FALSE;
   va_list ap;
+  int block_len;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1442,18 +1471,21 @@ void silc_server_send_notify_on_channels(SilcServer server,
        /* Get data used in packet header encryption, keys and stuff. */
        sock = (SilcSocketConnection)c->router->connection;
        idata = (SilcIDListData)c->router;
-       
+       block_len = idata->send_key ? 
+         silc_cipher_get_block_len(idata->send_key) : 0;
+
        packetdata.dst_id = silc_id_id2str(c->router->id, SILC_ID_SERVER);
        packetdata.dst_id_len = silc_id_get_len(c->router->id, SILC_ID_SERVER);
        packetdata.dst_id_type = SILC_ID_SERVER;
        packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
          packetdata.src_id_len + packetdata.dst_id_len;
-       packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+       packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
 
        /* Send the packet */
        silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                                idata->send_key, 
                                                idata->hmac_send, 
+                                               idata->psn_send++, 
                                                data, data_len, FALSE, 
                                                force_send);
        
@@ -1475,18 +1507,21 @@ void silc_server_send_notify_on_channels(SilcServer server,
        /* Get data used in packet header encryption, keys and stuff. */
        sock = (SilcSocketConnection)c->connection;
        idata = (SilcIDListData)c;
+       block_len = idata->send_key ? 
+         silc_cipher_get_block_len(idata->send_key) : 0;
        
        packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT);
        packetdata.dst_id_len = silc_id_get_len(c->id, SILC_ID_CLIENT);
        packetdata.dst_id_type = SILC_ID_CLIENT;
        packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
          packetdata.src_id_len + packetdata.dst_id_len;
-       packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+       packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
 
        /* Send the packet */
        silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                                idata->send_key, 
                                                idata->hmac_send, 
+                                               idata->psn_send++, 
                                                data, data_len, FALSE, 
                                                force_send);
 
@@ -1654,6 +1689,7 @@ void silc_server_relay_packet(SilcServer server,
                              SilcSocketConnection dst_sock,
                              SilcCipher cipher,
                              SilcHmac hmac,
+                             uint32 sequence,
                              SilcPacketContext *packet,
                              bool force_send)
 {
@@ -1664,7 +1700,8 @@ void silc_server_relay_packet(SilcServer server,
   silc_buffer_put(dst_sock->outbuf, packet->buffer->data, packet->buffer->len);
   
   /* Re-encrypt packet */
-  silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, packet->buffer->len);
+  silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf, 
+                     packet->buffer->len);
   
   /* Send the packet */
   silc_server_packet_send_real(server, dst_sock, force_send);
index f8c98233c899772bd30674d621617f8fc712e925..25efb1a1159b00203049168ffee832bc93a04c6d 100644 (file)
@@ -87,6 +87,7 @@ void silc_server_send_private_message(SilcServer server,
                                      SilcSocketConnection dst_sock,
                                      SilcCipher cipher,
                                      SilcHmac hmac,
+                                     uint32 sequence,
                                      SilcPacketContext *packet);
 void silc_server_send_motd(SilcServer server,
                           SilcSocketConnection sock);
@@ -221,6 +222,7 @@ void silc_server_relay_packet(SilcServer server,
                              SilcSocketConnection dst_sock,
                              SilcCipher cipher,
                              SilcHmac hmac,
+                             uint32 sequence,
                              SilcPacketContext *packet,
                              bool force_send);
 void silc_server_send_connection_auth_request(SilcServer server,
index c3cad75bc336c1769fdf3805ad4dc6f24e0f9613..50fdc7075a85a081b4e82bf81fe3192893780685 100644 (file)
@@ -227,6 +227,32 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske,
     return FALSE;
   }
   
+  if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, 
+                      &idata->hmac_send)) {
+    silc_cipher_free(idata->send_key);
+    silc_cipher_free(idata->receive_key);
+    silc_free(conn_data);
+    return FALSE;
+  }
+
+  if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, 
+                      &idata->hmac_receive)) {
+    silc_cipher_free(idata->send_key);
+    silc_cipher_free(idata->receive_key);
+    silc_hmac_free(idata->hmac_send);
+    silc_free(conn_data);
+    return FALSE;
+  }
+
+  /* XXX backwards support for old MAC thingy
+     XXX Remove ing 0.7.x */
+  if (ske->backward_version) {
+    silc_hmac_set_b(idata->hmac_send);
+    silc_hmac_set_b(idata->hmac_receive);
+    idata->send_key->back = TRUE;
+    idata->receive_key->back = TRUE;
+  }
+
   if (is_responder == TRUE) {
     silc_cipher_set_key(idata->send_key, keymat->receive_enc_key, 
                        keymat->enc_key_len);
@@ -234,6 +260,10 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske,
     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);
+    silc_hmac_set_key(idata->hmac_send, keymat->receive_hmac_key, 
+                     keymat->hmac_key_len);
+    silc_hmac_set_key(idata->hmac_receive, keymat->send_hmac_key, 
+                     keymat->hmac_key_len);
   } else {
     silc_cipher_set_key(idata->send_key, keymat->send_enc_key, 
                        keymat->enc_key_len);
@@ -241,6 +271,10 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske,
     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_send, keymat->send_hmac_key, 
+                     keymat->hmac_key_len);
+    silc_hmac_set_key(idata->hmac_receive, keymat->receive_hmac_key, 
+                     keymat->hmac_key_len);
   }
 
   idata->rekey = silc_calloc(1, sizeof(*idata->rekey));
@@ -255,29 +289,19 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske,
     idata->rekey->pfs = TRUE;
   idata->rekey->ske_group = silc_ske_group_get_number(group);
 
-  /* Save the remote host's public key */
-  silc_pkcs_public_key_decode(ske->ke1_payload->pk_data, 
-                             ske->ke1_payload->pk_len, &idata->public_key);
-
   /* Save the hash */
   if (!silc_hash_alloc(hash->hash->name, &idata->hash)) {
     silc_cipher_free(idata->send_key);
     silc_cipher_free(idata->receive_key);
+    silc_hmac_free(idata->hmac_send);
+    silc_hmac_free(idata->hmac_receive);
     silc_free(conn_data);
     return FALSE;
   }
 
-  /* Save HMAC key to be used in the communication. */
-  if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), 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_send, keymat->hmac_key, keymat->hmac_key_len);
-  idata->hmac_receive = idata->hmac_send;
+  /* Save the remote host's public key */
+  silc_pkcs_public_key_decode(ske->ke1_payload->pk_data, 
+                             ske->ke1_payload->pk_len, &idata->public_key);
 
   sock->user_data = (void *)conn_data;
 
@@ -345,6 +369,11 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
   if (min > min2)
     status = SILC_SKE_STATUS_BAD_VERSION;
 
+  /* Backwards support for 0.5.x for various MAC related issues.
+     XXX Remove in 0.7.x */
+  if (maj == 0 && min < 6)
+    ske->backward_version = 1;
+
   return status;
 }
 
@@ -1211,33 +1240,31 @@ silc_server_protocol_rekey_validate(SilcServer server,
       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_hmac_set_key(idata->hmac_send, keymat->receive_hmac_key, 
+                       keymat->hmac_key_len);
     } 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);
+      silc_hmac_set_key(idata->hmac_receive, keymat->send_hmac_key, 
+                       keymat->hmac_key_len);
     }
   } else {
     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);
+      silc_hmac_set_key(idata->hmac_send, keymat->send_hmac_key, 
+                       keymat->hmac_key_len);
     } 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_receive, keymat->receive_hmac_key, 
+                       keymat->hmac_key_len);
     }
   }
 
-  if (send) {
-    silc_hmac_alloc((char *)silc_hmac_get_name(idata->hmac_send), 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 */
   if (!send) {
     memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
index 5c95ce98b03b0275d11b5552f7bd23e1705de022..bad68ba9ab179017aacf0b7d535d2069249d4faf 100644 (file)
@@ -1448,6 +1448,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
   SilcIDListData idata;
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
+  uint32 sequence = 0;
   int ret;
 
   if (!sock)
@@ -1548,46 +1549,14 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
   if (idata) {
     cipher = idata->receive_key;
     hmac = idata->hmac_receive;
+    sequence = idata->psn_receive;
   }
  
   /* Process the packet. This will call the parser that will then
      decrypt and parse the packet. */
-  silc_packet_receive_process(sock, cipher, hmac, silc_server_packet_parse, 
-                             server);
-}
-
-/* Callback function that the silc_packet_decrypt will call to make the
-   decision whether the packet is normal or special packet. We will 
-   return TRUE if it is normal and FALSE if it is special */
-
-static int silc_server_packet_decrypt_check(SilcPacketType packet_type,
-                                           SilcBuffer buffer,
-                                           SilcPacketContext *packet,
-                                           void *context)
-{
-  SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
-  SilcServer server = (SilcServer)parse_ctx->context;
-
-  /* Packet is normal packet, if: 
-
-     1) packet is private message packet and does not have private key set
-     2) is other packet than channel message packet
-     3) is channel message packet and remote is router and we are router 
-
-     all other packets are special packets 
-  */
-
-  if (packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
-      (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
-    return FALSE;
-
-  if (packet_type != SILC_PACKET_CHANNEL_MESSAGE || 
-      (packet_type == SILC_PACKET_CHANNEL_MESSAGE &&
-       parse_ctx->sock->type == SILC_SOCKET_TYPE_ROUTER &&
-       server->server_type == SILC_ROUTER))
-    return TRUE;
-
-  return FALSE;
+  silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? 
+                             TRUE : FALSE, cipher, hmac, sequence, 
+                             silc_server_packet_parse, server);
 }
   
 /* Parses whole packet, received earlier. */
@@ -1603,29 +1572,15 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
 
   SILC_LOG_DEBUG(("Start"));
 
-  /* Decrypt the received packet */
-  ret = silc_packet_decrypt(idata ? idata->receive_key : NULL, 
-                           idata ? idata->hmac_receive : NULL, 
-                           packet->buffer, packet,
-                           silc_server_packet_decrypt_check, parse_ctx);
-  if (ret < 0) {
-    SILC_LOG_WARNING(("Packet decryption failed for connection "
-                     "%s:%d [%s]", sock->hostname, sock->port,  
-                     (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
-                      sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
-                      sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
-                      "Router")));
-    goto out;
-  }
+  /* XXX backwards support for 0.5.x
+     XXX remove in 0.7.x */
+  packet->sock = sock;
 
-  if (ret == 0) {
-    /* Parse the packet. Packet type is returned. */
-    ret = silc_packet_parse(packet);
-  } else {
-    /* Parse the packet header in special way as this is "special"
-       packet type. */
-    ret = silc_packet_parse_special(packet);
-  }
+  /* Parse the packet */
+  if (parse_ctx->normal)
+    ret = silc_packet_parse(packet, idata ? idata->receive_key : NULL);
+  else
+    ret = silc_packet_parse_special(packet, idata ? idata->receive_key : NULL);
 
   /* If entry is disabled ignore what we got. */
   if (ret != SILC_PACKET_RESUME_ROUTER &&
@@ -1699,10 +1654,15 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
 /* Parser callback called by silc_packet_receive_process. This merely
    registers timeout that will handle the actual parsing when appropriate. */
 
-void silc_server_packet_parse(SilcPacketParserContext *parser_context)
+void silc_server_packet_parse(SilcPacketParserContext *parser_context,
+                             void *context)
 {
-  SilcServer server = (SilcServer)parser_context->context;
+  SilcServer server = (SilcServer)context;
   SilcSocketConnection sock = parser_context->sock;
+  SilcIDListData idata = (SilcIDListData)sock->user_data;
+
+  if (idata)
+    idata->psn_receive = parser_context->packet->sequence + 1;
 
   switch (sock->type) {
   case SILC_SOCKET_TYPE_UNKNOWN:
index a09d41b9520affb022f5930bdfbdf88b0881f05b..5249e6b83cbd82c91aba5c6cc191c1c8d612881c 100644 (file)
@@ -126,7 +126,8 @@ void silc_server_stop(SilcServer server);
 void silc_server_start_key_exchange(SilcServer server,
                                    SilcServerConnection sconn,
                                    int sock);
-void silc_server_packet_parse(SilcPacketParserContext *parser_context);
+void silc_server_packet_parse(SilcPacketParserContext *parser_context,
+                             void *context);
 void silc_server_packet_parse_type(SilcServer server, 
                                   SilcSocketConnection sock,
                                   SilcPacketContext *packet);
index d782297a5b133a94899576fb0ec2e4ab04074e3a..2088dd9a0c8a93f6d8dde710fc208effb03c1cbb 100644 (file)
@@ -293,7 +293,7 @@ void silc_server_backup_broadcast(SilcServer server,
 
     silc_packet_send_prepare(sock, 0, 0, buffer->len); 
     silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
-    silc_packet_encrypt(idata->send_key, idata->hmac_send, 
+    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++, 
                        sock->outbuf, sock->outbuf->len);
 
     SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
index d54920dcfac699056b888552b1918f8e4eea9bd1..bb44b7c577ce03255fa5c9701e130100a09f4fb0 100644 (file)
@@ -209,17 +209,16 @@ Figure 1:  Typical SILC Packet
 SILC Header is always the first part of the packet and its purpose
 is to provide information about the packet.  It provides for example
 the packet type, origin of the packet and the destination of the packet.
-The header is variable in length and first two (2) bytes of the
-header (thus first two bytes of the packet) are not encrypted.  The
-first two (2) bytes are the length of the packet which is not encrypted.
-See the following section for description of SILC Packet header.  Packets
-without SILC header or with malformed SILC header MUST be dropped.
+The header is variable in length.  See the following section for
+description of SILC Packet header.  Packets without SILC header or
+with malformed SILC header MUST be dropped.
 
 Padding follows the packet header.  The purpose of the padding is to
 make the packet multiple by eight (8) or by the block size of the
 cipher used in the encryption, which ever is larger.  The maximum
 length of padding is currently 16 bytes.  The padding is always
-encrypted.
+encrypted.  See the section 2.7 Padding Generation for more detailed
+information.
 
 Data payload area follows padding and it is the actual data of the
 packet.  The packet data is the packet payloads defined in this
@@ -245,15 +244,14 @@ detailed information about the packet.  The receiver of the packet
 uses the packet header to parse the packet and gain other relevant
 parameters of the packet.
 
-The following diagram represents the SILC packet header.  (*) indicates
-that this field is never encrypted.  Other fields are always encrypted.
+The following diagram represents the SILC packet header.
 
 .in 5
 .nf
                      1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-|        Payload Length *       |     Flags     |  Packet Type  |
+|         Payload Length        |     Flags     |  Packet Type  |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |        Source ID Length       |     Destination ID Length     |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -277,8 +275,7 @@ Figure 2:  SILC Packet Header
 
 .in 6
 o Payload Length (2 bytes) - Is the length of the packet
-  not including the padding of the packet.  This field must
-  not be encrypted but must always be authenticated.
+  not including the padding of the packet.
 
 o Flags (1 byte) - Indicates flags to be used in packet
   processing.  Several flags may be set by ORing the flags
@@ -2398,12 +2395,6 @@ any of the special cases described in the following sections the packet
 decryption is special.  If the packet type is not among those special
 packet types rest of the packet can be decrypted with the same key.
 
-Also, note that two bytes of the SILC Packet header are not encrypted
-thus it must be noticed in the decryption process by starting the
-decryption from the second byte of the header.  This sets some rules
-to padding generation as well, see the section 2.7 Packet Padding
-Generation.
-
 With out a doubt, this sort of decryption processing causes some
 overhead to packet decryption, but never the less, is required.
 
@@ -2512,7 +2503,11 @@ Hence, packet's MAC generation is as follows:
 The MAC key is negotiated during the SKE protocol.  The sequence number
 is a 32 bit MSB first value starting from zero for first packet and
 increasing for subsequent packets, finally wrapping after 2^32 packets.
-The value is never reset, not even after rekey has been performed.
+The value is never reset, not even after rekey has been performed.  Note
+that the sequence number is incremented only when MAC is computed for a
+packet.  If packet is not encrypted and MAC is not computed then the
+sequence number is not incremented.  Hence, the sequence number is zero
+for first encrypted packet.
 
 See [SILC1] for defined and allowed MAC algorithms.
 
@@ -2529,23 +2524,21 @@ and between the Data Payload area.  The padding for normal packets
 are calculated as follows:
 
 .in 6
-padding length = 16 - ((packet length - 2) mod 16)
+padding length = 16 - (packet_length mod block_size)
 .in 3
 
-The 16 is the maximum padding allowed in SILC packet.  Two (2) is 
-subtracted from the true length of the packet because two (2) bytes
-is not encrypted in SILC Packet Header, see section 2.2 SILC Packet
-Header.  Those two bytes that are not encrypted MUST NOT be calculated
-to the padding length.
+The `block_size' is the block size of the cipher.  The maximum padding
+length is 16 bytes, and minimum is 1 byte.  The above algorithm calculates
+the padding to the next block size, and always returns the padding
+length between 1 - 16 bytes.
 
-For special packets the padding calculation MAY be different as special
+For special packets the padding calculation is different as special
 packets may be encrypted differently.  In these cases the encrypted
 data area MUST already be multiple by the block size thus in this case
 the padding is calculated only for SILC Packet Header, not for any
 other area of the packet.  The same algorithm works in this case as
 well, except that the `packet length' is now the SILC Packet Header
-length.  In this case, as well, two (2) is subtracted from the
-length.
+length. 
 
 The padding MUST be random data, preferably, generated by 
 cryptographically strong random number generator.
index 617682e17030e23d5c42587e99725b79f8166c50..c7c175911076778508c36df14a98e2f1a76620a9 100644 (file)
@@ -30,7 +30,8 @@ SILC_TASK_CALLBACK(silc_client_packet_parse_real);
 SILC_TASK_CALLBACK(silc_client_rekey_callback);
 SILC_TASK_CALLBACK(silc_client_rekey_final);
 
-static void silc_client_packet_parse(SilcPacketParserContext *parser_context);
+static void silc_client_packet_parse(SilcPacketParserContext *parser_context,
+                                    void *context);
 static void silc_client_packet_parse_type(SilcClient client, 
                                          SilcSocketConnection sock,
                                          SilcPacketContext *packet);
@@ -748,42 +749,15 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
     /* Process the packet. This will call the parser that will then
        decrypt and parse the packet. */
     if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
-      silc_packet_receive_process(sock, conn->receive_key, conn->hmac_receive,
+      silc_packet_receive_process(sock, FALSE, conn->receive_key, 
+                                 conn->hmac_receive, conn->psn_receive,
                                  silc_client_packet_parse, client);
     else
-      silc_packet_receive_process(sock, NULL, NULL,
+      silc_packet_receive_process(sock, FALSE, NULL, NULL, 0, 
                                  silc_client_packet_parse, client);
   }
 }
 
-/* Callback function that the silc_packet_decrypt will call to make the
-   decision whether the packet is normal or special packet. We will 
-   return TRUE if it is normal and FALSE if it is special */
-
-static int silc_client_packet_decrypt_check(SilcPacketType packet_type,
-                                           SilcBuffer buffer,
-                                           SilcPacketContext *packet,
-                                           void *context)
-{
-
-  /* Packet is normal packet, if: 
-
-     1) packet is private message packet and does not have private key set
-     2) is other packet than channel message packet
-
-     all other packets are special packets 
-  */
-
-  if (packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
-      (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
-    return FALSE;
-
-  if (packet_type != SILC_PACKET_CHANNEL_MESSAGE)
-    return TRUE;
-
-  return FALSE;
-}
-
 /* Parses whole packet, received earlier. */
 
 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
@@ -791,33 +765,17 @@ SILC_TASK_CALLBACK(silc_client_packet_parse_real)
   SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
   SilcClient client = (SilcClient)parse_ctx->context;
   SilcPacketContext *packet = parse_ctx->packet;
-  SilcBuffer buffer = packet->buffer;
   SilcSocketConnection sock = parse_ctx->sock;
   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
   int ret;
 
   SILC_LOG_DEBUG(("Start"));
 
-  /* Decrypt the received packet */
-  if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
-    ret = silc_packet_decrypt(conn->receive_key, conn->hmac_receive, 
-                             buffer, packet,
-                             silc_client_packet_decrypt_check, parse_ctx);
+  /* Parse the packet */
+  if (parse_ctx->normal)
+    ret = silc_packet_parse(packet, conn->receive_key);
   else
-    ret = silc_packet_decrypt(NULL, NULL, buffer, packet,
-                             silc_client_packet_decrypt_check, parse_ctx);
-
-  if (ret < 0)
-    goto out;
-
-  if (ret == 0) {
-    /* Parse the packet. Packet type is returned. */
-    ret = silc_packet_parse(packet);
-  } else {
-    /* Parse the packet header in special way as this is "special"
-       packet type. */
-    ret = silc_packet_parse_special(packet);
-  }
+    ret = silc_packet_parse_special(packet, conn->receive_key);
 
   if (ret == SILC_PACKET_NONE)
     goto out;
@@ -834,9 +792,15 @@ SILC_TASK_CALLBACK(silc_client_packet_parse_real)
 /* Parser callback called by silc_packet_receive_process. Thie merely
    registers timeout that will handle the actual parsing when appropriate. */
 
-void silc_client_packet_parse(SilcPacketParserContext *parser_context)
+void silc_client_packet_parse(SilcPacketParserContext *parser_context,
+                             void *context)
 {
-  SilcClient client = (SilcClient)parser_context->context;
+  SilcClient client = (SilcClient)context;
+  SilcSocketConnection sock = parser_context->sock;
+  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+
+  if (conn && conn->hmac_receive)
+    conn->psn_receive = parser_context->packet->sequence + 1;
 
   /* Parse the packet */
   silc_schedule_task_add(client->schedule, parser_context->sock->sock, 
@@ -1135,6 +1099,8 @@ void silc_client_packet_send(SilcClient client,
                             int force_send)
 {
   SilcPacketContext packetdata;
+  int block_len;
+  uint32 sequence = 0;
 
   if (!sock)
     return;
@@ -1153,8 +1119,13 @@ void silc_client_packet_send(SilcClient client,
       dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
       dst_id_type = SILC_ID_SERVER;
     }
+
+    if (hmac)
+      sequence = ((SilcClientConnection)sock->user_data)->psn_send++;
   }
 
+  block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
+
   /* Set the packet context pointers */
   packetdata.flags = 0;
   packetdata.type = type;
@@ -1180,7 +1151,7 @@ void silc_client_packet_send(SilcClient client,
   }
   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
     packetdata.src_id_len + packetdata.dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
 
   /* Prepare outgoing data buffer for packet sending */
   silc_packet_send_prepare(sock, 
@@ -1199,11 +1170,12 @@ void silc_client_packet_send(SilcClient client,
     silc_buffer_put(sock->outbuf, data, data_len);
 
   /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
+  silc_packet_assemble(&packetdata, cipher);
 
   /* Encrypt the packet */
   if (cipher)
-    silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+    silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, 
+                       sock->outbuf->len);
 
   SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
                   sock->outbuf->data, sock->outbuf->len);
@@ -1326,8 +1298,10 @@ void silc_client_close_connection(SilcClient client,
       silc_cipher_free(conn->send_key);
     if (conn->receive_key)
       silc_cipher_free(conn->receive_key);
-    if (conn->hmac_send)       /* conn->hmac_receive is same */
+    if (conn->hmac_send)
       silc_hmac_free(conn->hmac_send);
+    if (conn->hmac_receive)
+      silc_hmac_free(conn->hmac_receive);
     if (conn->pending_commands)
       silc_dlist_uninit(conn->pending_commands);
     if (conn->rekey)
index a2677b709ad0bf7dbe28d8bff3c0510272f63ea0..2275194be9b0e91d19691b543a8a4be8b38c86ee 100644 (file)
@@ -97,6 +97,8 @@ struct SilcClientConnectionStruct {
   SilcHmac hmac_send;
   SilcHmac hmac_receive;
   SilcHash hash;
+  uint32 psn_send;
+  uint32 psn_receive;
 
   /* Client ID and Channel ID cache. Messages transmitted in SILC network
      are done using different unique ID's. These are the cache for
index d08b3da00e8ed81986dd0003228302ca98ee66b7..8bc011e1155d5626cdb833e5ecabd2ac6dc58116 100644 (file)
@@ -49,6 +49,7 @@ void silc_client_send_channel_message(SilcClient client,
   SilcHmac hmac;
   unsigned char *id_string;
   uint32 iv_len;
+  int block_len;
 
   SILC_LOG_DEBUG(("Sending packet to channel"));
 
@@ -86,6 +87,8 @@ void silc_client_send_channel_message(SilcClient client,
   if (!cipher || !hmac)
     return;
 
+  block_len = silc_cipher_get_block_len(cipher);
+
   /* Generate IV */
   iv_len = silc_cipher_get_block_len(cipher);
   if (channel->iv[0] == '\0')
@@ -118,7 +121,7 @@ void silc_client_send_channel_message(SilcClient client,
     packetdata.src_id_len + packetdata.dst_id_len;
   packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
                                          packetdata.src_id_len +
-                                         packetdata.dst_id_len));
+                                         packetdata.dst_id_len), block_len);
 
   /* Prepare outgoing data buffer for packet sending */
   silc_packet_send_prepare(sock, 
@@ -134,11 +137,12 @@ void silc_client_send_channel_message(SilcClient client,
   silc_buffer_put(sock->outbuf, payload->data, payload->len);
 
   /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
+  silc_packet_assemble(&packetdata, cipher);
 
   /* Encrypt the header and padding of the packet. This is encrypted 
      with normal session key shared with our server. */
-  silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+  silc_packet_encrypt(cipher, hmac, conn->psn_send++,
+                     sock->outbuf, SILC_PACKET_HEADER_LEN + 
                      packetdata.src_id_len + packetdata.dst_id_len +
                      packetdata.padlen);
 
index 3da26c854a1ebc00f453a6a62fbd189d2cd647a2..d9f2e65d4d02e8bc5ad09b91e92833e382ce00a8 100644 (file)
@@ -45,6 +45,7 @@ void silc_client_send_private_message(SilcClient client,
   SilcPacketContext packetdata;
   SilcCipher cipher;
   SilcHmac hmac;
+  int block_len;
 
   SILC_LOG_DEBUG(("Sending private message"));
 
@@ -69,6 +70,7 @@ void silc_client_send_private_message(SilcClient client,
   /* Get data used in the encryption */
   cipher = client_entry->send_key;
   hmac = conn->hmac_send;
+  block_len = silc_cipher_get_block_len(cipher);
 
   /* Set the packet context pointers. */
   packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
@@ -83,7 +85,7 @@ void silc_client_send_private_message(SilcClient client,
     packetdata.src_id_len + packetdata.dst_id_len;
   packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
                                          packetdata.src_id_len +
-                                         packetdata.dst_id_len));
+                                         packetdata.dst_id_len), block_len);
 
   /* Prepare outgoing data buffer for packet sending */
   silc_packet_send_prepare(sock, 
@@ -99,11 +101,12 @@ void silc_client_send_private_message(SilcClient client,
   silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
 
   /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
+  silc_packet_assemble(&packetdata, cipher);
 
   /* Encrypt the header and padding of the packet. */
   cipher = conn->send_key;
-  silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+  silc_packet_encrypt(cipher, hmac, conn->psn_send++,
+                     sock->outbuf, SILC_PACKET_HEADER_LEN + 
                      packetdata.src_id_len + packetdata.dst_id_len +
                      packetdata.padlen);
 
index 51ee452cc555f6b331d7478ee3aef8e8bd00793a..ef570d8159118d0ddd60e72cd10bfe1527407354 100644 (file)
@@ -121,15 +121,19 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske,
   /* Allocate cipher to be used in the communication */
   silc_cipher_alloc(cipher->cipher->name, &conn->send_key);
   silc_cipher_alloc(cipher->cipher->name, &conn->receive_key);
-
-  conn->send_key->cipher->set_key(conn->send_key->context, 
-                                keymat->send_enc_key, 
-                                keymat->enc_key_len);
-  conn->send_key->set_iv(conn->send_key, keymat->send_iv);
-  conn->receive_key->cipher->set_key(conn->receive_key->context, 
-                                   keymat->receive_enc_key, 
-                                   keymat->enc_key_len);
-  conn->receive_key->set_iv(conn->receive_key, keymat->receive_iv);
+  silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &conn->hmac_send);
+  silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &conn->hmac_receive);
+
+  silc_cipher_set_key(conn->send_key, keymat->send_enc_key, 
+                     keymat->enc_key_len);
+  silc_cipher_set_iv(conn->send_key, keymat->send_iv);
+  silc_cipher_set_key(conn->receive_key, keymat->receive_enc_key, 
+                     keymat->enc_key_len);
+  silc_cipher_set_iv(conn->receive_key, keymat->receive_iv);
+  silc_hmac_set_key(conn->hmac_send, keymat->send_hmac_key, 
+                   keymat->hmac_key_len);
+  silc_hmac_set_key(conn->hmac_receive, keymat->receive_hmac_key, 
+                   keymat->hmac_key_len);
 
   /* Rekey stuff */
   conn->rekey = silc_calloc(1, sizeof(*conn->rekey));
@@ -144,11 +148,6 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske,
     conn->rekey->pfs = TRUE;
   conn->rekey->ske_group = silc_ske_group_get_number(group);
 
-  /* Save HMAC key to be used in the communication. */
-  silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &conn->hmac_send);
-  silc_hmac_set_key(conn->hmac_send, keymat->hmac_key, keymat->hmac_key_len);
-  conn->hmac_receive = conn->hmac_send;
-
   /* Save the HASH function */
   silc_hash_alloc(hash->hash->name, &conn->hash);
 }
@@ -750,33 +749,31 @@ silc_client_protocol_rekey_validate(SilcClient client,
       silc_cipher_set_key(conn->send_key, keymat->receive_enc_key, 
                          keymat->enc_key_len);
       silc_cipher_set_iv(conn->send_key, keymat->receive_iv);
+      silc_hmac_set_key(conn->hmac_send, keymat->receive_hmac_key, 
+                       keymat->hmac_key_len);
     } else {
       silc_cipher_set_key(conn->receive_key, keymat->send_enc_key, 
                          keymat->enc_key_len);
       silc_cipher_set_iv(conn->receive_key, keymat->send_iv);
+      silc_hmac_set_key(conn->hmac_receive, keymat->send_hmac_key, 
+                       keymat->hmac_key_len);
     }
   } else {
     if (send) {
       silc_cipher_set_key(conn->send_key, keymat->send_enc_key, 
                          keymat->enc_key_len);
       silc_cipher_set_iv(conn->send_key, keymat->send_iv);
+      silc_hmac_set_key(conn->hmac_send, keymat->send_hmac_key, 
+                       keymat->hmac_key_len);
     } else {
       silc_cipher_set_key(conn->receive_key, keymat->receive_enc_key, 
                          keymat->enc_key_len);
       silc_cipher_set_iv(conn->receive_key, keymat->receive_iv);
+      silc_hmac_set_key(conn->hmac_receive, keymat->receive_hmac_key, 
+                       keymat->hmac_key_len);
     }
   }
 
-  if (send) {
-    silc_hmac_alloc((char *)silc_hmac_get_name(conn->hmac_receive), NULL, 
-                   &conn->hmac_send);
-    silc_hmac_set_key(conn->hmac_send, keymat->hmac_key, 
-                     keymat->hmac_key_len);
-  } else {
-    silc_hmac_free(conn->hmac_receive);
-    conn->hmac_receive = conn->hmac_send;
-  }
-
   /* Save the current sending encryption key */
   if (!send) {
     memset(conn->rekey->send_enc_key, 0, conn->rekey->enc_key_len);
index dab8a83b0b3ff73952b6d80b1584fdf9bac5502e..1edd0bcf6a0ac3e700ddbd3d0bdf5b02dd060c74 100644 (file)
@@ -334,7 +334,7 @@ SilcBuffer silc_channel_message_payload_encode(uint16 flags,
 {
   int i;
   SilcBuffer buffer;
-  uint32 len, pad_len, mac_len;
+  uint32 len, pad_len, mac_len, block_len;
   unsigned char pad[SILC_PACKET_MAX_PADLEN];
   unsigned char mac[32];
 
@@ -343,8 +343,9 @@ SilcBuffer silc_channel_message_payload_encode(uint16 flags,
   /* Calculate length of padding. IV is not included into the calculation
      since it is not encrypted. */
   mac_len = silc_hmac_len(hmac);
+  block_len = silc_cipher_get_block_len(cipher);
   len = 6 + data_len + mac_len;
-  pad_len = SILC_PACKET_PADLEN((len + 2));
+  pad_len = SILC_PACKET_PADLEN(len, block_len);
 
   /* Allocate channel payload buffer */
   len += pad_len + iv_len;
index 28349d51783dacb2e9c19e16d618ab327a1bac10..f21ae66a900a9d19f2c6be8b6761d53a42cc8861 100644 (file)
@@ -76,7 +76,7 @@ int silc_packet_send(SilcSocketConnection sock, bool force_send)
    other process of HMAC computing and encryption is needed this function
    cannot be used. */
 
-void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, 
+void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, uint32 sequence,
                         SilcBuffer buffer, uint32 len)
 {
   unsigned char mac[32];
@@ -86,20 +86,34 @@ void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac,
      data area thus this uses the length found in buffer, not the length
      sent as argument. */
   if (hmac) {
+    unsigned char psn[4];
+
     silc_hmac_init(hmac);
+
+    /* XXX Backwards support for old MAC computation.
+       XXX Remove in 0.7.x */
+    if (!silc_hmac_get_b(hmac)) {
+      SILC_PUT32_MSB(sequence, psn);
+      silc_hmac_update(hmac, psn, 4);
+    }
+
     silc_hmac_update(hmac, buffer->data, buffer->len);
     silc_hmac_final(hmac, mac, &mac_len);
     silc_buffer_put_tail(buffer, mac, mac_len);
     memset(mac, 0, sizeof(mac));
   }
 
-  /* Encrypt the data area of the packet. 2 bytes of the packet
-     are not encrypted. */
+  /* Encrypt the data area of the packet. */
   if (cipher) {
-    SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d (%d)", 
-                   cipher->cipher->name, len, len - 2));
-    cipher->cipher->encrypt(cipher->context, buffer->data + 2, 
-                           buffer->data + 2, len - 2, cipher->iv);
+    SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d", 
+                   cipher->cipher->name, len));
+    /* XXX Backwards support for 0.5.x 
+       XXX Remove in 0.7.x */
+    if (hmac && silc_hmac_get_b(hmac))
+      silc_cipher_encrypt(cipher, buffer->data + 2, buffer->data + 2, 
+                         len - 1, cipher->iv);
+    else
+      silc_cipher_encrypt(cipher, buffer->data, buffer->data, len, cipher->iv);
   }
 
   /* Pull the HMAC into the visible data area in the buffer */
@@ -130,10 +144,10 @@ void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac,
    ^                                   ^
    Start of assembled packet
 
-   Packet construct is as follows (* = won't be encrypted):
+   Packet construct is as follows:
 
    n bytes       SILC Header
-      2 bytes     Payload length  (*)
+      2 bytes     Payload length
       1 byte      Flags
       1 byte      Packet type
       2 bytes     Source ID Length
@@ -153,9 +167,10 @@ void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac,
 
 */
 
-void silc_packet_assemble(SilcPacketContext *ctx)
+void silc_packet_assemble(SilcPacketContext *ctx, SilcCipher cipher)
 {
   unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
+  int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
   int i;
 
   SILC_LOG_DEBUG(("Assembling outgoing packet"));
@@ -168,11 +183,14 @@ void silc_packet_assemble(SilcPacketContext *ctx)
       ctx->src_id_len + ctx->dst_id_len;
 
   /* Calculate the length of the padding. The padding is calculated from
-     the data that will be encrypted. As protocol states 3 first bytes
-     of the packet are not encrypted they are not included in the
-     padding calculation. */
-  if (!ctx->padlen)
-    ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
+     the data that will be encrypted. */
+  if (!ctx->padlen) {
+    ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen, block_len);
+    /* XXX backwards support for 0.5.x
+       XXX remove in 0.7.x */
+    if (cipher->back)
+      ctx->padlen = SILC_PACKET_PADLEN2(ctx->truelen, block_len);
+  }
 
   /* Put the start of the data section to the right place. */
   silc_buffer_push(ctx->buffer, SILC_PACKET_HEADER_LEN + 
@@ -272,36 +290,92 @@ void silc_packet_send_prepare(SilcSocketConnection sock,
 
 ******************************************************************************/
 
-/* Processes the received data. This checks the received data and 
-   calls parser callback that handles the actual packet decryption
-   and parsing. If more than one packet was received this calls the
-   parser multiple times. The parser callback will get context
-   SilcPacketParserContext that includes the packet and the `context'
-   sent to this function. */
+static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac, 
+                              uint32 sequence, SilcBuffer buffer, 
+                              bool normal);
+
+/* Receives packet from network and reads the data into connection's
+   incoming data buffer. If the data was read directly this returns the
+   read bytes, if error occured this returns -1, if the data could not
+   be read directly at this time this returns -2 in which case the data
+   should be read again at some later time, or If EOF occured this returns
+   0. */
+
+int silc_packet_receive(SilcSocketConnection sock)
+{
+  int ret;
+
+  SILC_LOG_DEBUG(("Receiving packet from %s:%d [%s]", sock->hostname,
+                 sock->port, 
+                 (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                  sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                  sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                  "Router")));
+
+  /* Read some data from connection */
+  ret = silc_socket_read(sock);
+
+  return ret;
+}
+
+/* Processes and decrypts the incmoing data, and calls parser callback
+   for each received packet that will handle the actual packet parsing.
+   If more than one packet was received this calls the parser multiple
+   times.  The parser callback will get context SilcPacketParserContext
+   that includes the packet and the `parser_context' sent to this
+   function. 
+   
+   The `local_is_router' indicates whether the caller is router server
+   in which case the receiving process of a certain packet types may
+   be special.  Normal server and client must set it to FALSE.  The
+   SilcPacketParserContext will indicate also whether the received
+   packet was normal or special packet. */
 
 void silc_packet_receive_process(SilcSocketConnection sock,
+                                bool local_is_router,
                                 SilcCipher cipher, SilcHmac hmac,
+                                uint32 sequence,
                                 SilcPacketParserCallback parser,
-                                void *context)
+                                void *parser_context)
 {
   SilcPacketParserContext *parse_ctx;
-  int packetlen, paddedlen, count, mac_len = 0;
+  int packetlen, paddedlen, mac_len = 0;
+  int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
 
-  /* We need at least 2 bytes of data to be able to start processing
-     the packet. */
-  if (sock->inbuf->len < 2)
+  if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN)
     return;
 
   if (hmac)
     mac_len = silc_hmac_len(hmac);
 
   /* Parse the packets from the data */
-  count = 0;
   while (sock->inbuf->len > 0) {
-    SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
-    paddedlen += 2;
-    count++;
 
+    /* Decrypt first 16 bytes of the packet */
+    if (!SILC_IS_INBUF_PENDING(sock) && cipher) {
+      /* XXX backwards support for 0.5.x
+        XXX remove in 0.7.x */
+      if (cipher->back)
+       silc_cipher_decrypt(cipher, sock->inbuf->data + 2, 
+                           sock->inbuf->data + 2, 
+                           SILC_PACKET_MIN_HEADER_LEN, cipher->iv);
+      else
+       silc_cipher_decrypt(cipher, sock->inbuf->data, sock->inbuf->data, 
+                           SILC_PACKET_MIN_HEADER_LEN, cipher->iv);
+    }
+
+    /* Get packet lenght and full packet length with padding */
+    SILC_PACKET_LENGTH(sock->inbuf, packetlen);
+    /* XXX backwards support for 0.5.x
+       XXX remove in 0.7.x */
+    if (cipher && cipher->back) {
+      paddedlen = packetlen + SILC_PACKET_PADLEN2(packetlen, block_len);
+      paddedlen += 2;
+    } else {
+      paddedlen = packetlen + SILC_PACKET_PADLEN(packetlen, block_len);
+    }
+
+    /* Sanity checks */
     if (packetlen < SILC_PACKET_MIN_LEN) {
       SILC_LOG_DEBUG(("Received invalid packet, dropped"));
       silc_buffer_clear(sock->inbuf);
@@ -309,86 +383,96 @@ void silc_packet_receive_process(SilcSocketConnection sock,
     }
 
     if (sock->inbuf->len < paddedlen + mac_len) {
-      SILC_LOG_DEBUG(("Received partial packet, waiting for the rest"));
+      SILC_LOG_DEBUG(("Received partial packet, waiting for the rest"
+                     "(%d < %d)", sock->inbuf->len, paddedlen + mac_len));
+      SILC_SET_INBUF_PENDING(sock);
       return;
     }
 
+    SILC_UNSET_INBUF_PENDING(sock);
     parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
     parse_ctx->packet = silc_packet_context_alloc();
     parse_ctx->packet->buffer = silc_buffer_alloc(paddedlen + mac_len);
+    parse_ctx->packet->sequence = sequence++;
     parse_ctx->sock = sock;
-    parse_ctx->context = context;
+    parse_ctx->context = parser_context;
 
     silc_buffer_pull_tail(parse_ctx->packet->buffer, 
                          SILC_BUFFER_END(parse_ctx->packet->buffer));
     silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data, 
-                   paddedlen + mac_len);
+                   paddedlen + mac_len);
+
+    SILC_LOG_HEXDUMP(("Incoming packet (%d) (%d bytes decrypted), len %d", 
+                     sequence - 1, block_len, paddedlen + mac_len),
+                    sock->inbuf->data, paddedlen + mac_len);
+
+    /* Check whether this is normal or special packet */
+    if (local_is_router) {
+      if (sock->inbuf->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
+         (sock->inbuf->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
+       parse_ctx->normal = FALSE;
+      else if (sock->inbuf->data[3] != SILC_PACKET_CHANNEL_MESSAGE || 
+              (sock->inbuf->data[3] == SILC_PACKET_CHANNEL_MESSAGE &&
+               sock->type == SILC_SOCKET_TYPE_ROUTER))
+       parse_ctx->normal = TRUE;
+    } else {
+      if (sock->inbuf->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
+         (sock->inbuf->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
+       parse_ctx->normal = FALSE;
+      else if (sock->inbuf->data[3] != SILC_PACKET_CHANNEL_MESSAGE)
+       parse_ctx->normal = TRUE;
+    }
 
-    SILC_LOG_HEXDUMP(("Incoming packet, len %d", 
-                     parse_ctx->packet->buffer->len),
-                    parse_ctx->packet->buffer->data
-                    parse_ctx->packet->buffer->len);
+    /* Decrypt rest of the packet */
+    if (cipher)
+      silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence
+                         parse_ctx->packet->buffer, parse_ctx->normal);
 
     /* Call the parser */
     if (parser)
-      (*parser)(parse_ctx);
+      (*parser)(parse_ctx, parser_context);
 
     /* Pull the packet from inbuf thus we'll get the next one
        in the inbuf. */
-    silc_buffer_pull(sock->inbuf, paddedlen);
-    if (hmac)
-      silc_buffer_pull(sock->inbuf, mac_len);
+    silc_buffer_pull(sock->inbuf, paddedlen + mac_len);
   }
 
   SILC_LOG_DEBUG(("Clearing inbound buffer"));
   silc_buffer_clear(sock->inbuf);
 }
 
-/* Receives packet from network and reads the data into connection's
-   incoming data buffer. If the data was read directly this returns the
-   read bytes, if error occured this returns -1, if the data could not
-   be read directly at this time this returns -2 in which case the data
-   should be read again at some later time, or If EOF occured this returns
-   0. */
-
-int silc_packet_receive(SilcSocketConnection sock)
-{
-  int ret;
-
-  SILC_LOG_DEBUG(("Receiving packet from %s:%d [%s]", sock->hostname,
-                 sock->port, 
-                 (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
-                  sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
-                  sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
-                  "Router")));
-
-  /* Read some data from connection */
-  ret = silc_socket_read(sock);
-
-  return ret;
-}
-
 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. This is called
    after packet has been totally decrypted and parsed. */
 
-static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer)
+static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer,
+                                uint32 sequence)
 {
   /* Check MAC */
   if (hmac) {
-    unsigned char mac[32];
+    unsigned char mac[32], psn[4];
     uint32 mac_len;
     
     SILC_LOG_DEBUG(("Verifying MAC"));
 
     /* Compute HMAC of packet */
+
     memset(mac, 0, sizeof(mac));
     silc_hmac_init(hmac);
+
+    /* XXX Backwards support for old MAC computation.
+       XXX Remove in 0.7.x */
+    if (!silc_hmac_get_b(hmac)) {
+      SILC_PUT32_MSB(sequence, psn);
+      silc_hmac_update(hmac, psn, 4);
+    }
+
     silc_hmac_update(hmac, buffer->data, buffer->len);
     silc_hmac_final(hmac, mac, &mac_len);
 
     /* Compare the HMAC's (buffer->tail has the packet's HMAC) */
     if (memcmp(mac, buffer->tail, mac_len)) {
       SILC_LOG_ERROR(("MAC failed"));
+      assert(FALSE);
       return FALSE;
     }
     
@@ -422,11 +506,17 @@ static int silc_packet_decrypt_rest(SilcCipher cipher, SilcHmac hmac,
     SILC_LOG_DEBUG(("Decrypting rest of the packet"));
 
     /* Decrypt rest of the packet */
-    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
-    cipher->cipher->decrypt(cipher->context, buffer->data + 2,
-                           buffer->data + 2, buffer->len - 2,
-                           cipher->iv);
-    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN);
+    /* XXX backwards support for 0.5.x
+       XXX remove in 0.7.x */
+    if (cipher->back)
+      silc_cipher_decrypt(cipher, buffer->data + 2, buffer->data + 2, 
+                         buffer->len - 2, 
+                         cipher->iv);
+    else
+      silc_cipher_decrypt(cipher, buffer->data, buffer->data, buffer->len, 
+                         cipher->iv);
+    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN);
 
     SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d", buffer->len),
                     buffer->data, buffer->len);
@@ -447,7 +537,7 @@ static int silc_packet_decrypt_rest_special(SilcCipher cipher,
 {
   /* Decrypt rest of the header plus padding */
   if (cipher) {
-    uint16 truelen, len1, len2, padlen;
+    uint16 truelen, len1, len2, padlen, blocklen;
 
     /* Pull MAC from packet before decryption */
     if (hmac) {
@@ -464,21 +554,42 @@ static int silc_packet_decrypt_rest_special(SilcCipher cipher,
     SILC_GET16_MSB(len1, &buffer->data[4]);
     SILC_GET16_MSB(len2, &buffer->data[6]);
 
+    blocklen = silc_cipher_get_block_len(cipher);
     truelen = SILC_PACKET_HEADER_LEN + len1 + len2;
-    padlen = SILC_PACKET_PADLEN(truelen);
-    len1 = (truelen + padlen) - (SILC_PACKET_MIN_HEADER_LEN - 2);
 
-    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
-    if (len1 - 2 > buffer->len) {
-      SILC_LOG_DEBUG(("Garbage in header of packet, bad packet length, "
-                     "packet dropped"));
-      return FALSE;
-    }
+    /* XXX backwards support for 0.5.x
+       XXX remove in 0.7.x */
+    if (cipher->back) {
+      padlen = SILC_PACKET_PADLEN2(truelen, blocklen);
+      len1 = (truelen + padlen) - (SILC_PACKET_MIN_HEADER_LEN);
+      
+      silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN);
+
+      if (len1 - 2 > buffer->len) {
+       SILC_LOG_DEBUG(("Garbage in header of packet, bad packet length, "
+                       "packet dropped"));
+       return FALSE;
+      }
 
-    cipher->cipher->decrypt(cipher->context, buffer->data + 2,
-                           buffer->data + 2, len1 - 2,
-                           cipher->iv);
-    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+      silc_cipher_decrypt(cipher, buffer->data + 2, buffer->data + 2, 
+                         len1 - 2, cipher->iv);
+    } else {
+      blocklen = silc_cipher_get_block_len(cipher);
+      truelen = SILC_PACKET_HEADER_LEN + len1 + len2;
+      padlen = SILC_PACKET_PADLEN(truelen, blocklen);
+      len1 = (truelen + padlen) - SILC_PACKET_MIN_HEADER_LEN;
+      
+      silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN);
+
+      if (len1 > buffer->len) {
+       SILC_LOG_DEBUG(("Garbage in header of packet, bad packet length, "
+                       "packet dropped"));
+       return FALSE;
+      }
+      
+      silc_cipher_decrypt(cipher, buffer->data, buffer->data, len1, cipher->iv);
+    }
+    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN);
   }
 
   return TRUE;
@@ -498,31 +609,19 @@ static int silc_packet_decrypt_rest_special(SilcCipher cipher,
    the callback return TRUE the packet is normal and FALSE if the packet
    is special and requires special procesing. */
 
-int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
-                       SilcBuffer buffer, SilcPacketContext *packet,
-                       SilcPacketCheckDecrypt check_packet,
-                       void *context)
+static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
+                              uint32 sequence, SilcBuffer buffer, 
+                              bool normal)
 {
-  int check;
-
-  /* Decrypt start of the packet header */
-  if (cipher)
-    silc_cipher_decrypt(cipher, buffer->data + 2, buffer->data + 2, 
-                       SILC_PACKET_MIN_HEADER_LEN - 2, cipher->iv);
-
-  /* Do packet checking, whether the packet is normal or special */ 
-  check = check_packet((SilcPacketType)buffer->data[3], buffer,
-                      packet, context);
-
   /* If the packet type is not any special type lets decrypt rest
      of the packet here. */
-  if (check == TRUE) {
+  if (normal == TRUE) {
     /* Normal packet, decrypt rest of the packet */
     if (!silc_packet_decrypt_rest(cipher, hmac, buffer))
       return -1;
 
     /* Check MAC */
-    if (!silc_packet_check_mac(hmac, buffer))
+    if (!silc_packet_check_mac(hmac, buffer, sequence))
       return -1;
 
     return 0;
@@ -533,7 +632,7 @@ int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
       return -1;
 
     /* Check MAC */
-    if (!silc_packet_check_mac(hmac, buffer))
+    if (!silc_packet_check_mac(hmac, buffer, sequence))
       return -1;
 
     return 1;
@@ -546,10 +645,11 @@ int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
    function returns the type of the packet. The data section of the 
    buffer is parsed, not head or tail sections. */
 
-SilcPacketType silc_packet_parse(SilcPacketContext *ctx)
+SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher)
 {
   SilcBuffer buffer = ctx->buffer;
   int len, ret;
+  int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
 
   SILC_LOG_DEBUG(("Parsing incoming packet"));
 
@@ -573,12 +673,13 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx)
 
   if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
       ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
-    SILC_LOG_ERROR(("Bad ID lengths in packet"));
+    SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
+                   ctx->src_id_len, ctx->dst_id_len));
     return SILC_PACKET_NONE;
   }
 
   /* Calculate length of padding in packet */
-  ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
+  ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen, block_len);
 
   silc_buffer_pull(buffer, len);
   ret = silc_buffer_unformat(buffer, 
@@ -592,6 +693,15 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx)
   if (ret == -1)
     return SILC_PACKET_NONE;
 
+  /* XXX backwards support for 0.5.x
+     XXX remove in 0.7.x */
+  silc_buffer_pull(buffer, 
+                  ctx->src_id_len + 1 + ctx->dst_id_len + ctx->padlen);
+  SILC_LOG_DEBUG(("**************** %d", buffer->len));
+  if (buffer->len == 2)
+    ctx->padlen += 2;
+  silc_buffer_push(buffer, ret);
+
   silc_buffer_push(buffer, len);
 
   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
@@ -612,10 +722,12 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx)
    the header in a way that it does not take the data area into account
    and parses the header and padding area only. */
 
-SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
+SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
+                                        SilcCipher cipher)
 {
   SilcBuffer buffer = ctx->buffer;
   int len, tmplen, ret;
+  int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
 
   SILC_LOG_DEBUG(("Parsing incoming packet"));
 
@@ -634,12 +746,15 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
                             SILC_STR_UI_SHORT(&ctx->dst_id_len),
                             SILC_STR_UI_CHAR(&ctx->src_id_type),
                             SILC_STR_END);
-  if (len == -1)
+  if (len == -1) {
+    SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
     return SILC_PACKET_NONE;
+  }
 
   if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
       ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
-    SILC_LOG_ERROR(("Bad ID lengths in packet"));
+    SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
+                   ctx->src_id_len, ctx->dst_id_len));
     return SILC_PACKET_NONE;
   }
 
@@ -647,7 +762,12 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
      the data area is not used in the padding calculation as it won't
      be decrypted by the caller. */
   tmplen = SILC_PACKET_HEADER_LEN + ctx->src_id_len + ctx->dst_id_len;
-  ctx->padlen = SILC_PACKET_PADLEN(tmplen);
+  /* XXX backwards support for 0.5.x
+     XXX remove in 0.7.x */
+  if (ctx->back)
+    ctx->padlen = SILC_PACKET_PADLEN2(tmplen, block_len);
+  else
+    ctx->padlen = SILC_PACKET_PADLEN(tmplen, block_len);
 
   silc_buffer_pull(buffer, len);
   ret = silc_buffer_unformat(buffer, 
@@ -658,8 +778,10 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
                                                        ctx->dst_id_len),
                             SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
                             SILC_STR_END);
-  if (ret == -1)
+  if (ret == -1) {
+    SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
     return SILC_PACKET_NONE;
+  }
 
   silc_buffer_push(buffer, len);
 
index c8490b0b8bfb6e5ab20c719333302041c5703071..1e70334d00df1016ad4e4efd976b9aa03d558fcc 100644 (file)
 #define SILC_PACKET_DEFAULT_SIZE SILC_SOCKET_BUF_SIZE
 
 /* Header length without source and destination ID's. */
-#define SILC_PACKET_HEADER_LEN 8 + 2
+#define SILC_PACKET_HEADER_LEN 10
 
 /* Minimum length of SILC Packet Header. This much is decrypted always
    when packet is received to be able to get all the relevant data out
    from the header. */
-#define SILC_PACKET_MIN_HEADER_LEN 16 + 2
+#define SILC_PACKET_MIN_HEADER_LEN 16
 
 /* Maximum padding length */
 #define SILC_PACKET_MAX_PADLEN 16
@@ -227,6 +227,10 @@ typedef struct {
   int users;
 
   uint32 sequence;
+
+  /* XXX backwards support for 0.5.c
+     XXX remove in 0.7.x */
+  bool back;
 } SilcPacketContext;
 
 /****s* silccore/SilcPacketAPI/SilcPacketParserContext
@@ -237,10 +241,11 @@ typedef struct {
  *
  * DESCRIPTION
  *
- *    This context is used in packet reception when silc_packet_receive_process
- *    function calls parser callback that performs the actual packet decryption
- *    and parsing. This context is sent as argument to the parser function.
- *    This context must be free'd by the parser callback function.
+ *    This context is used in packet reception when the function
+ *    silc_packet_receive_process calls parser callback that performs
+ *    the actual packet decryption and parsing. This context is sent as
+ *    argument to the parser function. This context must be free'd by
+ *    the parser callback function.
  *
  *    Following description of the fields:
  *
@@ -250,6 +255,11 @@ typedef struct {
  *      context is not parsed, only the packet->buffer is allocated and
  *      it includes the raw packet data, which is encrypted.
  *
+ *    bool normal
+ *
+ *      Indicates whether the received packet is normal or special packet.
+ *      If special the parsing process is special also.
+ *
  *    SilcSocketConnection sock
  *
  *      The associated connection.
@@ -263,6 +273,7 @@ typedef struct {
  ***/
 typedef struct {
   SilcPacketContext *packet;
+  bool normal;
   SilcSocketConnection sock;
   void *context;
 } SilcPacketParserContext;
@@ -286,41 +297,7 @@ typedef struct {
  *
  ***/
 typedef void (*SilcPacketParserCallback)(SilcPacketParserContext 
-                                        *parse_context);
-
-/****f* silccore/SilcPacketAPI/SilcPacketCheckDecrypt
- *
- * SYNOPSIS
- *
- *    typedef int (*SilcPacketCheckDecrypt)(SilcPacketType packet_type,
- *                                          SilcBuffer buffer,
- *                                          SilcPacketContext *packet,
- *                                          void *context);
- *
- * DESCRIPTION
- *
- *    This callback function relates to the checking whether the packet is
- *    normal packet or special packet and how it should be processed.  If
- *    the callback returns TRUE the packet is normal and FALSE if the packet
- *    is special and requires special procesing. Some of the packets in
- *    SILC are special (like channel message packets that are encrypted
- *    using channel specific keys) and requires special processing. That
- *    is the reason for this callback function.
- *
- *    The library will call this function if provided for the
- *    silc_packet_decrypt function. The `packet_type' is the type of
- *    packet received (this is also actually the first time application
- *    receives information of the received packet, next time it receives
- *    it is when the SilcPacketParserCallback function is called),
- *    the `buffer' is the raw packet data the `packet' the allocated
- *    SilcPacketContext that is filled when parsing the packet and `context'
- *    is application specific user context.
- *
- ***/
-typedef int (*SilcPacketCheckDecrypt)(SilcPacketType packet_type,
-                                     SilcBuffer buffer,
-                                     SilcPacketContext *packet,
-                                     void *context);
+                                        *parse_context, void *context);
 
 /* Macros */
 
@@ -332,17 +309,15 @@ typedef int (*SilcPacketCheckDecrypt)(SilcPacketType packet_type,
  *
  * DESCRIPTION
  *
- *    Returns true length of the packet and padded length of the packet.
- *    This is primarily used by the libary in packet parsing phase but
- *    the application may use it as well if needed.
+ *    Returns true length of the packet. This is primarily used by the
+ *    libary in packet parsing phase but the application may use it as
+ *    well if needed.
  *
  * SOURCE
  */
-#define SILC_PACKET_LENGTH(__packet, __ret_truelen, __ret_padlen)           \
-do {                                                                        \
-  SILC_GET16_MSB((__ret_truelen), (__packet)->data);                        \
-  (__ret_padlen) = (((__ret_truelen) - 2) +                                 \
-                   SILC_PACKET_MAX_PADLEN) & ~(SILC_PACKET_MAX_PADLEN - 1); \
+#define SILC_PACKET_LENGTH(__packet, __ret_truelen)    \
+do {                                                   \
+  SILC_GET16_MSB((__ret_truelen), (__packet)->data);   \
 } while(0)
 /***/
 
@@ -359,10 +334,17 @@ do {                                                                           \
  *
  * SOURCE
  */
-#define SILC_PACKET_PADLEN(__packetlen)                                         \
-  SILC_PACKET_MAX_PADLEN - ((__packetlen) - 2) % SILC_PACKET_MAX_PADLEN;
+#define SILC_PACKET_PADLEN(__packetlen, __blocklen)            \
+  SILC_PACKET_MAX_PADLEN - (__packetlen) %                     \
+    ((__blocklen) ? (__blocklen) : SILC_PACKET_MAX_PADLEN)
 /***/
 
+/* XXX Backwards support for 0.5.x
+   XXX Remove in 0.7.x */
+#define SILC_PACKET_PADLEN2(__packetlen, __blocklen)           \
+  SILC_PACKET_MAX_PADLEN - ((__packetlen) - 2 ) %              \
+    ((__blocklen) ? (__blocklen) : SILC_PACKET_MAX_PADLEN)
+
 /* Prototypes */
 
 /****f* silccore/SilcPacketAPI/silc_packet_send
@@ -401,7 +383,7 @@ int silc_packet_send(SilcSocketConnection sock, bool force_send);
  *    cannot be used. 
  *
  ***/
-void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, 
+void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, uint32 sequence,
                         SilcBuffer buffer, uint32 len);
 
 /****f* silccore/SilcPacketAPI/silc_packet_assemble
@@ -457,7 +439,7 @@ void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac,
  *    the packet.
  *
  ***/
-void silc_packet_assemble(SilcPacketContext *ctx);
+void silc_packet_assemble(SilcPacketContext *ctx, SilcCipher cipher);
 
 /****f* silccore/SilcPacketAPI/silc_packet_send_prepare
  *
@@ -499,60 +481,38 @@ void silc_packet_send_prepare(SilcSocketConnection sock,
  ***/
 int silc_packet_receive(SilcSocketConnection sock);
 
-/****f* silccore/SilcPacketAPI/silc_packet_decrypt
- *
- * SYNOPSIS
- *
- *    int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
- *                            SilcBuffer buffer, SilcPacketContext *packet,
- *                            SilcPacketCheckDecrypt check_packet,
- *                            void *context);
- *
- * DESCRIPTION
- *
- *    Decrypts a packet. This assumes that typical SILC packet is the
- *    packet to be decrypted and thus checks for normal and special SILC
- *    packets and can handle both of them. This also computes and checks
- *    the HMAC of the packet. If any other special or customized decryption
- *    processing is required this function cannot be used. This returns
- *    -1 on error, 0 when packet is normal packet and 1 when the packet
- *    is special and requires special processing. 
- *
- *    The `check_packet' is a callback funtion that this function will 
- *    call.  The callback relates to the checking whether the packet is
- *    normal packet or special packet and how it should be processed.  If
- *    the callback return TRUE the packet is normal and FALSE if the packet
- *    is special and requires special procesing.
- *
- ***/
-int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
-                       SilcBuffer buffer, SilcPacketContext *packet,
-                       SilcPacketCheckDecrypt check_packet,
-                       void *context);
-
 /****f* silccore/SilcPacketAPI/silc_packet_receive_process
  *
  * SYNOPSIS
  *
  *    void silc_packet_receive_process(SilcSocketConnection sock,
+ *                                     bool local_is_router,
  *                                     SilcCipher cipher, SilcHmac hmac,
  *                                     SilcPacketParserCallback parser,
- *                                     void *context);
+ *                                     void *parser_context);
  *
  * DESCRIPTION
  *
- *    Processes the received data. This checks the received data and 
- *    calls parser callback that handles the actual packet decryption
- *    and parsing. If more than one packet was received this calls the
- *    parser multiple times. The parser callback will get context
- *    SilcPacketParserContext that includes the packet and the `context'
- *    sent to this function.
+ *    Processes and decrypts the incmoing data, and calls parser callback
+ *    for each received packet that will handle the actual packet parsing.
+ *    If more than one packet was received this calls the parser multiple
+ *    times.  The parser callback will get context SilcPacketParserContext
+ *    that includes the packet and the `parser_context' sent to this
+ *    function. 
+ *
+ *    The `local_is_router' indicates whether the caller is router server
+ *    in which case the receiving process of a certain packet types may
+ *    be special.  Normal server and client must set it to FALSE.  The
+ *    SilcPacketParserContext will indicate also whether the received
+ *    packet was normal or special packet.
  *
  ***/
 void silc_packet_receive_process(SilcSocketConnection sock,
+                                bool local_is_router,
                                 SilcCipher cipher, SilcHmac hmac,
+                                uint32 sequence,
                                 SilcPacketParserCallback parser,
-                                void *context);
+                                void *parser_context);
 
 /****f* silccore/SilcPacketAPI/silc_packet_parse
  *
@@ -569,7 +529,7 @@ void silc_packet_receive_process(SilcSocketConnection sock,
  *    buffer is parsed, not head or tail sections.
  *
  ***/
-SilcPacketType silc_packet_parse(SilcPacketContext *ctx);
+SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher);
 
 /****f* silccore/SilcPacketAPI/silc_packet_parse_special
  *
@@ -586,7 +546,8 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx);
  *    and parses the header and padding area only.
  *
  ***/
-SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx);
+SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
+                                        SilcCipher cipher);
 
 /****f* silccore/SilcPacketAPI/silc_packet_context_alloc
  *
index c828a8f77facb87c5608fd4643b14710d2a0cf3f..64c6f4d9c5a6caf1f9a83838a7d18c3330cbdcf8 100644 (file)
@@ -90,7 +90,7 @@ SilcBuffer silc_private_message_payload_encode(uint16 flags,
 {
   int i;
   SilcBuffer buffer;
-  uint32 len, pad_len = 0;
+  uint32 len, pad_len = 0, block_len;
   unsigned char pad[SILC_PACKET_MAX_PADLEN];
 
   SILC_LOG_DEBUG(("Encoding private message payload"));
@@ -99,7 +99,8 @@ SilcBuffer silc_private_message_payload_encode(uint16 flags,
 
   if (cipher) {
     /* Calculate length of padding. */
-    pad_len = SILC_PACKET_PADLEN((len + 2));
+    block_len = silc_cipher_get_block_len(cipher);
+    pad_len = SILC_PACKET_PADLEN(len, block_len);
     len += pad_len;
 
     /* Generate padding */
index 709c84113b50f49dc3f2f809434e90ee6ab9b3ee..fb3ec2576a391437cb92b6860b5f1190957dbdc3 100644 (file)
@@ -64,6 +64,10 @@ typedef struct SilcCipherStruct {
   void *context;
   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
 
+  /* XXX Backwards support for 0.5.x
+     XXX Remove in 0.7.x */
+  bool back;
+
   void (*set_iv)(struct SilcCipherStruct *, const unsigned char *);
   void (*get_iv)(struct SilcCipherStruct *, unsigned char *);
   uint32 (*get_key_len)(struct SilcCipherStruct *);
index 77dce315b4693961ee662c34300b4eb7dac9f15b..6293cea6757176f65c1dbf0a3042ccb9c50b4b2a 100644 (file)
@@ -32,6 +32,10 @@ struct SilcHmacStruct {
   unsigned char inner_pad[64];
   unsigned char outer_pad[64];
   void *hash_context;
+
+  /* XXX backwards thingy for 0.5.x MAC computation.
+     XXX Remove in 0.7.x */
+  bool backwards_support;
 };
 
 /* List of dynamically registered HMACs. */
@@ -394,3 +398,13 @@ void silc_hmac_final(SilcHmac hmac, unsigned char *return_hash,
   if (return_len)
     *return_len = hmac->hmac->len;
 }
+
+void silc_hmac_set_b(SilcHmac hmac)
+{
+  hmac->backwards_support = TRUE;
+}
+
+bool silc_hmac_get_b(SilcHmac hmac)
+{
+  return hmac->backwards_support;
+}
index 286ccdf8a7873298cfd196841eab26aa7f621909..a94d2b167d84a3f660270dd1565acba8e13e6a1c 100644 (file)
@@ -415,4 +415,7 @@ void silc_hmac_update(SilcHmac hmac, const unsigned char *data,
 void silc_hmac_final(SilcHmac hmac, unsigned char *return_hash,
                     uint32 *return_len);
 
+void silc_hmac_set_b(SilcHmac hmac);
+bool silc_hmac_get_b(SilcHmac hmac);
+
 #endif
index cacdb3d66d1b43be2f9d5e82cbe54210b425a3a2..0a56e96c70ed0ba79afd75adfd6f96392bd8f885 100644 (file)
@@ -1813,13 +1813,19 @@ silc_ske_process_key_material_data(unsigned char *data,
     key->enc_key_len = req_enc_key_len;
   }
 
-  /* Take HMAC key */
+  /* Take HMAC keys */
   memset(hashd, 0, sizeof(hashd));
   buf->data[0] = 4;
   silc_hash_make(hash, buf->data, buf->len, hashd);
-  key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
-  memcpy(key->hmac_key, hashd, req_hmac_key_len);
+  key->send_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
+  memcpy(key->send_hmac_key, hashd, req_hmac_key_len);
+  memset(hashd, 0, sizeof(hashd));
+  buf->data[0] = 5;
+  silc_hash_make(hash, buf->data, buf->len, hashd);
+  key->receive_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
+  memcpy(key->receive_hmac_key, hashd, req_hmac_key_len);
   key->hmac_key_len = req_hmac_key_len;
+  memset(hashd, 0, sizeof(hashd));
 
   silc_buffer_free(buf);
 
@@ -1856,6 +1862,14 @@ SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
                                              req_hmac_key_len, 
                                              ske->prop->hash, key);
 
+  /* Backwards support for old MAC keys */
+  /* XXX Remove in 0.7.x */
+  if (ske->backward_version == 1) {
+    silc_free(key->receive_hmac_key);
+    key->receive_hmac_key = silc_calloc(1, sizeof(*key->receive_hmac_key));
+    memcpy(key->receive_hmac_key, key->send_hmac_key, key->hmac_key_len);
+  }
+
   memset(tmpbuf, 0, klen);
   silc_free(tmpbuf);
   silc_buffer_free(buf);
@@ -1882,9 +1896,13 @@ void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
     memset(key->receive_enc_key, 0, key->enc_key_len / 8);
     silc_free(key->receive_enc_key);
   }
-  if (key->hmac_key) {
-    memset(key->hmac_key, 0, key->hmac_key_len);
-    silc_free(key->hmac_key);
+  if (key->send_hmac_key) {
+    memset(key->send_hmac_key, 0, key->hmac_key_len);
+    silc_free(key->send_hmac_key);
+  }
+  if (key->receive_hmac_key) {
+    memset(key->receive_hmac_key, 0, key->hmac_key_len);
+    silc_free(key->receive_hmac_key);
   }
   silc_free(key);
 }
index 62c221c0becbc02e3281942a284dc84cb3c2b5b8..85c78657e9c02362284c621baf1858aabf0b291c 100644 (file)
@@ -101,7 +101,8 @@ typedef struct {
   unsigned char *send_enc_key;
   unsigned char *receive_enc_key;
   uint32 enc_key_len;
-  unsigned char *hmac_key;
+  unsigned char *send_hmac_key;
+  unsigned char *receive_hmac_key;
   uint32 hmac_key_len;
 } SilcSKEKeyMaterial;
 
@@ -178,6 +179,9 @@ struct SilcSKEStruct {
 
   /* SKE callbacks. */
   SilcSKECallbacks callbacks;
+
+  /* Backwards support version indicator */
+  uint32 backward_version;
 };
 
 /* Prototypes */