Added support for automatically parsing and encoding signature
authorPekka Riikonen <priikone@silcnet.org>
Mon, 2 Dec 2002 21:48:25 +0000 (21:48 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 2 Dec 2002 21:48:25 +0000 (21:48 +0000)
payload for channel and private messages.  Redefined the signature
payload, updated specs and implemented.

16 files changed:
CHANGES
apps/irssi/docs/help/in/msg.in
apps/irssi/docs/help/in/smsg.in [new file with mode: 0644]
apps/irssi/src/core/chat-commands.c
apps/irssi/src/silc/core/client_ops.c
apps/irssi/src/silc/core/client_ops.h
apps/irssi/src/silc/core/silc-servers.c
apps/silcd/command_reply.c
apps/silcd/packet_send.c
lib/silcclient/client_channel.c
lib/silcclient/client_ops_example.c
lib/silcclient/client_prvmsg.c
lib/silcclient/silcclient.h
lib/silccore/silcmessage.c
lib/silccore/silcmessage.h
tutorial/mybot/mybot.c

diff --git a/CHANGES b/CHANGES
index 68e6cfca70b09cd1d8ef843f086af027fe074b17..a9cfe404284c50aec9a3905102445cef503c8d4b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -8,6 +8,21 @@ Mon Dec  2 20:50:20 EET 2002  Pekka Riikonen <priikone@silcnet.org>
          notify.  Affected file lib/silcclient/client_notify.c.
          Fixes bug in '@' character handling in a nickname.
 
+       * Added support for automatically parsing signature from
+         the message payload.  Added new function
+         silc_message_get_signature to return the payload to
+         application.  Affected files lib/silccore/silcmessage.[ch].
+
+       * Changed the private_message and channel_message client
+         operations to deliver the SilcMessagePayload to the
+         application too.  Application can use it fe. to get the
+         signature from the message for verification.  Affected
+         file lib/silcclient/silcclient.h, client_channel.c and
+         client_prvmsg.c.
+
+       * Redefined the signed payload for message payloads.
+         Updated protocol specs and implemented.
+
 Mon Dec  2 16:28:29 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Fixed wrong invite and ban list handling in server command
index 153d82e8c24935dd74656f1817b9b9c1dbc9d93d..fb7c4fc7f625191628c52161687cbd83ccae1315 100644 (file)
@@ -1,10 +1,22 @@
 
 @SYNTAX:msg@
 
-Sends a private message to someone.
+Sends a private message to other user in the network.
+
+It is possible to digitally sign your messages.  The receiver
+may then verify the message with your public key.  By default
+messages are not signed.  If you want your private messages 
+to be signed you SMSG command instead of this MSG command.
+
+If -channel option is provided then this command actually
+send channel message to the specified channel.  The message
+IS NOT private message, it is normal channel message.  It is
+also possible to digitally sign channel messages by using
+SMSG command or by doing /set sign_channel_messages on, in
+which case _all_ channel messages will be signed.
 
 Example:
 
 /MSG Toni Hi, what's up?
 
-See also: QUERY
+See also: QUERY SMSG
diff --git a/apps/irssi/docs/help/in/smsg.in b/apps/irssi/docs/help/in/smsg.in
new file mode 100644 (file)
index 0000000..1bdad4e
--- /dev/null
@@ -0,0 +1,18 @@
+
+@SYNTAX:smsg@
+
+Sends a signed private message to other user in the network.
+The message will be digitally signed and the receiver may verify
+the message by using your public key.
+
+If -channel option is provided then this command actually
+send channel message to the specified channel.  The message
+IS NOT private message, it is normal channel message.  Also this
+message will be signed and can be verified by using your public
+key.
+
+Example:
+
+/SMSG Foobar Very authenticated message
+
+See also: MSG QUERY
index e26df6cd7103785801956d5f6500af874bf57f91..722d3df58955473c0c943e87429497123d94ee5b 100644 (file)
@@ -319,7 +319,7 @@ static void cmd_join(const char *data, SERVER_REC *server)
        cmd_params_free(free_arg);
 }
 
-/* SYNTAX: MSG [-<server tag>] [-channel | -nick] <targets> <message> */
+/* SYNTAX: MSG [-channel] <target> <message> */
 static void cmd_msg(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
 {
        GHashTable *optlist;
index a21963ea17c5d43a9eaf2a244b98390b99bbcd0d..41418bc5a1377d3d971dc503ecab4253c90ea8d1 100644 (file)
@@ -158,6 +158,7 @@ void silc_say_error(char *msg, ...)
 
 void silc_channel_message(SilcClient client, SilcClientConnection conn,
                          SilcClientEntry sender, SilcChannelEntry channel,
+                         SilcMessagePayload payload,
                          SilcMessageFlags flags, const unsigned char *message,
                          SilcUInt32 message_len)
 {
@@ -183,6 +184,18 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
       nick = silc_nicklist_insert(chanrec, chu, FALSE);
   }
 
+  /* If the messages is digitally signed, verify it, if possible. */
+  if (flags & SILC_MESSAGE_FLAG_SIGNED) {
+    SilcMessageSignedPayload sig = silc_message_get_signature(payload);
+/*
+    if (sig) {
+      if (silc_message_signed_verify(sig, payload, client->public_key,
+                                    client->sha1hash) != SILC_AUTH_OK)
+       silc_say_error(("Could not verify signature in message"));
+    }
+*/
+  }
+  
   if (flags & SILC_MESSAGE_FLAG_DATA) {
     /* MIME object received, try to display it as well as we can */
     char type[128], enc[128];
@@ -251,7 +264,8 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
    sender received in the packet. */
 
 void silc_private_message(SilcClient client, SilcClientConnection conn,
-                         SilcClientEntry sender, SilcMessageFlags flags,
+                         SilcClientEntry sender, SilcMessagePayload payload,
+                         SilcMessageFlags flags,
                          const unsigned char *message,
                          SilcUInt32 message_len)
 {
@@ -266,6 +280,14 @@ void silc_private_message(SilcClient client, SilcClientConnection conn,
     snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
             sender->username, sender->hostname);
 
+  /* If the messages is digitally signed, verify it, if possible. */
+  if (flags & SILC_MESSAGE_FLAG_SIGNED) {
+    SilcMessageSignedPayload sig = silc_message_get_signature(payload);
+    if (sig) {
+
+    }
+  }
+  
   if (flags & SILC_MESSAGE_FLAG_DATA) {
     /* MIME object received, try to display it as well as we can */
     char type[128], enc[128];
index 68e2b09eeff3d43bc56ab049d400c3ad0718cac7..8c3f7630e0d5d6236496b7c196fa561c8c56e7dc 100644 (file)
@@ -27,11 +27,13 @@ void silc_say_error(char *msg, ...);
 void silc_channel_message(SilcClient client, SilcClientConnection conn,
                          SilcClientEntry sender, 
                          SilcChannelEntry channel, 
+                         SilcMessagePayload payload,
                          SilcMessageFlags flags, 
                          const unsigned char *message,
                          SilcUInt32 message_len);
 void silc_private_message(SilcClient client, SilcClientConnection conn,
                          SilcClientEntry sender, 
+                         SilcMessagePayload payload,
                          SilcMessageFlags flags, 
                          const unsigned char *message,
                          SilcUInt32 message_len);
index 4d68aeb0ad0cde2bd8433f716275ea84a31e6ddf..ec9addf4d63855481927169da2684a24a5d70eb4 100644 (file)
@@ -51,7 +51,8 @@ void silc_servers_reconnect_init(void);
 void silc_servers_reconnect_deinit(void);
 
 static void silc_send_channel(SILC_SERVER_REC *server,
-                             char *channel, char *msg)
+                             char *channel, char *msg,
+                             SilcMessageFlags flags)
 {
   SILC_CHANNEL_REC *rec;
   
@@ -62,8 +63,7 @@ static void silc_send_channel(SILC_SERVER_REC *server,
   }
 
   silc_client_send_channel_message(silc_client, server->conn, rec->entry, 
-                                  NULL, SILC_MESSAGE_FLAG_UTF8,
-                                  msg, strlen(msg), TRUE);
+                                  NULL, flags, msg, strlen(msg), TRUE);
 }
 
 typedef struct {
@@ -135,7 +135,7 @@ static void silc_send_msg_clients(SilcClient client,
 }
 
 static void silc_send_msg(SILC_SERVER_REC *server, char *nick, char *msg,
-                       int msg_len, SilcMessageFlags flags)
+                         int msg_len, SilcMessageFlags flags)
 {
   PRIVMSG_REC *rec;
   SilcClientEntry *clients;
@@ -249,7 +249,8 @@ static void send_message(SILC_SERVER_REC *server, char *target,
   }
 
   if (target_type == SEND_TARGET_CHANNEL)
-    silc_send_channel(server, target, message ? message : msg);
+    silc_send_channel(server, target, message ? message : msg,
+                     SILC_MESSAGE_FLAG_UTF8);
   else
     silc_send_msg(server, target, message ? message : msg,
                  message ? strlen(message) : strlen(msg),
@@ -444,6 +445,7 @@ char *silc_server_get_channels(SILC_SERVER_REC *server)
 /* SYNTAX: WATCH [<-add | -del> <nickname>] */
 /* SYNTAX: STATS */
 /* SYNTAX: ATTR [<-del> <option> [{ <value>}]] */
+/* SYNTAX: SMSG [<-channel>] <target> <message> */
 
 void silc_command_exec(SILC_SERVER_REC *server,
                       const char *command, const char *args)
@@ -495,6 +497,75 @@ static void command_sconnect(const char *data, SILC_SERVER_REC *server)
   signal_stop();
 }
 
+/* SMSG command, to send digitally signed messages */
+
+static void command_smsg(const char *data, SILC_SERVER_REC *server,
+                        WI_ITEM_REC *item)
+{
+  GHashTable *optlist;
+  char *target, *origtarget, *msg;
+  void *free_arg;
+  int free_ret, target_type;
+  
+  g_return_if_fail(data != NULL);
+  if (server == NULL || !server->connected)
+    cmd_param_error(CMDERR_NOT_CONNECTED);
+
+  if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
+                     PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
+                     "msg", &optlist, &target, &msg))
+    return;
+  if (*target == '\0' || *msg == '\0')
+    cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+  origtarget = target;
+  free_ret = FALSE;
+
+  if (strcmp(target, "*") == 0) {
+    if (item == NULL)
+      cmd_param_error(CMDERR_NOT_JOINED);
+
+    target_type = IS_CHANNEL(item) ?
+      SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
+    target = (char *) window_item_get_target(item);
+  } else if (g_hash_table_lookup(optlist, "channel") != NULL) {
+    target_type = SEND_TARGET_CHANNEL;
+  } else {
+    target_type = server_ischannel(SERVER(server), target) ?
+      SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
+  }
+
+  if (target != NULL) {
+    char *message = NULL;
+    int len;
+
+    if (!silc_term_utf8()) {
+      len = silc_utf8_encoded_len(msg, strlen(msg), SILC_STRING_LANGUAGE);
+      message = silc_calloc(len + 1, sizeof(*message));
+      g_return_if_fail(message != NULL);
+      silc_utf8_encode(msg, strlen(msg), SILC_STRING_LANGUAGE, message, len);
+    }
+
+    if (target_type == SEND_TARGET_CHANNEL)
+      silc_send_channel(server, target, message ? message : msg,
+                       SILC_MESSAGE_FLAG_UTF8 |
+                       SILC_MESSAGE_FLAG_SIGNED);
+    else
+      silc_send_msg(server, target, message ? message : msg,
+                   message ? strlen(message) : strlen(msg),
+                   SILC_MESSAGE_FLAG_UTF8 |
+                   SILC_MESSAGE_FLAG_SIGNED);
+    silc_free(message);
+  }
+
+  signal_emit(target != NULL && target_type == SEND_TARGET_CHANNEL ?
+             "message own_public" : "message own_private", 4,
+             server, msg, target, origtarget);
+
+  if (free_ret && target != NULL) g_free(target);
+  cmd_params_free(free_arg);
+}
+
 /* FILE command */
 
 SILC_TASK_CALLBACK(silc_client_file_close_later)
@@ -983,6 +1054,7 @@ void silc_server_init(void)
   command_bind_silc("watch", MODULE_NAME, (SIGNAL_FUNC) command_self);
   command_bind_silc("stats", MODULE_NAME, (SIGNAL_FUNC) command_self);
   command_bind_silc("attr", MODULE_NAME, (SIGNAL_FUNC) command_attr);
+  command_bind_silc("smsg", MODULE_NAME, (SIGNAL_FUNC) command_smsg);
 
   command_set_options("connect", "+silcnet");
 }
@@ -1021,6 +1093,7 @@ void silc_server_deinit(void)
   command_unbind("watch", (SIGNAL_FUNC) command_self);
   command_unbind("stats", (SIGNAL_FUNC) command_self);
   command_unbind("attr", (SIGNAL_FUNC) command_attr);
+  command_unbind("smsg", (SIGNAL_FUNC) command_smsg);
 }
 
 void silc_server_free_ftp(SILC_SERVER_REC *server,
index 03f71b879c4a4e11afd77d93574b566cc3dfa6c4..a72e6c206a8ccdef7d0f727f6fe7ec6fbbd94fba 100644 (file)
@@ -1000,7 +1000,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
 
   /* Get the ban list */
   tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
-  if (tmp) {
+  if (tmp && len > 2) {
     SilcArgumentPayload iargs;
     SilcUInt16 iargc;
     SILC_GET16_MSB(iargc, tmp);
index 0d97aeafd33ecabab76994248887f38c9ee996d0..afee4c0fa79c5f977f8b554f48acf0131d36ebb6 100644 (file)
@@ -760,8 +760,9 @@ silc_server_packet_relay_to_channel_encrypt(SilcServer server,
     }
 
     memcpy(iv, data + (data_len - iv_len - mac_len), iv_len);
-    silc_message_payload_encrypt(data, data_len - iv_len, iv, iv_len,
-                                channel->channel_key, channel->hmac);
+    silc_message_payload_encrypt(data, data_len - iv_len, data_len,
+                                iv, iv_len, channel->channel_key,
+                                channel->hmac);
   }
 
   return TRUE;
index e4daea8f20b27fc771c1b9d036a427f8cf51bd6e..68983d59c6f6692dc5adf3837deca7c95632cd1f 100644 (file)
@@ -109,7 +109,8 @@ void silc_client_send_channel_message(SilcClient client,
 
   /* Encode the message payload. This also encrypts the message payload. */
   payload = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
-                                       cipher, hmac, client->rng);
+                                       cipher, hmac, client->rng, NULL,
+                                       client->private_key, client->sha1hash);
 
   /* Get data used in packet header encryption, keys and stuff. */
   cipher = conn->internal->send_key;
@@ -205,9 +206,9 @@ static void silc_client_channel_message_cb(SilcClient client,
     
     /* Pass the message to application */
     client->internal->ops->channel_message(
-                              client, conn, clients[0], channel,
-                              silc_message_get_flags(res->payload),
-                              message, message_len);
+                           client, conn, clients[0], channel, res->payload,
+                           silc_message_get_flags(res->payload),
+                           message, message_len);
   }
 
  out:
