silc_stack_free can now be called with NULL stack
[silc.git] / lib / silccore / silcmessage.c
index e7f06c0ee2f158b0ab979c50e649ac2103019743..d1b43ee581bc03c7d0610ff431b13a79930129d5 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2006 Pekka Riikonen
+  Copyright (C) 1997 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -44,6 +44,8 @@ typedef struct {
   SilcHmac hmac;
   unsigned char *iv;
   SilcUInt16 payload_len;
+  SilcID *sid;
+  SilcID *rid;
 } SilcMessageEncode;
 
 
@@ -65,7 +67,7 @@ SilcUInt32 silc_message_payload_datalen(SilcUInt32 data_len,
                      silc_pkcs_private_key_get_len(private_key) / 8 : 0);
   SilcUInt32 dlen = data_len + SILC_MESSAGE_HLEN + header_len + pklen + prlen;
 
-  if (dlen > SILC_MESSAGE_MAX_LEN)
+  if (silc_unlikely(dlen > SILC_MESSAGE_MAX_LEN))
     data_len -= (dlen - SILC_MESSAGE_MAX_LEN);
 
   return data_len;
@@ -192,7 +194,7 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
     if (!pk)
       return NULL;
   }
-  pk_type = silc_pkcs_get_type(public_key);
+  pk_type = silc_pkcs_get_type(private_key);
 
   /* Encode the data to be signed */
   sign = silc_message_signed_encode_data(message_payload,
@@ -207,7 +209,8 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
 
   /* Compute the hash and the signature. */
   if (!silc_pkcs_sign(private_key, sign->data, silc_buffer_len(sign),
-                     auth_data, sizeof(auth_data) - 1, &auth_len, hash)) {
+                     auth_data, sizeof(auth_data) - 1, &auth_len,
+                     TRUE, hash)) {
     SILC_LOG_ERROR(("Could not compute signature"));
     silc_buffer_clear(sign);
     silc_buffer_free(sign);
@@ -267,6 +270,10 @@ SilcBool silc_message_payload_decrypt(unsigned char *data,
                                      SilcBool static_key,
                                      SilcCipher cipher,
                                      SilcHmac hmac,
+                                     unsigned char *sender_id,
+                                     SilcUInt32 sender_id_len,
+                                     unsigned char *receiver_id,
+                                     SilcUInt32 receiver_id_len,
                                      SilcBool check_mac)
 {
   SilcUInt32 mac_len, iv_len = 0, block_len;
@@ -281,18 +288,31 @@ SilcBool silc_message_payload_decrypt(unsigned char *data,
   if (!private_message || (private_message && static_key))
     iv_len = block_len;
 
-  if (data_len < (mac_len + iv_len + block_len))
+  if (silc_unlikely(data_len < (mac_len + iv_len + block_len)))
     return FALSE;
 
-  if (check_mac) {
+  if (silc_likely(check_mac)) {
     /* Check the MAC of the message */
     SILC_LOG_DEBUG(("Checking message MAC"));
     silc_hmac_init(hmac);
     silc_hmac_update(hmac, data, data_len - mac_len);
+    silc_hmac_update(hmac, sender_id, sender_id_len);
+    silc_hmac_update(hmac, receiver_id, receiver_id_len);
     silc_hmac_final(hmac, mac, &mac_len);
-    if (memcmp(data + (data_len - mac_len), mac, mac_len)) {
+    if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) {
+#if 0
       SILC_LOG_DEBUG(("Message MAC does not match"));
       return FALSE;
+#else
+      /* Check for old style message MAC.  Remove this check at some point. */
+      silc_hmac_init(hmac);
+      silc_hmac_update(hmac, data, data_len - mac_len);
+      silc_hmac_final(hmac, mac, &mac_len);
+      if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) {
+       SILC_LOG_DEBUG(("Message MAC does not match"));
+#endif
+       return FALSE;
+      }
     }
     SILC_LOG_DEBUG(("MAC is Ok"));
   }
@@ -306,7 +326,8 @@ SilcBool silc_message_payload_decrypt(unsigned char *data,
         silc_cipher_get_iv(cipher));
 
   /* Decrypt block */
-  if (!silc_cipher_decrypt(cipher, data, data, block_len, ivp)) {
+  if (silc_unlikely(!silc_cipher_decrypt(cipher, data, data, block_len,
+                                        ivp))) {
     SILC_ASSERT(FALSE);
     return FALSE;
   }
@@ -315,13 +336,14 @@ SilcBool silc_message_payload_decrypt(unsigned char *data,
   totlen = 2;
   SILC_GET16_MSB(len, data + totlen);
   totlen += 2 + len;
-  if (totlen + iv_len + mac_len + 2 > data_len)
+  if (silc_unlikely(totlen + iv_len + mac_len + 2 > data_len))
     return FALSE;
   totlen += 2;
   if (totlen >= block_len)
-    if (!silc_cipher_decrypt(cipher, data + block_len, data + block_len,
-                            (totlen - block_len) + SILC_MESSAGE_PAD(totlen),
-                            ivp)) {
+    if (silc_unlikely(!silc_cipher_decrypt(cipher, data + block_len,
+                                          data + block_len,
+                                          (totlen - block_len) +
+                                          SILC_MESSAGE_PAD(totlen), ivp))) {
       SILC_ASSERT(FALSE);
       return FALSE;
     }
@@ -339,6 +361,10 @@ silc_message_payload_parse(unsigned char *payload,
                           SilcBool static_key,
                           SilcCipher cipher,
                           SilcHmac hmac,
+                          unsigned char *sender_id,
+                          SilcUInt32 sender_id_len,
+                          unsigned char *receiver_id,
+                          SilcUInt32 receiver_id_len,
                           SilcStack stack,
                           SilcBool no_allocation,
                           SilcMessagePayload message)
@@ -353,15 +379,17 @@ silc_message_payload_parse(unsigned char *payload,
   silc_buffer_set(&buffer, payload, payload_len);
 
   /* Decrypt the payload */
-  if (cipher) {
+  if (silc_likely(cipher)) {
     ret = silc_message_payload_decrypt(buffer.data, silc_buffer_len(&buffer),
                                       private_message, static_key,
-                                      cipher, hmac, TRUE);
-    if (ret == FALSE)
+                                      cipher, hmac, sender_id,
+                                      sender_id_len, receiver_id,
+                                      receiver_id_len, TRUE);
+    if (silc_unlikely(ret == FALSE))
       return NULL;
   }
 
-  if (hmac)
+  if (silc_likely(hmac))
     mac_len = silc_hmac_len(hmac);
 
   /* IV is present for all channel messages, and private messages when
@@ -371,7 +399,7 @@ silc_message_payload_parse(unsigned char *payload,
 
   if (!message) {
     newp = message = silc_calloc(1, sizeof(*newp));
-    if (!newp)
+    if (silc_unlikely(!newp))
       return NULL;
   }
   memset(message, 0, sizeof(*message));
@@ -394,12 +422,13 @@ silc_message_payload_parse(unsigned char *payload,
                               SILC_STR_UI16_NSTRING(&message->pad,
                                                     &message->pad_len),
                               SILC_STR_END);
-  if (ret == -1)
+  if (silc_unlikely(ret == -1))
     goto err;
 
-  if ((message->data_len > silc_buffer_len(&buffer) - 6 - mac_len - iv_len) ||
-      (message->pad_len + message->data_len > silc_buffer_len(&buffer) -
-       6 - mac_len - iv_len)) {
+  if (silc_unlikely((message->data_len > silc_buffer_len(&buffer) -
+                    6 - mac_len - iv_len) ||
+                   (message->pad_len + message->data_len >
+                    silc_buffer_len(&buffer) - 6 - mac_len - iv_len))) {
     SILC_LOG_ERROR(("Incorrect Message Payload in packet"));
     goto err;
   }
@@ -443,16 +472,39 @@ SilcBool silc_message_payload_encrypt(unsigned char *data,
                                      SilcUInt32 data_len,
                                      SilcUInt32 true_len,
                                      unsigned char *iv,
+                                     SilcID *sender_id,
+                                     SilcID *receiver_id,
                                      SilcCipher cipher,
                                      SilcHmac hmac)
 {
+#if 0
+  unsigned char sid[32], rid[32];
+  SilcUInt32 sid_len = 0, rid_len = 0;
+#endif /* 0 */
+
   /* Encrypt payload of the packet */
-  if (!silc_cipher_encrypt(cipher, data, data, data_len, iv))
+  if (silc_unlikely(!silc_cipher_encrypt(cipher, data, data, data_len, iv)))
     return FALSE;
 
+#if 0 /* For now this is disabled.  Enable at 1.1.x or 1.2 at the latest. */
+  /* Encode IDs */
+  silc_id_id2str(&sender_id->u.client_id, SILC_ID_CLIENT, sid, sizeof(sid),
+                &sid_len);
+  if (receiver_id->type == SILC_ID_CLIENT)
+    silc_id_id2str(&receiver_id->u.client_id, SILC_ID_CLIENT, rid,
+                  sizeof(rid), &rid_len);
+  else if (receiver_id->type == SILC_ID_CHANNEL)
+    silc_id_id2str(&receiver_id->u.channel_id, SILC_ID_CHANNEL, rid,
+                  sizeof(rid), &rid_len);
+#endif /* 0 */
+
   /* Compute the MAC of the encrypted message data */
   silc_hmac_init(hmac);
   silc_hmac_update(hmac, data, true_len);
+#if 0
+  silc_hmac_update(hmac, sid, sid_len);
+  silc_hmac_update(hmac, rid, rid_len);
+#endif /* 0 */
   silc_hmac_final(hmac, data + true_len, NULL);
 
   return TRUE;
@@ -470,13 +522,14 @@ static int silc_message_payload_encode_encrypt(SilcBuffer buffer,
     return 0;
 
   mac_len = silc_hmac_len(e->hmac);
-  if (!silc_buffer_enlarge(buffer, mac_len))
+  if (silc_unlikely(!silc_buffer_enlarge(buffer, mac_len)))
     return -1;
 
-  if (!silc_message_payload_encrypt(buffer->head,
-                                   e->payload_len,
-                                   silc_buffer_headlen(buffer),
-                                   e->iv, e->cipher, e->hmac))
+  if (silc_unlikely(!silc_message_payload_encrypt(buffer->head,
+                                                 e->payload_len,
+                                                 silc_buffer_headlen(buffer),
+                                                 e->iv, e->sid, e->rid,
+                                                 e->cipher, e->hmac)))
     return -1;
 
   return mac_len;
@@ -498,14 +551,14 @@ static int silc_message_payload_encode_sig(SilcBuffer buffer,
                                           silc_buffer_headlen(buffer),
                                           e->public_key, e->private_key,
                                           e->hash);
-  if (!sig)
+  if (silc_unlikely(!sig))
     return -1;
 
   len = silc_buffer_format(buffer,
                           SILC_STR_DATA(silc_buffer_data(sig),
                                         silc_buffer_len(sig)),
                           SILC_STR_END);
-  if (len < 0) {
+  if (silc_unlikely(len < 0)) {
     silc_buffer_free(sig);
     return -1;
   }
@@ -527,6 +580,8 @@ SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
                                       SilcPublicKey public_key,
                                       SilcPrivateKey private_key,
                                       SilcHash hash,
+                                      SilcID *sender_id,
+                                      SilcID *receiver_id,
                                       SilcBuffer buffer)
 {
   SilcUInt32 pad_len = 0, mac_len = 0, iv_len = 0;
@@ -537,14 +592,14 @@ SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
 
   SILC_LOG_DEBUG(("Encoding Message Payload"));
 
-  if (!data_len)
+  if (silc_unlikely(!data_len))
     return NULL;
-  if (!private_message && (!cipher || !hmac))
+  if (silc_unlikely(!private_message && (!cipher || !hmac)))
     return NULL;
 
   if (!buffer) {
     buf = buffer = silc_buffer_alloc(0);
-    if (!buf)
+    if (silc_unlikely(!buf))
       return NULL;
   }
   silc_buffer_reset(buffer);
@@ -587,6 +642,8 @@ SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
   e.hash = hash;
   e.cipher = cipher;
   e.hmac = hmac;
+  e.sid = sender_id;
+  e.rid = receiver_id;
   e.iv = iv_len ? iv : NULL;
   e.payload_len = 6 + data_len + pad_len;
 
@@ -614,6 +671,7 @@ SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
 
 void silc_message_payload_free(SilcMessagePayload payload)
 {
+  silc_message_signed_payload_free(&payload->sig);
   if (payload->data) {
     memset(payload->data, 0, payload->data_len);
     if (payload->allocated)
@@ -623,7 +681,6 @@ void silc_message_payload_free(SilcMessagePayload payload)
     silc_free(payload->pad);
     silc_free(payload);
   }
-  silc_message_signed_payload_free(&payload->sig);
 }
 
 /* Return flags */