From: Pekka Riikonen Date: Wed, 28 Mar 2001 19:45:57 +0000 (+0000) Subject: updates. X-Git-Tag: 1.2.beta1~2416 X-Git-Url: http://git.silcnet.org/gitweb/?p=crypto.git;a=commitdiff_plain;h=a4bea30553d9f9ce717f2c658febcd43133b9f94 updates. --- diff --git a/CHANGES b/CHANGES index 6699e53b..0a8babd9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,16 @@ +Wed Mar 28 20:50:47 EEST 2001 Pekka Riikonen + + * Redefined the Private Message Payload to support private message + keys and to support the new private message flags. Updated + the protocol specs. + + * Added new type SilcPrivateMessagePayload and defined an API + for it in the lib/silcclient/silcprivate.[ch]. + + * Tested private message private keys successfully. Tested the + private message key set, unset and list commands with the new + KEY command. + Wed Mar 28 15:52:36 EEST 2001 Pekka Riikonen * Added SilcKeyAgreementStatus type to the key agreement routines diff --git a/apps/silc/local_command.c b/apps/silc/local_command.c index 1938e9f9..3527a3ff 100644 --- a/apps/silc/local_command.c +++ b/apps/silc/local_command.c @@ -417,7 +417,7 @@ SILC_CLIENT_LCMD_FUNC(key) if (!strcasecmp(cmd->argv[3], "set")) { command = 1; - if (cmd->argc == 3) { + if (cmd->argc == 4) { if (curr_key && type == 1 && client_entry) { silc_client_del_private_message_key(client, conn, client_entry); silc_client_add_private_message_key_ske(client, conn, client_entry, @@ -426,13 +426,13 @@ SILC_CLIENT_LCMD_FUNC(key) } } - if (cmd->argc >= 4) { + if (cmd->argc >= 5) { if (type == 1 && client_entry) { /* Set private message key */ silc_client_del_private_message_key(client, conn, client_entry); - if (cmd->argc >= 5) + if (cmd->argc >= 6) silc_client_add_private_message_key(client, conn, client_entry, cmd->argv[5], cmd->argv[4], cmd->argv_lens[4], @@ -458,9 +458,9 @@ SILC_CLIENT_LCMD_FUNC(key) goto out; } - if (cmd->argc >= 5) - cipher = cmd->argv[5]; if (cmd->argc >= 6) + cipher = cmd->argv[5]; + if (cmd->argc >= 7) hmac = cmd->argv[6]; if (!silc_client_add_channel_private_key(client, conn, channel_entry, @@ -489,10 +489,10 @@ SILC_CLIENT_LCMD_FUNC(key) unsigned int keys_count; int number; - if (cmd->argc == 3) + if (cmd->argc == 4) silc_client_del_channel_private_keys(client, conn, channel_entry); - if (cmd->argc > 3) { + if (cmd->argc > 4) { number = atoi(cmd->argv[4]); keys = silc_client_list_channel_private_keys(client, conn, channel_entry, @@ -533,7 +533,7 @@ SILC_CLIENT_LCMD_FUNC(key) if (nickname[0] == '*') { silc_say(client, conn, "Private message keys"); silc_say(client, conn, - " Client Cipher Key"); + " Client Cipher Key"); for (k = 0; k < keys_count; k++) { memset(buf, 0, sizeof(buf)); strncat(buf, " ", 2); @@ -562,7 +562,7 @@ SILC_CLIENT_LCMD_FUNC(key) silc_say(client, conn, "Private message key", client_entry->nickname); silc_say(client, conn, - " Client Cipher Key"); + " Client Cipher Key"); for (k = 0; k < keys_count; k++) { if (keys[k].client_entry != client_entry) continue; diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index c4c4a706..f88b63e8 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -782,11 +782,17 @@ void silc_server_send_private_message(SilcServer server, silc_server_packet_send_real(server, dst_sock, FALSE); } else { - /* Key exist so just send it */ + /* Key exist so encrypt just header and send it */ silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len + packet->dst_id_len + packet->padlen); silc_packet_send_prepare(dst_sock, 0, 0, buffer->len); silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len); + + /* Encrypt header */ + silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, + SILC_PACKET_HEADER_LEN + packet->src_id_len + + packet->dst_id_len + packet->padlen); + silc_server_packet_send_real(server, dst_sock, FALSE); } } diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 96a2433a..54dc325a 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -1423,9 +1423,12 @@ static int silc_server_packet_decrypt_check(SilcPacketType packet_type, all other packets are special packets */ - if ((packet_type == SILC_PACKET_PRIVATE_MESSAGE && - !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) || - packet_type != SILC_PACKET_CHANNEL_MESSAGE || + + if (packet_type == SILC_PACKET_PRIVATE_MESSAGE && + (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) + return FALSE; + + if (packet_type != SILC_PACKET_CHANNEL_MESSAGE || (packet_type == SILC_PACKET_CHANNEL_MESSAGE && parse_ctx->sock->type == SILC_SOCKET_TYPE_ROUTER && server->server_type == SILC_ROUTER)) diff --git a/doc/draft-riikonen-silc-pp-01.nroff b/doc/draft-riikonen-silc-pp-01.nroff index 29d5713d..65da1422 100644 --- a/doc/draft-riikonen-silc-pp-01.nroff +++ b/doc/draft-riikonen-silc-pp-01.nroff @@ -1640,10 +1640,16 @@ diagram represents the Private Message Payload. ~ Nickname ~ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Flags | Message Data Length | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | ~ Message Data ~ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | +~ Padding ~ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ .in 3 .ce @@ -1662,9 +1668,24 @@ o Nickname (variable length) - Nickname of the sender of the to the Client ID in the SILC Packet Header. This nickname is merely provided to be displayed by the client. +o Flags (2 bytes) - This field includes the flags of the + private message. They can indicate a different reason or + purpose for the private message. See section XXX for the + defined flags. + +o Message Data Length (2 bytes) - Indicates the length of the + Message Data field, not includes any other field. + o Message Data (variable length) - The actual message to the client. Rest of the packet is reserved for the message data. + +o Padding (variable length) - This field is present only + when the private message payload is encrypted with private + message key. In this case the padding is applied to make + the packet multiple by eight (8), or by the block size of + the cipher, which ever is larger. When encrypted with + normal session keys, this field must not be included. .in 3 diff --git a/includes/silcincludes.h b/includes/silcincludes.h index b27765cd..09da825b 100644 --- a/includes/silcincludes.h +++ b/includes/silcincludes.h @@ -168,6 +168,7 @@ #include "silcnotify.h" #include "silcmode.h" #include "silcauth.h" +#include "silcprivate.h" /* TRQ (SilcList API and SilcDList API) */ #include "silclist.h" diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 7637466b..8bbf3b10 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -692,9 +692,12 @@ static int silc_client_packet_decrypt_check(SilcPacketType packet_type, all other packets are special packets */ - if ((packet_type == SILC_PACKET_PRIVATE_MESSAGE && - !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) || - packet_type != SILC_PACKET_CHANNEL_MESSAGE) + + if (packet_type == SILC_PACKET_PRIVATE_MESSAGE && + (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) + return FALSE; + + if (packet_type != SILC_PACKET_CHANNEL_MESSAGE) return TRUE; return FALSE; diff --git a/lib/silcclient/client_prvmsg.c b/lib/silcclient/client_prvmsg.c index 0234f023..56748bf4 100644 --- a/lib/silcclient/client_prvmsg.c +++ b/lib/silcclient/client_prvmsg.c @@ -42,22 +42,16 @@ void silc_client_send_private_message(SilcClient client, SilcSocketConnection sock = conn->sock; SilcBuffer buffer; SilcPacketContext packetdata; - unsigned int nick_len; SilcCipher cipher; SilcHmac hmac; SILC_LOG_DEBUG(("Sending private message")); - /* Create private message payload */ - nick_len = strlen(conn->nickname); - buffer = silc_buffer_alloc(2 + nick_len + data_len); - silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); - silc_buffer_format(buffer, - SILC_STR_UI_SHORT(nick_len), - SILC_STR_UI_XNSTRING(conn->nickname, - nick_len), - SILC_STR_UI_XNSTRING(data, data_len), - SILC_STR_END); + /* Encode private message payload */ + buffer = silc_private_message_payload_encode(strlen(conn->nickname), + conn->nickname, 0, + data_len, data, + client_entry->send_key); /* If we don't have private message specific key then private messages are just as any normal packet thus call normal packet sending. If @@ -101,12 +95,7 @@ void silc_client_send_private_message(SilcClient client, packetdata.buffer = sock->outbuf; - /* Encrypt payload of the packet. Encrypt with private message specific - key */ - cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data, - buffer->len, cipher->iv); - - /* Put the actual encrypted payload data into the buffer. */ + /* Put the actual encrypted message payload data into the buffer. */ silc_buffer_put(sock->outbuf, buffer->data, buffer->len); /* Create the outgoing packet */ @@ -126,9 +115,21 @@ void silc_client_send_private_message(SilcClient client, silc_free(packetdata.dst_id); out: - silc_free(buffer); + silc_buffer_free(buffer); } +static void silc_client_private_message_cb(SilcClient client, + SilcClientConnection conn, + SilcClientEntry *clients, + unsigned int clients_count, + void *context) +{ + SilcPacketContext *packet = (SilcPacketContext *)context; + + silc_client_private_message(client, conn->sock, packet); + silc_packet_context_free(packet); +} + /* Private message received. This processes the private message and finally displays it on the screen. */ @@ -137,29 +138,14 @@ void silc_client_private_message(SilcClient client, SilcPacketContext *packet) { SilcClientConnection conn = (SilcClientConnection)sock->user_data; - SilcBuffer buffer = packet->buffer; + SilcPrivateMessagePayload payload = NULL; SilcIDCacheEntry id_cache; SilcClientID *remote_id = NULL; SilcClientEntry remote_client; - unsigned short nick_len; - unsigned char *nickname, *message = NULL; - int ret; if (packet->src_id_type != SILC_ID_CLIENT) goto out; - /* Get nickname */ - ret = silc_buffer_unformat(buffer, - SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len), - SILC_STR_END); - if (ret == -1) - return; - - silc_buffer_pull(buffer, 2 + nick_len); - - message = silc_calloc(buffer->len + 1, sizeof(char)); - memcpy(message, buffer->data, buffer->len); - remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT); if (!remote_id) @@ -167,24 +153,28 @@ void silc_client_private_message(SilcClient client, /* Check whether we know this client already */ if (!silc_idcache_find_by_id_one(conn->client_cache, remote_id, - SILC_ID_CLIENT, &id_cache)) - { - /* Allocate client entry */ - remote_client = silc_calloc(1, sizeof(*remote_client)); - remote_client->id = silc_id_dup(remote_id, SILC_ID_CLIENT); - silc_parse_nickname(nickname, &remote_client->nickname, - &remote_client->server, &remote_client->num); - - /* Save the client to cache */ - silc_idcache_add(conn->client_cache, remote_client->nickname, - strlen(remote_client->nickname), SILC_ID_CLIENT, - remote_client->id, remote_client, TRUE, TRUE); - } else { - remote_client = (SilcClientEntry)id_cache->context; - } + SILC_ID_CLIENT, &id_cache)) { + /* Resolve the client info */ + silc_client_get_client_by_id_resolve(client, conn, remote_id, + silc_client_private_message_cb, + silc_packet_context_dup(packet)); + return; + } + + remote_client = (SilcClientEntry)id_cache->context; + + /* Parse the payload and decrypt it also if private message key is set */ + payload = silc_private_message_payload_parse(packet->buffer, + remote_client->send_key); + if (!payload) { + silc_free(remote_id); + return; + } /* Pass the private message to application */ - client->ops->private_message(client, conn, remote_client, message); + client->ops->private_message(client, conn, remote_client, + silc_private_message_get_message(payload, + NULL)); /* See if we are away (gone). If we are away we will reply to the sender with the set away message. */ @@ -200,14 +190,10 @@ void silc_client_private_message(SilcClient client, } out: + if (payload) + silc_private_message_payload_free(payload); if (remote_id) silc_free(remote_id); - - if (message) { - memset(message, 0, buffer->len); - silc_free(message); - } - silc_free(nickname); } /* Function that actually employes the received private message key */ diff --git a/lib/silccore/Makefile.am b/lib/silccore/Makefile.am index b22ae264..73100fa8 100644 --- a/lib/silccore/Makefile.am +++ b/lib/silccore/Makefile.am @@ -30,7 +30,8 @@ libsilccore_a_SOURCES = \ silcsockconn.c \ silcpayload.c \ silcnotify.c \ - silcauth.c + silcauth.c \ + silcprivate.c EXTRA_DIST = *.h diff --git a/lib/silccore/silcchannel.c b/lib/silccore/silcchannel.c index 26f7f4dc..74265436 100644 --- a/lib/silccore/silcchannel.c +++ b/lib/silccore/silcchannel.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2000 Pekka Riikonen + Copyright (C) 1997 - 2001 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 diff --git a/lib/silccore/silcchannel.h b/lib/silccore/silcchannel.h index 1059b156..50e40041 100644 --- a/lib/silccore/silcchannel.h +++ b/lib/silccore/silcchannel.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2000 Pekka Riikonen + Copyright (C) 1997 - 2001 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 diff --git a/lib/silccore/silcprivate.c b/lib/silccore/silcprivate.c new file mode 100644 index 00000000..45e81d85 --- /dev/null +++ b/lib/silccore/silcprivate.c @@ -0,0 +1,180 @@ +/* + + silcprivate.c + + Author: Pekka Riikonen + + Copyright (C) 1997 - 2001 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ +/* Includes the Private Message Payload implementation */ +/* $Id$ */ + +#include "silcincludes.h" +#include "silcprivate.h" + +/****************************************************************************** + + Private Message Payload + +******************************************************************************/ + +/* Private Message Payload structure. Contents of this structure is parsed + from SILC packets. */ +struct SilcPrivateMessagePayloadStruct { + unsigned short nickname_len; + unsigned char *nickname; + unsigned short flags; + unsigned short message_len; + unsigned char *message; +}; + +/* Parses private message payload returning new private mesage payload + structure. This also decrypts the message if the `cipher' is provided. */ + +SilcPrivateMessagePayload +silc_private_message_payload_parse(SilcBuffer buffer, SilcCipher cipher) +{ + SilcPrivateMessagePayload new; + int ret; + + SILC_LOG_DEBUG(("Parsing private message payload")); + + /* Decrypt the payload */ + if (cipher) + silc_cipher_decrypt(cipher, buffer->data, buffer->data, + buffer->len, cipher->iv); + + new = silc_calloc(1, sizeof(*new)); + + /* Parse the Private Message Payload. Ignore the padding. */ + ret = silc_buffer_unformat(buffer, + SILC_STR_UI16_NSTRING_ALLOC(&new->nickname, + &new->nickname_len), + SILC_STR_UI_SHORT(&new->flags), + SILC_STR_UI16_NSTRING_ALLOC(&new->message, + &new->message_len), + SILC_STR_END); + if (ret == -1) + goto err; + + if ((new->message_len < 1 || new->message_len > buffer->len) || + (new->nickname_len < 1 || new->nickname_len > buffer->len)) { + SILC_LOG_ERROR(("Incorrect private message payload in packet, " + "packet dropped")); + goto err; + } + + return new; + + err: + silc_private_message_payload_free(new); + return NULL; +} + +/* Encodes private message payload into a buffer and returns it. If + the cipher is provided the packet is also encrypted here. It is provided + if the private message private keys are used. */ + +SilcBuffer silc_private_message_payload_encode(unsigned int nickname_len, + unsigned char *nickname, + unsigned short flags, + unsigned short data_len, + unsigned char *data, + SilcCipher cipher) +{ + int i; + SilcBuffer buffer; + unsigned int len, pad_len = 0; + unsigned char pad[SILC_PACKET_MAX_PADLEN]; + + SILC_LOG_DEBUG(("Encoding private message payload")); + + len = 2 + nickname_len + 4 + data_len; + + if (cipher) { + /* Calculate length of padding. */ + pad_len = SILC_PACKET_PADLEN((len + 2)); + len += pad_len; + + /* Generate padding */ + for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte(); + } + + /* Allocate private message payload buffer */ + buffer = silc_buffer_alloc(len); + + /* Encode the Channel Message Payload */ + silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + silc_buffer_format(buffer, + SILC_STR_UI_SHORT(nickname_len), + SILC_STR_UI_XNSTRING(nickname, nickname_len), + SILC_STR_UI_SHORT(flags), + SILC_STR_UI_SHORT(data_len), + SILC_STR_UI_XNSTRING(data, data_len), + SILC_STR_UI_XNSTRING(pad, pad_len), + SILC_STR_END); + + if (cipher) { + /* Encrypt payload of the packet. */ + silc_cipher_encrypt(cipher, buffer->data, buffer->data, + buffer->len, cipher->iv); + memset(pad, 0, sizeof(pad)); + } + + return buffer; +} + +/* Free's Private Message Payload */ + +void silc_private_message_payload_free(SilcPrivateMessagePayload payload) +{ + silc_free(payload->nickname); + if (payload->message) { + memset(payload->message, 0, payload->message_len); + silc_free(payload->message); + } + silc_free(payload); +} + +/* Return nickname */ + +unsigned char * +silc_private_message_get_nickname(SilcPrivateMessagePayload payload, + unsigned int *nickname_len) +{ + if (nickname_len) + *nickname_len = payload->nickname_len; + + return payload->nickname; +} + +/* Return message */ + +unsigned char * +silc_private_message_get_message(SilcPrivateMessagePayload payload, + unsigned int *message_len) +{ + if (message_len) + *message_len = payload->message_len; + + return payload->message; +} + +/* Return flags */ + +unsigned short +silc_private_message_get_flags(SilcPrivateMessagePayload payload) +{ + return payload->flags; +} diff --git a/lib/silccore/silcprivate.h b/lib/silccore/silcprivate.h new file mode 100644 index 00000000..4cc2872f --- /dev/null +++ b/lib/silccore/silcprivate.h @@ -0,0 +1,47 @@ +/* + + silcprivate.h + + Author: Pekka Riikonen + + Copyright (C) 1997 - 2001 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#ifndef SILCPRIVATE_H +#define SILCPRIVATE_H + +/* Forward declaration of the Private Message Payload. */ +typedef struct SilcPrivateMessagePayloadStruct *SilcPrivateMessagePayload; + +/* Prototypes */ + +SilcPrivateMessagePayload +silc_private_message_payload_parse(SilcBuffer buffer, SilcCipher cipher); +SilcBuffer silc_private_message_payload_encode(unsigned int nickname_len, + unsigned char *nickname, + unsigned short flags, + unsigned short data_len, + unsigned char *data, + SilcCipher cipher); +void silc_private_message_payload_free(SilcPrivateMessagePayload payload); +unsigned char * +silc_private_message_get_nickname(SilcPrivateMessagePayload payload, + unsigned int *nickname_len); +unsigned char * +silc_private_message_get_message(SilcPrivateMessagePayload payload, + unsigned int *message_len); +unsigned short +silc_private_message_get_flags(SilcPrivateMessagePayload payload); + +#endif diff --git a/lib/silcutil/silcbuffmt.c b/lib/silcutil/silcbuffmt.c index 08c8e290..87fa12ae 100644 --- a/lib/silcutil/silcbuffmt.c +++ b/lib/silcutil/silcbuffmt.c @@ -145,9 +145,6 @@ int silc_buffer_format(SilcBuffer dst, ...) fail: SILC_LOG_DEBUG(("Error occured while formatting data")); -#ifdef SILC_DEBUG - assert(FALSE); -#endif return -1; ok: @@ -370,9 +367,6 @@ int silc_buffer_unformat(SilcBuffer src, ...) fail: SILC_LOG_DEBUG(("Error occured while unformatting buffer")); -#ifdef SILC_DEBUG - assert(FALSE); -#endif return -1; ok: