+Wed Mar 28 20:50:47 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * 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 <priikone@poseidon.pspt.fi>
* Added SilcKeyAgreementStatus type to the key agreement routines
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,
}
}
- 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],
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,
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,
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);
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;
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);
}
}
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))
~ Nickname ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Flags | Message Data Length |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
~ Message Data ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ Padding ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
.in 3
.ce
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
#include "silcnotify.h"
#include "silcmode.h"
#include "silcauth.h"
+#include "silcprivate.h"
/* TRQ (SilcList API and SilcDList API) */
#include "silclist.h"
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;
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
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 */
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. */
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)
/* 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. */
}
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 */
silcsockconn.c \
silcpayload.c \
silcnotify.c \
- silcauth.c
+ silcauth.c \
+ silcprivate.c
EXTRA_DIST = *.h
Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- 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
Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- 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
--- /dev/null
+/*
+
+ silcprivate.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ 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;
+}
--- /dev/null
+/*
+
+ silcprivate.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ 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
fail:
SILC_LOG_DEBUG(("Error occured while formatting data"));
-#ifdef SILC_DEBUG
- assert(FALSE);
-#endif
return -1;
ok:
fail:
SILC_LOG_DEBUG(("Error occured while unformatting buffer"));
-#ifdef SILC_DEBUG
- assert(FALSE);
-#endif
return -1;
ok: