Protocol 1.2 integration continues.
authorPekka Riikonen <priikone@silcnet.org>
Mon, 11 Nov 2002 19:38:53 +0000 (19:38 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 11 Nov 2002 19:38:53 +0000 (19:38 +0000)
CHANGES
apps/silcd/packet_send.c
apps/silcd/serverconfig.c
doc/draft-riikonen-silc-pp-06.nroff
lib/silccore/silcchannel.c
lib/silccore/silcchannel.h
lib/silccore/silcpacket.c
lib/silccore/silcpacket.h

diff --git a/CHANGES b/CHANGES
index a456d060e6cc5a3eab5849f1ba3714cf45c8fb7e..d7bcc8ef4b8cd9d3dc01efac8f671ca901c5b2b7 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,12 @@
+Mon Nov 11 19:32:00 EET 2002  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added Encrypt-Then-MAC order to SILC packet MAC generation.
+         Deprecated the old Encrypt-And-MAC order.  Updated protocol
+         specs and implemented.
+
+       * Added Encrypt-Then-MAC order to Channel Message Payload MAC
+         generation.  Updated specs and implemented.
+
 Sun Nov 10 12:20:56 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Added support for rekey before 2^32 sequence number wraps.
index 9113f68840de7bc55d4db9fc02b7ec9f4372b512..f9a7b2fe3c8da670fa64774a3c433080d9e8038d 100644 (file)
@@ -180,7 +180,8 @@ void silc_server_packet_send_dest(SilcServer server,
     cipher = idata->send_key;
     hmac = idata->hmac_send;
     sequence = idata->psn_send++;
-    block_len = silc_cipher_get_block_len(cipher);
+    if (cipher)
+      block_len = silc_cipher_get_block_len(cipher);
 
     /* Check for mandatory rekey */
     if (sequence == SILC_SERVER_REKEY_THRESHOLD)
@@ -758,9 +759,8 @@ silc_server_packet_relay_to_channel_encrypt(SilcServer server,
       return FALSE;
     }
 
-    memcpy(iv, data + (data_len - iv_len), iv_len);
-    silc_channel_message_payload_encrypt(data, data_len - iv_len - mac_len,
-                                        data_len, iv, iv_len,
+    memcpy(iv, data + (data_len - iv_len - mac_len), iv_len);
+    silc_channel_message_payload_encrypt(data, data_len - iv_len, iv, iv_len,
                                         channel->channel_key, channel->hmac);
   }
 
@@ -938,7 +938,8 @@ void silc_server_packet_relay_to_channel(SilcServer server,
 
          /* Decrypt the channel message (we don't check the MAC) */
          silc_channel_message_payload_decrypt(tmp, data_len,
-                                              channel->channel_key, NULL);
+                                              channel->channel_key,
+                                              channel->hmac, FALSE);
 
          /* Now re-encrypt and send it to the router */
          silc_server_packet_send_srcdest(server, sock,
index 0bd9ab57861f6b2acc6dc33489b0c366e2ed1480..7eba42e613e78942f928903eae2e3a0a6fd6ae1b 100644 (file)
@@ -1250,11 +1250,11 @@ SilcServerConfig silc_server_config_alloc(const char *filename)
 
   /* alloc a config object */
   config_new = silc_calloc(1, sizeof(*config_new));
-  config_new->refcount = 1;
   if (!config_new)
     return NULL;
 
   /* general config defaults */
+  config_new->refcount = 1;
   config_new->logging_timestamp = TRUE;
 
   /* obtain a config file object */
index 24e7690ead21ecdc78b16bf65c32583b33281e9d..fc4cbe72568ac7d49823a6b594cf73e0a7b75e80 100644 (file)
@@ -232,7 +232,7 @@ protocol.  The data payload area is always encrypted.
 
 The last part of SILC packet is the packet MAC that assures the
 integrity of the packet.  See the section 2.6 Packet MAC Generation
-for more information.  If compsession is used the compsession is
+for more information.  If compression is used the compsession is
 always applied before encryption.
 
 All fields in all packet payloads are always in MSB (most significant
@@ -1592,12 +1592,11 @@ o Error Message (variable length) - Human readable error
 .ti 0
 2.3.9 Channel Message Payload
 
-Channel messages are the most common messages sent in the SILC.
-Channel Message Payload is used to send message to channels.  These
-messages can only be sent if client has joined to some channel.
-Even though this packet is the most common in SILC it is still
-special packet.  Some special handling on sending and reception
-of channel message is required.
+Channel Message Payload is used to send message to channels, a group
+of users.  These messages can only be sent if client has joined to
+some channel.  Even though this packet is very common in SILC it
+is still special packet.  Some special handling on sending and
+reception of channel message is required.
 
 Padding MUST be applied into this payload since the payload is
 encrypted separately from other parts of the packet with the
@@ -1645,11 +1644,11 @@ represents the Channel Message Payload.
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                                                               |
-~                              MAC                              ~
+~                       Initial Vector *                        ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                                                               |
-~                       Initial Vector *                        ~
+~                              MAC *                            ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 .in 3
@@ -1749,27 +1748,24 @@ o Padding (variable length) - The padding that MUST be
   applied because this payload is encrypted separately from
   other parts of the packet.
 
+o Initial Vector (variable length) - The initial vector
+  that has been used in packet encryption.  It needs to be
+  used in the packet decryption as well.  Contents of this
+  field depends on the encryption algorithm and mode.  This
+  field is not encrypted, is not included in padding
+  calculation and its length equals to cipher's block size.
+  This field is authenticated by the channel message MAC.
+
 o MAC (variable length) - The MAC computed from the
   Message Flags, Message Length, Message Data, Padding Length,
-  Padding and Initial Vector fields in that order.  This
-  protects the integrity of the plaintext channel message.
-  The receiver can verify from the MAC whether the message
-  decrypted correctly.  Also, if more than one private key
+  Padding and Initial Vector fields in that order.  The MAC
+  is computed after the payload is encrypted.  This is so
+  called Encrypt-Then-MAC order; first encrypt, then compute
+  MAC from ciphertext.  The MAC protects the integrity of
+  the channel message.  Also, if more than one private key
   has been set for the channel, the receiver can verify which
-  of the keys decrypted the message correctly.  Note that,
-  this field is encrypted and MUST be added to the padding
-  calculation.
-
-o Initial Vector (variable length) - The initial vector
-  that has been used in packet encryption.  It needs to be
-  used in the packet decryption as well.  What this field
-  includes is implementation issue.  However, it is 
-  RECOMMENDED that it would be random data, or perhaps
-  a timestamp.  It is NOT RECOMMENDED to use zero (0) as an
-  initial vector.  This field is not encrypted.  This field
-  is not included into the padding calculation.  Length
-  of this field equals the cipher's block size.  This field
-  is, however authenticated.
+  of the keys must be used in decryption.  This field is not
+  encrypted.
 .in 3
 
 
@@ -1893,6 +1889,8 @@ The payload may only be sent with SILC_PACKET_PRIVATE_MESSAGE
 packet.  It MUST NOT be sent in any other packet type.  The following 
 diagram represents the Private Message Payload.
 
+(*) indicates that the field is not encrypted.
+
 
 .in 5
 .nf
@@ -1910,7 +1908,7 @@ diagram represents the Private Message Payload.
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                                                               |
-~                              MAC                              ~
+~                              MAC *                            ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 .in 3
@@ -1942,13 +1940,15 @@ o Padding (variable length) - This field is present only
 
 o MAC (variable length) - This field is present only when
   the private message payload is encrypted with private
-  message key. The MAC is computed from the Message Flags,
+  message key.  The MAC is computed from the Message Flags,
   Message Data Length, Message Data and Padding fields in
-  that order.  The MAC protects the integrity of the channel
+  that order.  The MAC protects the integrity of the private
   message.  The MAC is computed after encryption from the
-  ciphertext.  Note that, this field is not encrypted and
-  thus not included in the padding calculation.  When encrypted
-  with normal session keys, this field MUST NOT be included.
+  ciphertext.  This is so called Encrypt-Then-MAC order;
+  first encrypt, then compute MAC from ciphertext.  Note that,
+  this field is not encrypted and thus not included in the
+  padding calculation.  When encrypted with normal session
+  keys, this field MUST NOT be included.
 .in 3
 
 
@@ -2723,23 +2723,18 @@ of the message.
 Data integrity of a packet is protected by including a message
 authentication code (MAC) at the end of the packet.  The MAC is computed
 from shared secret MAC key, that is established by the SILC Key Exchange
-protocol, from packet sequence number, and from the original contents
-of the packet.  The MAC is always computed before the packet is
-encrypted, although after it is compressed if compression is used.
+protocol, from packet sequence number, and from the encrypted packet
+data.  The MAC is always computed after packet is encrypted.  This is
+so called Encrypt-Then-MAC order; packet is first encrypted, then MAC
+is computed from the encrypted data.
 
 The MAC is computed from entire packet.  Every bit of data in the packet,
 including SILC Packet Header is used in the MAC computing.  This way
 the entire packet becomes authenticated.
 
-If the packet is special packet MAC is computed from the entire packet
-but part of the packet may be encrypted before the MAC is computed.
-This is case, for example, with channel messages where the message data
-is encrypted with key that server may not now.  In this case the MAC
-has been computed from the encrypted data.
-
 Hence, packet's MAC generation is as follows:
 
-  mac = MAC(key, sequence number | SILC packet)
+  mac = MAC(key, sequence number | Encrypted SILC packet)
 
 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
@@ -2822,10 +2817,9 @@ channel it will be Channel ID.
 
 If the sender wants to compress the packet it MUST apply the
 compression now.  Sender MUST also compute the padding as described
-in above sections.  Then sender MUST compute the MAC of the packet.
-
-Then sender MUST encrypt the packet as has been described in above
-sections according whether the packet is normal packet or special
+in above sections.  Then sender MUST encrypt the packet as has been
+described in above sections according whether the packet is normal
+packet or special packet.  Then sender MUST compute the MAC of the
 packet.  The computed MAC MUST NOT be encrypted.
 
 
index adc857ee88c34449c406e164e43503811ebbbc8b..491743c5a5c70f418a42b0edaa807fc86d361613 100644 (file)
@@ -225,58 +225,38 @@ SilcUInt32 silc_channel_get_mode(SilcChannelPayload payload)
 bool silc_channel_message_payload_decrypt(unsigned char *data,
                                          size_t data_len,
                                          SilcCipher cipher,
-                                         SilcHmac hmac)
+                                         SilcHmac hmac,
+                                         bool check_mac)
 {
   SilcUInt32 iv_len, mac_len;
-  unsigned char *end, *mac, mac2[32];
-  unsigned char *dst, iv[SILC_CIPHER_MAX_IV_SIZE];
+  unsigned char *mac, mac2[32];
 
-  /* Push the IV out of the packet, and copy the IV since we do not want
-     to modify the original data buffer. */
-  end = data + data_len;
+  mac_len = silc_hmac_len(hmac);
   iv_len = silc_cipher_get_block_len(cipher);
-  memcpy(iv, end - iv_len, iv_len);
-
-  /* Allocate destination decryption buffer since we do not want to modify
-     the original data buffer, since we might want to call this function 
-     many times for same payload. */
-  if (hmac) {
-    dst = silc_calloc(data_len - iv_len, sizeof(*dst));
-    if (!dst)
-      return FALSE;
-  } else {
-    dst = data;
-  }
 
-  /* Decrypt the channel message */
-  silc_cipher_decrypt(cipher, data, dst, data_len - iv_len, iv);
+  if (data_len < mac_len)
+    return FALSE;
 
-  if (hmac) {
+  if (check_mac) {
     /* Take the MAC */
-    end = dst + (data_len - iv_len);
-    mac_len = silc_hmac_len(hmac);
-    mac = (end - mac_len);
+    mac = data + (data_len - mac_len);
 
     /* Check the MAC of the message */
-    SILC_LOG_DEBUG(("Checking channel message MACs"));
+    SILC_LOG_DEBUG(("Checking channel message MAC"));
     silc_hmac_init(hmac);
-    silc_hmac_update(hmac, dst, (data_len - iv_len - mac_len));
-    silc_hmac_update(hmac, data + (data_len - iv_len), iv_len);
+    silc_hmac_update(hmac, data, data_len - mac_len);
     silc_hmac_final(hmac, mac2, &mac_len);
     if (memcmp(mac, mac2, mac_len)) {
-      SILC_LOG_DEBUG(("Channel message MACs does not match"));
-      silc_free(dst);
+      SILC_LOG_DEBUG(("Channel message MAC does not match"));
       return FALSE;
     }
     SILC_LOG_DEBUG(("MAC is Ok"));
-
-    /* Now copy the decrypted data into the buffer since it is verified
-       it decrypted correctly. */
-    memcpy(data, dst, data_len - iv_len);
-    memset(dst, 0, data_len - iv_len);
-    silc_free(dst);
   }
 
+  /* Decrypt the channel message */
+  silc_cipher_decrypt(cipher, data, data,
+                     data_len - iv_len - mac_len,
+                     data + (data_len - iv_len - mac_len));
   return TRUE;
 }
 
@@ -300,7 +280,7 @@ silc_channel_message_payload_parse(unsigned char *payload,
 
   /* Decrypt the payload */
   ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len,
-                                            cipher, hmac);
+                                            cipher, hmac, TRUE);
   if (ret == FALSE)
     return NULL;
 
@@ -318,8 +298,8 @@ silc_channel_message_payload_parse(unsigned char *payload,
                                                         &newp->data_len),
                             SILC_STR_UI16_NSTRING_ALLOC(&newp->pad, 
                                                         &newp->pad_len),
-                            SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
                             SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
+                            SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
                             SILC_STR_END);
   if (ret == -1)
     goto err;
@@ -350,7 +330,6 @@ silc_channel_message_payload_parse(unsigned char *payload,
 
 bool silc_channel_message_payload_encrypt(unsigned char *data,
                                          SilcUInt32 data_len,
-                                         SilcUInt32 true_len,
                                          unsigned char *iv,
                                          SilcUInt32 iv_len,
                                          SilcCipher cipher,
@@ -360,24 +339,19 @@ bool silc_channel_message_payload_encrypt(unsigned char *data,
   SilcUInt32 mac_len;
   SilcBufferStruct buf;
 
-  /* Compute the MAC of the channel message data */
+  /* Encrypt payload of the packet. This is encrypted with the channel key. */
+  silc_cipher_encrypt(cipher, data, data, data_len - iv_len, iv);
+
+  /* Compute the MAC of the encrypted channel message data */
   silc_hmac_init(hmac);
   silc_hmac_update(hmac, data, data_len);
-  silc_hmac_update(hmac, iv, iv_len);
   silc_hmac_final(hmac, mac, &mac_len);
 
   /* Put rest of the data to the payload */
-  silc_buffer_set(&buf, data, true_len);
+  silc_buffer_set(&buf, data, data_len + mac_len);
   silc_buffer_pull(&buf, data_len);
-  silc_buffer_format(&buf, 
-                    SILC_STR_UI_XNSTRING(mac, mac_len),
-                    SILC_STR_UI_XNSTRING(iv, iv_len),
-                    SILC_STR_END);
-
-  /* Encrypt payload of the packet. This is encrypted with the channel key. */
-  silc_cipher_encrypt(cipher, data, data, true_len - iv_len, iv);
+  silc_buffer_put(&buf, mac, mac_len);
 
-  memset(mac, 0, sizeof(mac));
   return TRUE;
 }
 
@@ -406,11 +380,11 @@ SilcBuffer silc_channel_message_payload_encode(SilcMessageFlags flags,
      since it is not encrypted. */
   mac_len = silc_hmac_len(hmac);
   data_len = SILC_CHANNEL_MESSAGE_DATALEN(data_len, mac_len + iv_len);
-  len = 6 + data_len + mac_len;
+  len = 6 + data_len;
   pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
 
   /* Allocate channel payload buffer */
-  len += pad_len + iv_len;
+  len += pad_len + iv_len + mac_len;
   buffer = silc_buffer_alloc(len);
   if (!buffer)
     return NULL;
@@ -423,20 +397,20 @@ SilcBuffer silc_channel_message_payload_encode(SilcMessageFlags flags,
   }
 
   /* Encode the Channel Message Payload */
-  silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
+  silc_buffer_pull_tail(buffer, 6 + data_len + pad_len + iv_len);
   silc_buffer_format(buffer, 
                     SILC_STR_UI_SHORT(flags),
                     SILC_STR_UI_SHORT(data_len),
                     SILC_STR_UI_XNSTRING(data, data_len),
                     SILC_STR_UI_SHORT(pad_len),
                     SILC_STR_UI_XNSTRING(pad, pad_len),
+                    SILC_STR_UI_XNSTRING(iv, iv_len),
                     SILC_STR_END);
 
   memset(pad, 0, sizeof(pad));
 
   if (!silc_channel_message_payload_encrypt(buffer->data, buffer->len,
-                                           buffer->truelen, iv, iv_len,
-                                           cipher, hmac)) {
+                                           iv, iv_len, cipher, hmac)) {
     silc_buffer_free(buffer);
     return NULL;
   }
index 23dfccf1db2b87714e385557ba012feb8d384c1e..ea280aa89817cac0779845e6807ce6bdd1ecaaba 100644 (file)
@@ -284,14 +284,14 @@ SilcUInt32 silc_channel_get_mode(SilcChannelPayload payload);
  *    For example server might need to call this directly in some 
  *    circumstances. The `cipher' is used to decrypt the payload.
  *
- *    If the `hmac' is no provided then the MAC of the channel message is
- *    not verified.
+ *    If `check_mac' is FALSE then MAC is not verified.
  *
  ***/
 bool silc_channel_message_payload_decrypt(unsigned char *data,
                                          size_t data_len,
                                          SilcCipher cipher,
-                                         SilcHmac hmac);
+                                         SilcHmac hmac,
+                                         bool check_mac);
 
 /****f* silccore/SilcChannelAPI/silc_channel_message_payload_parse
  *
@@ -325,7 +325,6 @@ silc_channel_message_payload_parse(unsigned char *payload,
  *
  *    bool silc_channel_message_payload_encrypt(unsigned char *data,
  *                                              SilcUInt32 data_len,
- *                                              SilcUInt32 true_len,
  *                                              unsigned char *iv,
  *                                              SilcUInt32 iv_len,
  *                                              SilcCipher cipher,
@@ -335,9 +334,8 @@ silc_channel_message_payload_parse(unsigned char *payload,
  *
  *    This function is used to encrypt the Channel Messsage Payload which is
  *    the `data' and `data_len'.  The `data_len' is the data length which is
- *    used to create MAC out of.  The `true_len' is the true length of `data'
- *    message payload and is used assemble rest of the packet after MAC
- *    creation. The `true_len' length packet will then be encrypted.
+ *    used to create MAC out of.  The `data' MUST have additional space
+ *    after `data_len' bytes for the MAC which is appended to the data.
  *
  *    This is usually used by the Channel Message interface itself but can
  *    be called by the appliation if separate encryption process is required.
@@ -347,7 +345,6 @@ silc_channel_message_payload_parse(unsigned char *payload,
  ***/
 bool silc_channel_message_payload_encrypt(unsigned char *data,
                                          SilcUInt32 data_len,
-                                         SilcUInt32 true_len,
                                          unsigned char *iv,
                                          SilcUInt32 iv_len,
                                          SilcCipher cipher,
index fe76866208d8dc32890bca3bee5092cc69c94e71..fbbb4a695ec34674ebc5705d1262bf2341aab2cb 100644 (file)
@@ -80,35 +80,32 @@ int silc_packet_send(SilcSocketConnection sock, bool force_send)
 void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, SilcUInt32 sequence,
                         SilcBuffer buffer, SilcUInt32 len)
 {
-  unsigned char mac[32];
-  SilcUInt32 mac_len;
 
-  /* Compute HMAC. This assumes that HMAC is created from the entire
+  /* Encrypt the data area of the packet. */
+  if (cipher) {
+    SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d", 
+                   silc_cipher_get_name(cipher), len));
+    silc_cipher_encrypt(cipher, buffer->data, buffer->data, len,
+                       silc_cipher_get_iv(cipher));
+  }
+
+  /* Compute HMAC. This assumes that MAC is computed from the entire
      data area thus this uses the length found in buffer, not the length
      sent as argument. */
   if (hmac) {
-    unsigned char psn[4];
+    unsigned char mac[32], psn[4];
+    SilcUInt32 mac_len;
 
     silc_hmac_init(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. */
-  if (cipher) {
-    SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d", 
-                   silc_cipher_get_name(cipher), len));
-    silc_cipher_encrypt(cipher, buffer->data, buffer->data, len,
-                       silc_cipher_get_iv(cipher));
-  }
 
-  /* Pull the HMAC into the visible data area in the buffer */
-  if (hmac)
+    /* Put MAC and pull the it into the visible data area in the buffer */
+    silc_buffer_put_tail(buffer, mac, mac_len);
     silc_buffer_pull_tail(buffer, mac_len);
+  }
 }
 
 /* Assembles a new packet to be ready for send out. */
@@ -258,6 +255,11 @@ bool silc_packet_send_prepare(SilcSocketConnection sock,
 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac, 
                               SilcUInt32 sequence, SilcBuffer buffer, 
                               bool normal);
+static bool silc_packet_check_mac(SilcHmac hmac,
+                                 const unsigned char *data,
+                                 SilcUInt32 data_len,
+                                 const unsigned char *packet_mac,
+                                 SilcUInt32 sequence);
 
 /* Receives packet from network and reads the data into connection's
    incoming data buffer. If the data was read directly this returns the
@@ -304,8 +306,10 @@ bool silc_packet_receive_process(SilcSocketConnection sock,
                                 void *parser_context)
 {
   SilcPacketParserContext *parse_ctx;
-  int packetlen, paddedlen, mac_len = 0;
+  int packetlen, paddedlen, mac_len = 0, ret, block_len;
   bool cont = TRUE;
+  unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
+  unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
 
   /* Do not process for disconnected connection */
   if (SILC_IS_DISCONNECTED(sock))
@@ -325,73 +329,95 @@ bool silc_packet_receive_process(SilcSocketConnection sock,
       return TRUE;
     }
 
-    /* Decrypt first 16 bytes of the packet */
-    if (!SILC_IS_INBUF_PENDING(sock) && cipher)
-      silc_cipher_decrypt(cipher, sock->inbuf->data, sock->inbuf->data, 
-                         SILC_PACKET_MIN_HEADER_LEN,
-                         silc_cipher_get_iv(cipher));
+    /* Decrypt first block of the packet to get the length field out */
+    if (cipher) {
+      block_len = silc_cipher_get_block_len(cipher);
+      memcpy(iv, silc_cipher_get_iv(cipher), block_len);
+      silc_cipher_decrypt(cipher, sock->inbuf->data, tmp, block_len, iv);
+      header = tmp;
+    } else {
+      block_len = SILC_PACKET_MIN_HEADER_LEN;
+      header = sock->inbuf->data;
+    }
 
     /* Get packet lenght and full packet length with padding */
-    SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
+    SILC_PACKET_LENGTH(header, packetlen, paddedlen);
 
     /* Sanity checks */
     if (packetlen < SILC_PACKET_MIN_LEN) {
-      SILC_LOG_ERROR(("Received invalid packet, dropped"));
+      SILC_LOG_ERROR(("Received too short packet"));
+      memset(header, 0, sizeof(header));
       silc_buffer_clear(sock->inbuf);
       return FALSE;
     }
 
     if (sock->inbuf->len < paddedlen + mac_len) {
-      SILC_LOG_DEBUG(("Received partial packet, waiting for the rest"
-                     "(%d < %d)", sock->inbuf->len, paddedlen + mac_len));
+      SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
+                     "(%d bytes)", paddedlen + mac_len - sock->inbuf->len));
       SILC_SET_INBUF_PENDING(sock);
+      memset(tmp, 0, sizeof(tmp));
       return TRUE;
     }
 
+    /* Check MAC of the packet */
+    if (!silc_packet_check_mac(hmac, sock->inbuf->data, paddedlen,
+                              sock->inbuf->data + paddedlen, sequence)) {
+      SILC_LOG_WARNING(("Packet MAC check failed %s:%d [%s] [%s]", 
+                       sock->hostname, sock->port,
+                       silc_get_packet_name(header[3]),
+                       (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                        sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                        sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                        "Router")));
+      memset(tmp, 0, sizeof(tmp));
+      silc_buffer_clear(sock->inbuf);
+      return FALSE;
+    }
+
     SILC_UNSET_INBUF_PENDING(sock);
     parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
     if (!parse_ctx)
       return FALSE;
     parse_ctx->packet = silc_packet_context_alloc();
-    parse_ctx->packet->buffer = silc_buffer_alloc(paddedlen + mac_len);
-    parse_ctx->packet->type = sock->inbuf->data[3];
-    parse_ctx->packet->padlen = sock->inbuf->data[4];
+    parse_ctx->packet->buffer = silc_buffer_alloc_size(paddedlen);
+    parse_ctx->packet->type = header[3];
+    parse_ctx->packet->padlen = header[4];
     parse_ctx->packet->sequence = sequence++;
     parse_ctx->sock = sock;
     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);
-
-    SILC_LOG_HEXDUMP(("Incoming packet (%d) (%dB decrypted), len %d", 
-                     sequence - 1, SILC_PACKET_MIN_HEADER_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))
+      if (header[3] == SILC_PACKET_PRIVATE_MESSAGE &&
+         (header[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 &&
+      else if (header[3] != SILC_PACKET_CHANNEL_MESSAGE || 
+              (header[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))
+      if (header[3] == SILC_PACKET_PRIVATE_MESSAGE &&
+         (header[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
        parse_ctx->normal = FALSE;
-      else if (sock->inbuf->data[3] != SILC_PACKET_CHANNEL_MESSAGE)
+      else if (header[3] != SILC_PACKET_CHANNEL_MESSAGE)
        parse_ctx->normal = TRUE;
     }
 
-    /* Decrypt rest of the packet */
-    if (cipher)
-      if (silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence, 
-                             parse_ctx->packet->buffer, 
-                             parse_ctx->normal) == -1) {
+    SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
+                     sequence - 1, paddedlen + mac_len),
+                    sock->inbuf->data, paddedlen + mac_len);
+
+    /* Put the decrypted part, and rest of the encrypted data, and decrypt */
+    silc_buffer_put(parse_ctx->packet->buffer, header, block_len);
+    silc_buffer_pull(parse_ctx->packet->buffer, block_len);
+    silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data + block_len,
+                   paddedlen - block_len);
+    if (cipher) {
+      silc_cipher_set_iv(cipher, iv);
+      ret = silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence, 
+                               parse_ctx->packet->buffer, 
+                               parse_ctx->normal);
+      if (ret < 0) {
        SILC_LOG_WARNING(("Packet decryption failed %s:%d [%s] [%s]", 
                          sock->hostname, sock->port,
                          silc_get_packet_name(parse_ctx->packet->type),
@@ -399,10 +425,18 @@ bool silc_packet_receive_process(SilcSocketConnection sock,
                           sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
                           sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
                           "Router")));
+       memset(tmp, 0, sizeof(tmp));
        silc_packet_context_free(parse_ctx->packet);
        silc_free(parse_ctx);
        return FALSE;
       }
+    }
+    silc_buffer_push(parse_ctx->packet->buffer, block_len);
+
+    SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d",
+                     parse_ctx->packet->buffer->len), 
+                    parse_ctx->packet->buffer->data,
+                    parse_ctx->packet->buffer->len);
 
     /* Pull the packet from inbuf thus we'll get the next one
        in the inbuf. */
@@ -410,6 +444,7 @@ bool silc_packet_receive_process(SilcSocketConnection sock,
 
     /* Call the parser */
     cont = (*parser)(parse_ctx, parser_context);
+    memset(tmp, 0, sizeof(tmp));
   }
 
   if (cont == FALSE && sock->inbuf->len > 0)
@@ -420,11 +455,13 @@ bool silc_packet_receive_process(SilcSocketConnection sock,
   return TRUE;
 }
 
-/* Checks MAC in the packet. Returns TRUE if MAC is Ok. This is called
-   after packet has been totally decrypted and parsed. */
+/* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
 
-static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer,
-                                SilcUInt32 sequence)
+static bool silc_packet_check_mac(SilcHmac hmac,
+                                 const unsigned char *data,
+                                 SilcUInt32 data_len,
+                                 const unsigned char *packet_mac,
+                                 SilcUInt32 sequence)
 {
   /* Check MAC */
   if (hmac) {
@@ -434,123 +471,26 @@ static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer,
     SILC_LOG_DEBUG(("Verifying MAC"));
 
     /* Compute HMAC of packet */
-
-    memset(mac, 0, sizeof(mac));
     silc_hmac_init(hmac);
     SILC_PUT32_MSB(sequence, psn);
     silc_hmac_update(hmac, psn, 4);
-    silc_hmac_update(hmac, buffer->data, buffer->len);
+    silc_hmac_update(hmac, data, data_len);
     silc_hmac_final(hmac, mac, &mac_len);
 
-    /* Compare the HMAC's (buffer->tail has the packet's HMAC) */
-    if (memcmp(buffer->tail, mac, mac_len)) {
+    /* Compare the MAC's */
+    if (memcmp(packet_mac, mac, mac_len)) {
       SILC_LOG_ERROR(("MAC failed"));
       return FALSE;
     }
     
     SILC_LOG_DEBUG(("MAC is Ok"));
-    memset(mac, 0, sizeof(mac));
   }
   
   return TRUE;
 }
 
-/* Decrypts rest of the packet (after decrypting just the SILC header).
-   After calling this function the packet is ready to be parsed by calling 
-   silc_packet_parse. If everything goes without errors this returns TRUE,
-   if packet is malformed this returns FALSE. */
-
-static int silc_packet_decrypt_rest(SilcCipher cipher, SilcHmac hmac,
-                                   SilcBuffer buffer)
-{
-  if (cipher) {
-
-    /* Pull MAC from packet before decryption */
-    if (hmac) {
-      if ((buffer->len - silc_hmac_len(hmac)) > SILC_PACKET_MIN_LEN) {
-       silc_buffer_push_tail(buffer, silc_hmac_len(hmac));
-      } else {
-       SILC_LOG_ERROR(("Bad MAC length in packet, packet dropped"));
-       return FALSE;
-      }
-    }
-
-    SILC_LOG_DEBUG(("Decrypting rest of the packet"));
-
-    /* Decrypt rest of the packet */
-    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN);
-    silc_cipher_decrypt(cipher, buffer->data, buffer->data, buffer->len, 
-                       silc_cipher_get_iv(cipher));
-    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN);
-
-    SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d", buffer->len),
-                    buffer->data, buffer->len);
-  }
-
-  return TRUE;
-}
-
-/* Decrypts rest of the SILC Packet header that has been decrypted partly
-   already. This decrypts the padding of the packet also. After calling 
-   this function the packet is ready to be parsed by calling function 
-   silc_packet_parse. This is used in special packet reception (protocol
-   defines the way of decrypting special packets). */
-
-static int silc_packet_decrypt_rest_special(SilcCipher cipher,
-                                           SilcHmac hmac,
-                                           SilcBuffer buffer)
-{
-  /* Decrypt rest of the header plus padding */
-  if (cipher) {
-    SilcUInt16 len;
-
-    /* Pull MAC from packet before decryption */
-    if (hmac) {
-      if ((buffer->len - silc_hmac_len(hmac)) > SILC_PACKET_MIN_LEN) {
-       silc_buffer_push_tail(buffer, silc_hmac_len(hmac));
-      } else {
-       SILC_LOG_ERROR(("Bad MAC length in packet, packet dropped"));
-       return FALSE;
-      }
-    }
-  
-    SILC_LOG_DEBUG(("Decrypting rest of the header"));
-
-    /* padding length + src id len + dst id len + header length - 16
-       bytes already decrypted, gives the rest of the encrypted packet */
-    len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] + 
-          (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
-          SILC_PACKET_MIN_HEADER_LEN);
-
-    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN);
-    if (len > buffer->len) {
-      SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
-                     "packet dropped"));
-      return FALSE;
-    }
-    silc_cipher_decrypt(cipher, buffer->data, buffer->data, len,
-                       silc_cipher_get_iv(cipher));
-    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN);
-    SILC_LOG_HEXDUMP(("packet, len %d", buffer->len), 
-                    buffer->data, buffer->len);
-  }
-
-  return TRUE;
-}
-
-/* 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. */
+/* Decrypts SILC packet.  Handles both normal and special packet decryption.
+   Return 0 when packet is normal and 1 when it it special, -1 on error. */
 
 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
                               SilcUInt32 sequence, SilcBuffer buffer, 
@@ -559,24 +499,38 @@ static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
   /* If the packet type is not any special type lets decrypt rest
      of the packet here. */
   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, sequence))
-      return -1;
-
+    if (cipher) {
+      /* Decrypt rest of the packet */
+      SILC_LOG_DEBUG(("Decrypting the packet"));
+      silc_cipher_decrypt(cipher, buffer->data, buffer->data, buffer->len, 
+                         silc_cipher_get_iv(cipher));
+    }
     return 0;
+
   } else {
-    /* Packet requires special handling, decrypt rest of the header.
-       This only decrypts. */
-    if (!silc_packet_decrypt_rest_special(cipher, hmac, buffer))
-      return -1;
-
-    /* Check MAC */
-    if (!silc_packet_check_mac(hmac, buffer, sequence))
-      return -1;
+    /* Decrypt rest of the header plus padding */
+    if (cipher) {
+      SilcUInt16 len;
+      int block_len = silc_cipher_get_block_len(cipher);
+
+      SILC_LOG_DEBUG(("Decrypting the header"));
+
+      /* padding length + src id len + dst id len + header length - 16
+        bytes already decrypted, gives the rest of the encrypted packet */
+      silc_buffer_push(buffer, block_len);
+      len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] + 
+             (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
+            block_len);
+
+      if (len > buffer->len) {
+       SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
+                       "packet dropped"));
+       return -1;
+      }
+      silc_buffer_pull(buffer, block_len);
+      silc_cipher_decrypt(cipher, buffer->data, buffer->data, len,
+                         silc_cipher_get_iv(cipher));
+    }
 
     return 1;
   }
index 7d62a3b4210b754cada5dda1c3e50499ecad33ec..0e15ae438b714ae7a01584a78af24a23942f9d90 100644 (file)
@@ -332,10 +332,10 @@ typedef bool (*SilcPacketParserCallback)(SilcPacketParserContext
  *
  * SOURCE
  */
-#define SILC_PACKET_LENGTH(__packet, __ret_truelen, __ret_paddedlen)   \
-do {                                                                   \
-  SILC_GET16_MSB((__ret_truelen), (__packet)->data);                   \
-  (__ret_paddedlen) = (__ret_truelen) + (__packet)->data[4];           \
+#define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
+do {                                                                    \
+  SILC_GET16_MSB((__ret_truelen), (__packetdata));                      \
+  (__ret_paddedlen) = (__ret_truelen) + (__packetdata)[4];              \
 } while(0)
 /***/
 
@@ -375,12 +375,12 @@ do {                                                                      \
  *
  * SOURCE
  */
-#define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen)             \
-do {                                                                      \
-  __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) %                \
-             ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
-  if (__padlen < 8)                                                       \
-    __padlen = ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
+#define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen)              \
+do {                                                                       \
+  __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) %                 \
+             ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN));  \
+  if (__padlen < 8)                                                        \
+    __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
 } while(0)
 /***/