/* This file includes the private message sending and receiving routines
and private message key handling routines. */
-#include "clientlibincludes.h"
+#include "silcincludes.h"
+#include "silcclient.h"
#include "client_internal.h"
/* Sends private message to remote client. If private message key has
SilcClientEntry client_entry,
SilcMessageFlags flags,
unsigned char *data,
- uint32 data_len,
+ SilcUInt32 data_len,
int force_send)
{
- SilcSocketConnection sock = conn->sock;
+ SilcSocketConnection sock;
SilcBuffer buffer;
SilcPacketContext packetdata;
+ const SilcBufferStruct packet;
SilcCipher cipher;
SilcHmac hmac;
+ int block_len;
+ assert(client && conn && client_entry);
+ sock = conn->sock;
SILC_LOG_DEBUG(("Sending private message"));
/* Encode private message payload */
buffer = silc_private_message_payload_encode(flags,
data_len, data,
- client_entry->send_key);
+ client_entry->send_key,
+ client->rng);
/* If we don't have private message specific key then private messages
are just as any normal packet thus call normal packet sending. If
/* We have private message specific key */
/* Get data used in the encryption */
- cipher = client_entry->send_key;
- hmac = conn->hmac_send;
+ cipher = conn->internal->send_key;
+ hmac = conn->internal->hmac_send;
+ block_len = silc_cipher_get_block_len(cipher);
/* Set the packet context pointers. */
+ data = buffer->data;
+ data_len = buffer->len;
packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
packetdata.src_id = conn->local_id_data;
packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
packetdata.dst_id_type = SILC_ID_CLIENT;
- packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
+ data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len);
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
packetdata.src_id_len + packetdata.dst_id_len;
packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
packetdata.src_id_len +
- packetdata.dst_id_len));
-
- /* Prepare outgoing data buffer for packet sending */
- silc_packet_send_prepare(sock,
- SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len +
- packetdata.dst_id_len,
- packetdata.padlen,
- buffer->len);
-
- packetdata.buffer = sock->outbuf;
-
- /* Put the actual encrypted message payload data into the buffer. */
- silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
+ packetdata.dst_id_len), block_len);
/* Create the outgoing packet */
- silc_packet_assemble(&packetdata);
+ if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
+ data, data_len, (const SilcBuffer)&packet)) {
+ SILC_LOG_ERROR(("Error assembling packet"));
+ goto out;
+ }
/* Encrypt the header and padding of the packet. */
- cipher = conn->send_key;
- silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
+ silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
+ (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
packetdata.src_id_len + packetdata.dst_id_len +
packetdata.padlen);
- SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
- sock->outbuf->data, sock->outbuf->len);
+ SILC_LOG_HEXDUMP(("Private message packet, len %d", packet.len),
+ packet.data, packet.len);
/* Now actually send the packet */
- silc_client_packet_send_real(client, sock, force_send, FALSE);
+ silc_client_packet_send_real(client, sock, force_send);
silc_free(packetdata.dst_id);
out:
static void silc_client_private_message_cb(SilcClient client,
SilcClientConnection conn,
SilcClientEntry *clients,
- uint32 clients_count,
+ SilcUInt32 clients_count,
void *context)
{
SilcPacketContext *packet = (SilcPacketContext *)context;
+ if (!clients) {
+ silc_packet_context_free(packet);
+ return;
+ }
+
silc_client_private_message(client, conn->sock, packet);
silc_packet_context_free(packet);
}
{
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
SilcPrivateMessagePayload payload = NULL;
- SilcIDCacheEntry id_cache;
SilcClientID *remote_id = NULL;
SilcClientEntry remote_client;
+ SilcMessageFlags flags;
+ unsigned char *message;
+ SilcUInt32 message_len;
+ SilcCipher cipher = NULL;
if (packet->src_id_type != SILC_ID_CLIENT)
goto out;
goto out;
/* Check whether we know this client already */
- if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)remote_id,
- NULL, NULL,
- silc_hash_client_id_compare, NULL,
- &id_cache)) {
+ remote_client = silc_client_get_client_by_id(client, conn, remote_id);
+ if (!remote_client || !remote_client->nickname) {
+ if (remote_client) {
+ if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
+ remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
+ goto out;
+ }
+ remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
+ remote_client->resolve_cmd_ident = conn->cmd_ident + 1;
+ }
+
/* Resolve the client info */
- silc_client_get_client_by_id_resolve(client, conn, remote_id,
+ silc_client_get_client_by_id_resolve(client, conn, remote_id, NULL,
silc_client_private_message_cb,
silc_packet_context_dup(packet));
return;
}
- remote_client = (SilcClientEntry)id_cache->context;
+ cipher = remote_client->receive_key;
+ if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher) {
+ silc_free(remote_id);
+ return;
+ }
/* 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);
+ payload = silc_private_message_payload_parse(packet->buffer->data,
+ packet->buffer->len, cipher);
if (!payload) {
silc_free(remote_id);
return;
}
+ flags = silc_private_message_get_flags(payload);
+
/* Pass the private message to application */
- client->ops->private_message(client, conn, remote_client,
- silc_private_message_get_flags(payload),
- silc_private_message_get_message(payload,
- NULL));
+ message = silc_private_message_get_message(payload, &message_len);
+ client->internal->ops->private_message(client, conn, remote_client, 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. */
- if (conn->away && conn->away->away) {
+ if (conn->internal->away && conn->internal->away->away &&
+ !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
/* If it's me, ignore */
if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
goto out;
/* Send the away message */
silc_client_send_private_message(client, conn, remote_client,
- SILC_MESSAGE_FLAG_AUTOREPLY,
- conn->away->away,
- strlen(conn->away->away), TRUE);
+ SILC_MESSAGE_FLAG_AUTOREPLY |
+ SILC_MESSAGE_FLAG_NOREPLY,
+ conn->internal->away->away,
+ strlen(conn->internal->away->away), TRUE);
}
out:
if (payload)
silc_private_message_payload_free(payload);
- if (remote_id)
- silc_free(remote_id);
+ silc_free(remote_id);
}
/* Function that actually employes the received private message key */
static void silc_client_private_message_key_cb(SilcClient client,
SilcClientConnection conn,
SilcClientEntry *clients,
- uint32 clients_count,
+ SilcUInt32 clients_count,
void *context)
{
SilcPacketContext *packet = (SilcPacketContext *)context;
unsigned char *key;
- uint16 key_len;
+ SilcUInt16 key_len;
unsigned char *cipher;
int ret;
/* Now take the key in use */
if (!silc_client_add_private_message_key(client, conn, clients[0],
- cipher, key, key_len, FALSE))
+ cipher, key, key_len, FALSE, TRUE))
goto out;
/* Print some info for application */
- client->ops->say(client, conn,
- "Received private message key from %s%s%s %s%s%s",
- clients[0]->nickname,
- clients[0]->server ? "@" : "",
- clients[0]->server ? clients[0]->server : "",
- clients[0]->username ? "(" : "",
- clients[0]->username ? clients[0]->username : "",
- clients[0]->username ? ")" : "");
+ client->internal->ops->say(
+ client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Received private message key from %s%s%s %s%s%s",
+ clients[0]->nickname,
+ clients[0]->server ? "@" : "",
+ clients[0]->server ? clients[0]->server : "",
+ clients[0]->username ? "(" : "",
+ clients[0]->username ? clients[0]->username : "",
+ clients[0]->username ? ")" : "");
out:
silc_packet_context_free(packet);
return;
silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
+ NULL,
silc_client_private_message_key_cb,
silc_packet_context_dup(packet));
silc_free(remote_id);
requirements of the SILC protocol are met. The API, however, allows
to allocate any cipher.
+ If `responder' is TRUE then the sending and receiving keys will be
+ set according the client being the receiver of the private key. If
+ FALSE the client is being the sender (or negotiator) of the private
+ key.
+
It is not necessary to set key for normal private message usage. If the
key is not set then the private messages are encrypted using normal
session keys. Setting the private key, however, increases the security.
SilcClientEntry client_entry,
char *cipher,
unsigned char *key,
- uint32 key_len,
- int generate_key)
+ SilcUInt32 key_len,
+ bool generate_key,
+ bool responder)
{
unsigned char private_key[32];
- uint32 len;
+ SilcUInt32 len;
int i;
SilcSKEKeyMaterial *keymat;
- assert(client_entry);
+ assert(client && client_entry);
/* Return FALSE if key already set */
if (client_entry->send_key && client_entry->receive_key)
return FALSE;
if (!cipher)
- cipher = "aes-256-cbc";
+ cipher = SILC_DEFAULT_CIPHER;
/* Check the requested cipher */
if (!silc_cipher_is_supported(cipher))
}
/* Save the key */
- client_entry->key = silc_calloc(key_len, sizeof(*client_entry->key));
- memcpy(client_entry->key, key, key_len);
+ client_entry->key = silc_memdup(key, key_len);
client_entry->key_len = key_len;
/* Produce the key material as the protocol defines */
silc_cipher_alloc(cipher, &client_entry->receive_key);
/* Set the keys */
- silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
- keymat->enc_key_len);
- silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
- silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
- keymat->enc_key_len);
- silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
+ if (responder == TRUE) {
+ silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
+ silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
+ } else {
+ silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
+ silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
+ }
/* Free the key material */
silc_ske_free_key_material(keymat);
SilcClientConnection conn,
SilcClientEntry client_entry,
char *cipher,
- SilcSKEKeyMaterial *key)
+ SilcSKEKeyMaterial *key,
+ bool responder)
{
- assert(client_entry);
+ assert(client && client_entry);
/* Return FALSE if key already set */
if (client_entry->send_key && client_entry->receive_key)
return FALSE;
if (!cipher)
- cipher = "aes-256-cbc";
+ cipher = SILC_DEFAULT_CIPHER;
/* Check the requested cipher */
if (!silc_cipher_is_supported(cipher))
silc_cipher_alloc(cipher, &client_entry->receive_key);
/* Set the keys */
- silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
- key->enc_key_len);
- silc_cipher_set_iv(client_entry->send_key, key->send_iv);
- silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
- key->enc_key_len);
- silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
+ if (responder == TRUE) {
+ silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
+ key->enc_key_len);
+ silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
+ silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
+ key->enc_key_len);
+ silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
+ } else {
+ silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
+ key->enc_key_len);
+ silc_cipher_set_iv(client_entry->send_key, key->send_iv);
+ silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
+ key->enc_key_len);
+ silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
+ }
return TRUE;
}
SilcClientEntry client_entry,
int force_send)
{
- SilcSocketConnection sock = conn->sock;
+ SilcSocketConnection sock;
SilcBuffer buffer;
int cipher_len;
+ const char *cipher;
+
+ assert(client && conn && client_entry);
+ sock = conn->sock;
if (!client_entry->send_key || !client_entry->key)
return FALSE;
SILC_LOG_DEBUG(("Sending private message key"));
- cipher_len = strlen(client_entry->send_key->cipher->name);
+ cipher = silc_cipher_get_name(client_entry->send_key);
+ cipher_len = strlen(cipher);
/* Create private message key payload */
buffer = silc_buffer_alloc(2 + client_entry->key_len);
SILC_STR_UI_XNSTRING(client_entry->key,
client_entry->key_len),
SILC_STR_UI_SHORT(cipher_len),
- SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
+ SILC_STR_UI_XNSTRING(cipher,
cipher_len),
SILC_STR_END);
SilcClientConnection conn,
SilcClientEntry client_entry)
{
- assert(client_entry);
+ assert(client && client_entry);
if (!client_entry->send_key && !client_entry->receive_key)
return FALSE;
SilcPrivateMessageKeys
silc_client_list_private_message_keys(SilcClient client,
SilcClientConnection conn,
- uint32 *key_count)
+ SilcUInt32 *key_count)
{
SilcPrivateMessageKeys keys;
- uint32 count = 0;
+ SilcUInt32 count = 0;
SilcIDCacheEntry id_cache;
SilcIDCacheList list;
SilcClientEntry entry;
- if (!silc_idcache_get_all(conn->client_cache, &list))
+ assert(client && conn);
+
+ if (!silc_idcache_get_all(conn->internal->client_cache, &list))
return NULL;
if (!silc_idcache_list_count(list)) {
if (entry->send_key) {
keys[count].client_entry = entry;
- keys[count].cipher = entry->send_key->cipher->name;
+ keys[count].cipher = (char *)silc_cipher_get_name(entry->send_key);
keys[count].key = entry->generated == FALSE ? entry->key : NULL;
keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
count++;
silc_client_list_private_message_keys. */
void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
- uint32 key_count)
+ SilcUInt32 key_count)
{
silc_free(keys);
}
SilcClientConnection conn,
char *message)
{
- if (!message && conn->away) {
- silc_free(conn->away->away);
- silc_free(conn->away);
- conn->away = NULL;
+ assert(client && conn);
+
+ if (!message && conn->internal->away) {
+ silc_free(conn->internal->away->away);
+ silc_free(conn->internal->away);
+ conn->internal->away = NULL;
}
if (message) {
- if (!conn->away)
- conn->away = silc_calloc(1, sizeof(*conn->away));
- if (conn->away->away)
- silc_free(conn->away->away);
- conn->away->away = strdup(message);
+ if (!conn->internal->away)
+ conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
+ if (conn->internal->away->away)
+ silc_free(conn->internal->away->away);
+ conn->internal->away->away = strdup(message);
}
}