@@ -316,9 +317,9 @@ void silc_client_channel_message(SilcClient client,
 
   /* Pass the message to application */
   client->internal->ops->channel_message(
-                                client, conn, client_entry, channel,
-                                silc_message_get_flags(payload),
-                                message, message_len);
+                            client, conn, client_entry, channel, payload,
+                            silc_message_get_flags(payload),
+                            message, message_len);
 
  out:
   silc_free(id);
index c94692da3574ac644ee80aa42b5a21f797c17351..19b9acc14fdc856291da82e83f43c54b5f13938e 100644 (file)
@@ -31,8 +31,8 @@ silc_say(SilcClient client, SilcClientConnection conn,
 static void
 silc_channel_message(SilcClient client, SilcClientConnection conn,
                     SilcClientEntry sender, SilcChannelEntry channel,
-                    SilcMessageFlags flags, const unsigned char *message,
-                    SilcUInt32 message_len)
+                    SilcMessagePayload payload, SilcMessageFlags flags,
+                    const unsigned char *message, SilcUInt32 message_len)
 {
 
 }
@@ -46,8 +46,8 @@ silc_channel_message(SilcClient client, SilcClientConnection conn,
 
 static void
 silc_private_message(SilcClient client, SilcClientConnection conn,
-                    SilcClientEntry sender, SilcMessageFlags flags,
-                    const unsigned char *message,
+                    SilcClientEntry sender, SilcMessagePayload payload,
+                    SilcMessageFlags flags, const unsigned char *message,
                     SilcUInt32 message_len)
 {
 
index fee91ebf74597bbd0462dc1b33e657cce8f0d5e5..36d7bbe43a7eaffd76fe308eb7980b50da6a9867 100644 (file)
@@ -58,7 +58,8 @@ void silc_client_send_private_message(SilcClient client,
                                       !client_entry->generated,
                                       TRUE, client_entry->send_key,
                                       client_entry->hmac_send,
-                                      client->rng);
+                                      client->rng, NULL, client->private_key,
+                                      client->sha1hash);
 
   /* If we don't have private message specific key then private messages
      are just as any normal packet thus call normal packet sending.  If
@@ -211,8 +212,8 @@ void silc_client_private_message(SilcClient client,
 
   /* Pass the private message to application */
   message = silc_message_get_data(payload, &message_len);
-  client->internal->ops->private_message(client, conn, remote_client, flags,
-                                        message, message_len);
+  client->internal->ops->private_message(client, conn, remote_client, payload,
+                                        flags, message, message_len);
 
   /* See if we are away (gone). If we are away we will reply to the
      sender with the set away message. */
index f2bc667ccff0b7d1acf678de235fac05415489c1..d87dff84b92f2054edc34d15498df2fa459195e0 100644 (file)
@@ -538,7 +538,7 @@ typedef struct {
      (like it may tell the message is multimedia message). */
   void (*channel_message)(SilcClient client, SilcClientConnection conn, 
                          SilcClientEntry sender, SilcChannelEntry channel, 
-                         SilcMessageFlags flags,
+                         SilcMessagePayload payload, SilcMessageFlags flags,
                          const unsigned char *message,
                          SilcUInt32 message_len);
 
@@ -548,7 +548,8 @@ typedef struct {
      can be interpreted (like it may tell the message is multimedia 
      message). */
   void (*private_message)(SilcClient client, SilcClientConnection conn,
-                         SilcClientEntry sender, SilcMessageFlags flags,
+                         SilcClientEntry sender, SilcMessagePayload payload,
+                         SilcMessageFlags flags,
                          const unsigned char *message,
                          SilcUInt32 message_len);
 
@@ -1126,6 +1127,9 @@ void silc_client_close_connection(SilcClient client,
  *    keys are set then the first key (the key that was added first as
  *    private key) is used. 
  *
+ *    If the `flags' includes SILC_MESSAGE_FLAG_SIGNED the message will be
+ *    digitally signed with the SILC key pair.
+ *
  ***/
 void silc_client_send_channel_message(SilcClient client, 
                                      SilcClientConnection conn,
@@ -1158,6 +1162,9 @@ void silc_client_send_channel_message(SilcClient client,
  *    message. The `data' is the private message. If the `force_send' is
  *    TRUE the packet is sent immediately. 
  *
+ *    If the `flags' includes SILC_MESSAGE_FLAG_SIGNED the message will be
+ *    digitally signed with the SILC key pair.
+ *
  ***/
 void silc_client_send_private_message(SilcClient client,
                                      SilcClientConnection conn,
index e3fd64f970cb17556abd27cb35a6eec618429aa1..7ca95ac6fca52f950fdcba99eb437e5dac32f43f 100644 (file)
@@ -54,7 +54,7 @@ struct SilcMessagePayloadStruct {
   unsigned char *pad;
   unsigned char *iv;
   unsigned char *mac;
-  /*SilcMessageSignedPayload sig;*/
+  SilcMessageSignedPayload sig;
 };
 
 /* Decrypts the Message Payload. The `data' is the actual Message Payload */
@@ -67,9 +67,11 @@ bool silc_message_payload_decrypt(unsigned char *data,
                                  SilcHmac hmac,
                                  bool check_mac)
 {
-  SilcUInt32 mac_len = 0, iv_len = 0;
+  SilcUInt32 mac_len = 0, iv_len = 0, block_len, pad_len;
   unsigned char *mac, mac2[32];
-
+  unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *ivp;
+  SilcUInt16 len;
+  
   mac_len = silc_hmac_len(hmac);
 
   /* IV is present for channel messages and private messages when static
@@ -96,9 +98,27 @@ bool silc_message_payload_decrypt(unsigned char *data,
     SILC_LOG_DEBUG(("MAC is Ok"));
   }
 
-  /* Decrypt the message */
-  silc_cipher_decrypt(cipher, data, data, data_len - iv_len - mac_len,
-                     (iv_len ? data + (data_len - iv_len - mac_len) : NULL));
+  /* Get pointer to the IV */
+  ivp = (iv_len ? data + (data_len - iv_len - mac_len) :
+        silc_cipher_get_iv(cipher));
+
+  /* Decrypt first block to get data length.  We need to do this since
+     there might be extra data at the end of the payload which is not
+     encrypted (like the signature payload). */
+  block_len = silc_cipher_get_block_len(cipher);
+  memcpy(iv, ivp, block_len);
+  silc_cipher_decrypt(cipher, data, data, 16, iv);
+
+  /* Decrypt rest of the message */
+  SILC_GET16_MSB(len, data + 2);
+  pad_len = SILC_MESSAGE_PAD(6 + len);
+  if (6 + len + pad_len > 16 &&
+      6 + len + pad_len + mac_len + iv_len <= data_len) {
+    silc_cipher_set_iv(cipher, iv);
+    silc_cipher_decrypt(cipher, data + 16, data + 16,
+                       (6 + len + pad_len) - 16, NULL);
+  }
+
   return TRUE;
 }
 
@@ -164,6 +184,18 @@ silc_message_payload_parse(unsigned char *payload,
 
   newp->iv_len = iv_len;
 
+  SILC_LOG_HEXDUMP(("foo"), buffer.data, buffer.len);
+  
+  /* Parse Signed Message Payload if provided */
+  if (newp->flags & SILC_MESSAGE_FLAG_SIGNED &&
+      newp->data_len + newp->pad_len + 6 + mac_len + iv_len < buffer.len) {
+    silc_buffer_pull(&buffer, 6 + newp->data_len + newp->pad_len);
+    newp->sig =
+      silc_message_signed_payload_parse(buffer.data,
+                                       buffer.len - iv_len - mac_len);
+    silc_buffer_push(&buffer, 6 + newp->data_len + newp->pad_len);
+  }
+  
   return newp;
 
  err:
@@ -174,10 +206,11 @@ silc_message_payload_parse(unsigned char *payload,
 /* This function is used to encrypt the Messsage Payload which is
    the `data' and `data_len'.  This is used internally by the Message
    Payload encoding routines but application may call this too if needed. 
-   The `data_len' is the data lenght which is used to create MAC out of. */
+   The `true_len' is the data length which is used to create MAC out of. */
 
 bool silc_message_payload_encrypt(unsigned char *data,
                                  SilcUInt32 data_len,
+                                 SilcUInt32 true_len,
                                  unsigned char *iv,
                                  SilcUInt32 iv_len,
                                  SilcCipher cipher,
@@ -189,17 +222,16 @@ bool silc_message_payload_encrypt(unsigned char *data,
 
   /* Encrypt payload of the packet. If the IV is added to packet do
      not encrypt that. */
-  silc_cipher_encrypt(cipher, data, data, data_len - iv_len,
-                     iv_len ? iv : NULL);
+  silc_cipher_encrypt(cipher, data, data, data_len, iv_len ? iv : NULL);
 
   /* Compute the MAC of the encrypted message data */
   silc_hmac_init(hmac);
-  silc_hmac_update(hmac, data, data_len);
+  silc_hmac_update(hmac, data, true_len);
   silc_hmac_final(hmac, mac, &mac_len);
 
   /* Put rest of the data to the payload */
-  silc_buffer_set(&buf, data, data_len + mac_len);
-  silc_buffer_pull(&buf, data_len);
+  silc_buffer_set(&buf, data, true_len + mac_len);
+  silc_buffer_pull(&buf, true_len);
   silc_buffer_put(&buf, mac, mac_len);
 
   return TRUE;
@@ -214,12 +246,16 @@ SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
                                       bool private_message,
                                       SilcCipher cipher,
                                       SilcHmac hmac,
-                                      SilcRng rng)
+                                      SilcRng rng,
+                                      SilcPublicKey public_key,
+                                      SilcPrivateKey private_key,
+                                      SilcHash hash)
 {
   int i;
   SilcBuffer buffer;
   SilcUInt32 len, pad_len = 0, mac_len = 0, iv_len = 0;
   unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE];
+  SilcBuffer sig = NULL;
 
   SILC_LOG_DEBUG(("Encoding Message Payload"));
 
@@ -265,28 +301,57 @@ SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
   }
 
   /* Encode the Message Payload */
-  silc_buffer_pull_tail(buffer, 6 + data_len + pad_len + iv_len);
+  silc_buffer_pull_tail(buffer, 6 + data_len + pad_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));
 
-  /* Now encrypt the Message Payload */
+  /* Sign the message if wanted */
+  if (flags & SILC_MESSAGE_FLAG_SIGNED && private_key && hash) {
+    sig = silc_message_signed_payload_encode(buffer->data, buffer->len,
+                                            public_key, private_key, hash);
+    if (sig) {
+      buffer = silc_buffer_realloc(buffer, buffer->truelen + sig->len);
+      if (buffer) {
+       silc_buffer_pull(buffer, 6 + data_len + pad_len);
+       silc_buffer_pull_tail(buffer, sig->len);
+       silc_buffer_put(buffer, sig->data, sig->len);
+       silc_buffer_push(buffer, 6 + data_len + pad_len);
+      }
+    }
+  }
+
+  /* Put IV */
+  silc_buffer_pull(buffer, 6 + data_len + pad_len + (sig ? sig->len : 0));
+  silc_buffer_pull_tail(buffer, iv_len);
+  silc_buffer_format(buffer, 
+                    SILC_STR_UI_XNSTRING(iv, iv_len),
+                    SILC_STR_END);
+  silc_buffer_push(buffer, 6 + data_len + pad_len + (sig ? sig->len : 0));
+  
+  SILC_LOG_HEXDUMP(("foo"), buffer->data, buffer->len);
+  
+  /* Now encrypt the Message Payload and compute MAC */
   if (cipher) {
-    if (!silc_message_payload_encrypt(buffer->data, buffer->len,
-                                     iv, iv_len, cipher, hmac)) {
+    if (!silc_message_payload_encrypt(buffer->data,
+                                     buffer->len - iv_len -
+                                     (sig ? sig->len : 0),
+                                     buffer->len, iv, iv_len,
+                                     cipher, hmac)) {
       silc_buffer_free(buffer);
+      silc_buffer_free(sig);
       return NULL;
     }
   }
   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
 
+  silc_buffer_free(sig);
   return buffer;
 }
 
@@ -298,6 +363,8 @@ void silc_message_payload_free(SilcMessagePayload payload)
     memset(payload->data, 0, payload->data_len);
     silc_free(payload->data);
   }
+  if (payload->sig)
+    silc_message_signed_payload_free(payload->sig);
   silc_free(payload->pad);
   silc_free(payload);
 }
@@ -333,6 +400,14 @@ unsigned char *silc_message_get_iv(SilcMessagePayload payload)
   return payload->iv;
 }
 
+/* Return signature of the message */
+
+const SilcMessageSignedPayload
+silc_message_get_signature(SilcMessagePayload payload)
+{
+  return (const SilcMessageSignedPayload)payload->sig;
+}
+
 /******************************************************************************
 
                      SILC_MESSAGE_FLAG_SIGNED Payload
@@ -392,6 +467,8 @@ silc_message_signed_payload_parse(const unsigned char *data,
 
   SILC_LOG_DEBUG(("Parsing SILC_MESSAGE_FLAG_SIGNED Payload"));
 
+  SILC_LOG_HEXDUMP(("sig payload"), data, data_len);
+
   silc_buffer_set(&buffer, (unsigned char *)data, data_len);
   sig = silc_calloc(1, sizeof(*sig));
   if (!sig)
@@ -404,6 +481,8 @@ silc_message_signed_payload_parse(const unsigned char *data,
                             SILC_STR_END);
   if (ret == -1 || sig->pk_len > data_len - 4) {
     silc_message_signed_payload_free(sig);
+    SILC_LOG_DEBUG(("Malformed public key in SILC_MESSAGE_FLAG_SIGNED "
+                   "Payload"));
     return NULL;
   }
 
@@ -416,12 +495,15 @@ silc_message_signed_payload_parse(const unsigned char *data,
                             SILC_STR_END);
   if (ret == -1) {
     silc_message_signed_payload_free(sig);
+    SILC_LOG_DEBUG(("Malformed SILC_MESSAGE_FLAG_SIGNED Payload"));
     return NULL;
   }
   silc_buffer_push(&buffer, 4);
 
   /* Signature must be provided */
   if (sig->sign_len < 1)  {
+    SILC_LOG_DEBUG(("Malformed signature in SILC_MESSAGE_SIGNED_PAYLOAD "
+                   "Payload"));
     silc_message_signed_payload_free(sig);
     return NULL;
   }
@@ -437,8 +519,7 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
                                   SilcUInt32 message_payload_len,
                                   SilcPublicKey public_key,
                                   SilcPrivateKey private_key,
-                                  SilcHash hash,
-                                  bool include_public_key)
+                                  SilcHash hash)
 {
   SilcBuffer buffer, sign;
   SilcPKCS pkcs;
@@ -450,10 +531,8 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
 
   if (!message_payload || !message_payload_len || !private_key || !hash)
     return NULL;
-  if (include_public_key && !public_key)
-    return NULL;
-
-  if (include_public_key)
+  
+  if (public_key)
     pk = silc_pkcs_public_key_encode(public_key, &pk_len);
 
   /* Now we support only SILC style public key */
@@ -472,6 +551,7 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
 
   /* Allocate PKCS object */
   if (!silc_pkcs_alloc(private_key->name, &pkcs)) {
+    SILC_LOG_ERROR(("Could not allocated PKCS"));
     silc_buffer_clear(sign);
     silc_buffer_free(sign);
     silc_free(pk);
@@ -483,6 +563,7 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
   if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
       !silc_pkcs_sign_with_hash(pkcs, hash, sign->data, sign->len, auth_data,
                                &auth_len)) {
+    SILC_LOG_ERROR(("Could not compute signature"));
     silc_buffer_clear(sign);
     silc_buffer_free(sign);
     silc_pkcs_free(pkcs);
@@ -502,25 +583,27 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
     return NULL;
   }
 
-  silc_buffer_format(sign,
+  silc_buffer_format(buffer,
                     SILC_STR_UI_SHORT(pk_len),
                     SILC_STR_UI_SHORT(pk_type),
                     SILC_STR_END);
 
   if (pk_len && pk) {
-    silc_buffer_pull(sign, 4);
-    silc_buffer_format(sign,
+    silc_buffer_pull(buffer, 4);
+    silc_buffer_format(buffer,
                       SILC_STR_UI_XNSTRING(pk, pk_len),
                       SILC_STR_END);
-    silc_buffer_push(sign, 4);
+    silc_buffer_push(buffer, 4);
   }
 
-  silc_buffer_pull(sign, 4 + pk_len);
-  silc_buffer_format(sign,
+  silc_buffer_pull(buffer, 4 + pk_len);
+  silc_buffer_format(buffer,
                     SILC_STR_UI_SHORT(auth_len),
                     SILC_STR_UI_XNSTRING(auth_data, auth_len),
                     SILC_STR_END);
-  silc_buffer_push(sign, 4 + pk_len);
+  silc_buffer_push(buffer, 4 + pk_len);
+
+  SILC_LOG_HEXDUMP(("sig payload"), buffer->data, buffer->len);
 
   memset(auth_data, 0, sizeof(auth_data));
   silc_pkcs_free(pkcs);
@@ -535,12 +618,10 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
 
 void silc_message_signed_payload_free(SilcMessageSignedPayload sig)
 {
-  if (sig) {
-    memset(sig->sign_data, 0, sig->sign_len);
-    silc_free(sig->sign_data);
-    silc_free(sig->pk_data);
-    silc_free(sig);
-  }
+  memset(sig->sign_data, 0, sig->sign_len);
+  silc_free(sig->sign_data);
+  silc_free(sig->pk_data);
+  silc_free(sig);
 }
 
 /* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */
@@ -559,15 +640,13 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig,
     return ret;
 
   /* Generate the signature verification data, the Message Payload */
-  tmp = silc_buffer_alloc_size(6 + message->data_len + message->pad_len +
-                              message->iv_len);
+  tmp = silc_buffer_alloc_size(6 + message->data_len + message->pad_len);
   silc_buffer_format(tmp,
                     SILC_STR_UI_SHORT(message->flags),
                     SILC_STR_UI_SHORT(message->data_len),
                     SILC_STR_UI_XNSTRING(message->data, message->data_len),
                     SILC_STR_UI_SHORT(message->pad_len),
                     SILC_STR_UI_XNSTRING(message->pad, message->pad_len),
-                    SILC_STR_UI_XNSTRING(message->iv, message->iv_len),
                     SILC_STR_END);
   sign = silc_message_signed_encode_data(tmp->data, tmp->len,
                                         sig->pk_data, sig->pk_len,
index e003e029ee1a52623182896bca5ebea7c9febbc9..ff77a81203b1be0ea4478c3eed31f31edbcc1a8a 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 -2002 Pekka Riikonen
+  Copyright (C) 1997 - 2002 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
  ***/
 typedef struct SilcMessagePayloadStruct *SilcMessagePayload;
 
+/****s* silccore/SilcMessageAPI/SilcMessageSignedPayload
+ *
+ * NAME
+ * 
+ *    typedef struct SilcMessageSignedPayloadStruct *SilcMessageSignedPayload;
+ *
+ *
+ * DESCRIPTION
+ *
+ *    This context represents the SILC_MESSAGE_FLAG_SIGNED Payload which
+ *    is used with channel messages and private messages to indicate that
+ *    the message is digitally signed.  This payload may include the
+ *    message sender's public key and it includes the digital signature.
+ *    This payload MUST NOT be used in any other context except with
+ *    channel and private message sending and reception.
+ *
+ ***/
+typedef struct SilcMessageSignedPayloadStruct *SilcMessageSignedPayload;
+
 /****d* silccore/SilcMessageAPI/SilcMessageFlags
  *
  * NAME
@@ -161,6 +180,7 @@ silc_message_payload_parse(unsigned char *payload,
  *
  *    bool silc_message_payload_encrypt(unsigned char *data,
  *                                      SilcUInt32 data_len,
+ *                                      SilcUInt32 true_len,
  *                                      unsigned char *iv,
  *                                      SilcUInt32 iv_len,
  *                                      SilcCipher cipher,
@@ -171,7 +191,7 @@ silc_message_payload_parse(unsigned char *payload,
  *    This function is used to encrypt the 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 `data' MUST have additional space
- *    after `data_len' bytes for the MAC which is appended to the data.
+ *    after `true_len' bytes for the MAC which is appended to the data.
  *
  *    This is usually used by the Message Payload interface itself but can
  *    be called by the appliation if separate encryption process is required.
@@ -182,6 +202,7 @@ silc_message_payload_parse(unsigned char *payload,
  ***/
 bool silc_message_payload_encrypt(unsigned char *data,
                                  SilcUInt32 data_len,
+                                 SilcUInt32 true_len,
                                  unsigned char *iv,
                                  SilcUInt32 iv_len,
                                  SilcCipher cipher,
@@ -198,7 +219,10 @@ bool silc_message_payload_encrypt(unsigned char *data,
  *                                           bool private_message,
  *                                           SilcCipher cipher,
  *                                           SilcHmac hmac,
- *                                           SilcRng rng);
+ *                                           SilcRng rng,
+ *                                           SilcPublicKey public_key,
+ *                                           SilcPrivateKey private_key,
+ *                                           SilcHash hash);
  *
  * DESCRIPTION
  *
@@ -219,10 +243,15 @@ bool silc_message_payload_encrypt(unsigned char *data,
  *    message that will be encrypted with session keys (no private message
  *    key) then `cipher' and `hmac' is NULL and this merely encodes the
  *    payload buffer, and the caller must encrypt the packet later.
- *
  *    If `rng' is NULL then global RNG is used, if non-NULL then the
  *    `rng' is used (for IV and padding generation).
  *
+ *    The `public_key', `private_key' and `hash' are provided only if the
+ *    flags includes SILC_MESSAGE_FLAG_SIGNED, in which case the message
+ *    will be digitally signed.  If `public_key' is non-NULL then it will
+ *    be included in the message.  The `private_message' and `hash' MUST
+ *    be provided.  The `hash' SHOULD be SHA1.
+ *
  ***/
 SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
                                       const unsigned char *data,
@@ -231,7 +260,10 @@ SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
                                       bool private_message,
                                       SilcCipher cipher,
                                       SilcHmac hmac,
-                                      SilcRng rng);
+                                      SilcRng rng,
+                                      SilcPublicKey public_key,
+                                      SilcPrivateKey private_key,
+                                      SilcHash hash);
 
 /****f* silccore/SilcMessageAPI/silc_message_payload_free
  *
@@ -306,24 +338,26 @@ unsigned char *silc_message_get_mac(SilcMessagePayload payload);
  ***/
 unsigned char *silc_message_get_iv(SilcMessagePayload payload);
 
-/****s* silccore/SilcMessageAPI/SilcMessageSignedPayload
+/****f* silccore/SilcMessageAPI/silc_message_get_signature
  *
- * NAME
- * 
- *    typedef struct SilcMessageSignedPayloadStruct *SilcMessageSignedPayload;
+ * SYNOPSIS
  *
+ *    const SilcMessageSignedPayload
+ *    silc_message_get_signature(SilcMessagePayload payload);
  *
  * DESCRIPTION
  *
- *    This context represents the SILC_MESSAGE_FLAG_SIGNED Payload which
- *    is used with channel messages and private messages to indicate that
- *    the message is digitally signed.  This payload may include the
- *    message sender's public key and it includes the digital signature.
- *    This payload MUST NOT be used in any other context except with
- *    channel and private message sending and reception.
+ *    Returns the pointer to the signature of the message if the
+ *    SILC_MESSAGE_FLAG_SIGNED was set.  If the flag is set and this
+ *    function returns NULL then error had occurred and the signature
+ *    could not be retrieved from the message.
+ *
+ *    The caller SHOULD verify the signature by calling the
+ *    silc_message_signed_verify function.
  *
  ***/
-typedef struct SilcMessageSignedPayloadStruct *SilcMessageSignedPayload;
+const SilcMessageSignedPayload
+silc_message_get_signature(SilcMessagePayload payload);
 
 /****f* silccore/SilcMessageAPI/silc_message_signed_payload_parse
  *
@@ -335,10 +369,13 @@ typedef struct SilcMessageSignedPayloadStruct *SilcMessageSignedPayload;
  *
  * DESCRIPTION
  *
- *    Parses the SILC_MESSAGE_FLAG_SIGNED Payload from the `data' of
+ *    Parses the SilcMessageSignedPayload Payload from the `data' of
  *    length of `data_len' bytes.  The `data' must be payload without
  *    the actual message payload.  Returns the parsed payload or NULL
- *    on error.  Caller must free the returned payload.
+ *    on error.  Caller must free the returned payload.  Application
+ *    usually does not need to call this since the function
+ *    silc_message_payload_parse calls this automatically for signed
+ *    messages.
  *
  ***/
 SilcMessageSignedPayload
@@ -354,18 +391,22 @@ silc_message_signed_payload_parse(const unsigned char *data,
  *                                       SilcUInt32 message_payload_len,
  *                                       SilcPublicKey public_key,
  *                                       SilcPrivateKey private_key,
- *                                       bool include_public_key);
+ *                                       SilcHash hash);
  *
  * DESCRIPTION
  *
- *    Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the
+ *    Encodes the SilcMessageSignedPayload Payload and computes the
  *    digital signature.  The `message_payload' is the message data that
  *    is used in the signature computation.  The encoding of the buffer
- *    is specified in the SILC protocol.  If `include_public_key' is
- *    TRUE then the public key included in the payload.  The `private_key'
+ *    is specified in the SILC protocol.  If `public_key' is provided
+ *    then the public key included in the payload.  The `private_key'
  *    is used to produce the signature.  This function returns the encoded
  *    payload with the signature or NULL on error.  Caller must free the
- *    returned buffer.
+ *    returned buffer.  The `hash' SHOULD be SHA-1 hash function.
+ *    
+ *    Application usually does not need to call this since the function
+ *    silc_message_payload_encode calls this automatically if the caller
+ *    wants to sign the message.
  *
  ***/
 SilcBuffer
@@ -373,8 +414,7 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
                                   SilcUInt32 message_payload_len,
                                   SilcPublicKey public_key,
                                   SilcPrivateKey private_key,
-                                  SilcHash hash,
-                                  bool include_public_key);
+                                  SilcHash hash);
 
 /****f* silccore/SilcMessageAPI/silc_message_signed_payload_free
  *
@@ -384,7 +424,7 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
  *
  * DESCRIPTION
  *
- *    Frees the SILC_MESSAGE_FLAG_SIGNED Payload.
+ *    Frees the SilcMessageSignedPayload Payload.
  *
  ***/
 void silc_message_signed_payload_free(SilcMessageSignedPayload sig);
@@ -401,7 +441,7 @@ void silc_message_signed_payload_free(SilcMessageSignedPayload sig);
  * DESCRIPTION
  *
  *    This routine can be used to verify the signature found in
- *    SILC_MESSAGE_FLAG_SIGNED Payload.  This returns SILC_AUTH_OK if the
+ *    SilcMessageSignedPayload Payload.  This returns SILC_AUTH_OK if the
  *    signature verification was successful.
  *
  ***/
@@ -419,7 +459,7 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig,
  *
  * DESCRIPTION
  *
- *    Returns the public key from the SILC_MESSAGE_FLAG_SIGNED Payload
+ *    Returns the public key from the SilcMessageSignedPayload Payload
  *    or NULL if it does not include public key.  The caller must free
  *    the returned public key.
  *
index 8e16c897ec72c7a650ad112a20addef4562bd40e..e1c8d2162e958f771fdfabe7c58dd6f6aa0e64ad 100644 (file)
@@ -166,6 +166,7 @@ silc_say(SilcClient client, SilcClientConnection conn,
 static void
 silc_channel_message(SilcClient client, SilcClientConnection conn,
                     SilcClientEntry sender, SilcChannelEntry channel,
+                    SilcMessagePayload payload,
                     SilcMessageFlags flags, const unsigned char *message,
                     SilcUInt32 message_len)
 {
@@ -182,7 +183,8 @@ silc_channel_message(SilcClient client, SilcClientConnection conn,
 
 static void
 silc_private_message(SilcClient client, SilcClientConnection conn,
-                    SilcClientEntry sender, SilcMessageFlags flags,
+                    SilcClientEntry sender, SilcMessagePayload payload,
+                    SilcMessageFlags flags,
                     const unsigned char *message,
                     SilcUInt32 message_len)
 {