/************************** Channel Message Send ****************************/
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+ SilcChannelEntry channel;
+} *SilcClientChannelMessageContext;
+
+/* Message payload encoding callback */
+
+static void silc_client_send_channel_message_final(SilcBuffer message,
+ void *context)
+{
+ SilcClientChannelMessageContext c = context;
+
+ /* Send the channel message */
+ if (message)
+ silc_packet_send_ext(c->conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0,
+ 0, NULL, SILC_ID_CHANNEL, &c->channel->id,
+ silc_buffer_datalen(message), NULL, NULL);
+
+ silc_client_unref_channel(c->client, c->conn, c->channel);
+ silc_free(c);
+}
+
/* Sends channel message to `channel'. */
SilcBool silc_client_send_channel_message(SilcClient client,
unsigned char *data,
SilcUInt32 data_len)
{
+ SilcClientChannelMessageContext c;
SilcChannelUser chu;
- SilcBuffer buffer;
SilcCipher cipher;
SilcHmac hmac;
- SilcBool ret;
SilcID sid, rid;
SILC_LOG_DEBUG(("Sending channel message"));
if (silc_unlikely(!client || !conn || !channel))
return FALSE;
- if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash))
+ if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash)) {
+ SILC_LOG_ERROR(("Cannot send signed message without hash, missing "
+ "arguments"));
return FALSE;
+ }
if (silc_unlikely(conn->internal->disconnected))
return FALSE;
if (channel->internal.private_keys) {
if (key) {
/* Use key application specified */
- cipher = key->cipher;
+ cipher = key->send_key;
hmac = key->hmac;
} else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
channel->internal.curr_key) {
/* Use current private key */
- cipher = channel->internal.curr_key->cipher;
+ cipher = channel->internal.curr_key->send_key;
hmac = channel->internal.curr_key->hmac;
} else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
!channel->internal.curr_key &&
and private keys are set. */
silc_dlist_start(channel->internal.private_keys);
key = silc_dlist_get(channel->internal.private_keys);
- cipher = key->cipher;
+ cipher = key->send_key;
hmac = key->hmac;
/* Use this key as current private key */
return FALSE;
}
- /* Encode the message payload. This also encrypts the message payload. */
+ c = silc_calloc(1, sizeof(*c));
+ if (!c)
+ return FALSE;
+
+ c->client = client;
+ c->conn = conn;
+ c->channel = silc_client_ref_channel(client, conn, channel);
+
sid.type = SILC_ID_CLIENT;
sid.u.client_id = chu->client->id;
rid.type = SILC_ID_CHANNEL;
rid.u.channel_id = chu->channel->id;
- buffer = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
- cipher, hmac, client->rng, NULL,
- conn->private_key, hash, &sid, &rid,
- NULL);
- if (silc_unlikely(!buffer)) {
- SILC_LOG_ERROR(("Error encoding channel message"));
- return FALSE;
- }
- /* Send the channel message */
- ret = silc_packet_send_ext(conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0,
- 0, NULL, SILC_ID_CHANNEL, &channel->id,
- silc_buffer_datalen(buffer), NULL, NULL);
+ /* Encode the message payload. This also encrypts the message payload. */
+ silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
+ cipher, hmac, client->rng, NULL,
+ conn->private_key, hash, &sid, &rid, NULL,
+ silc_client_send_channel_message_final, c);
- silc_buffer_free(buffer);
- return ret;
+ return TRUE;
}
/************************* Channel Message Receive **************************/
/* Parse the message payload. This also decrypts the payload */
payload = silc_message_payload_parse(silc_buffer_data(buffer),
silc_buffer_len(buffer),
- FALSE, FALSE, key->cipher,
+ FALSE, FALSE, key->receive_key,
key->hmac, packet->src_id,
packet->src_id_len,
packet->dst_id,
return FALSE;
}
+ channel->cipher = silc_cipher_get_name(channel->internal.send_key);
+ channel->hmac = silc_hmac_get_name(channel->internal.hmac);
+
/* Set HMAC key */
silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key,
tmp_len, hash);
entry->name = name ? strdup(name) : NULL;
/* Allocate the cipher and set the key */
- if (!silc_cipher_alloc(cipher, &entry->cipher)) {
+ if (!silc_cipher_alloc(cipher, &entry->send_key)) {
silc_free(entry);
silc_free(entry->name);
silc_ske_free_key_material(keymat);
return FALSE;
}
- silc_cipher_set_key(entry->cipher, keymat->send_enc_key,
+ if (!silc_cipher_alloc(cipher, &entry->receive_key)) {
+ silc_free(entry);
+ silc_free(entry->name);
+ silc_cipher_free(entry->send_key);
+ silc_ske_free_key_material(keymat);
+ return FALSE;
+ }
+ silc_cipher_set_key(entry->send_key, keymat->send_enc_key,
keymat->enc_key_len, TRUE);
+ silc_cipher_set_key(entry->receive_key, keymat->send_enc_key,
+ keymat->enc_key_len, FALSE);
/* Generate HMAC key from the channel key data and set it */
if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
silc_free(entry);
silc_free(entry->name);
- silc_cipher_free(entry->cipher);
+ silc_cipher_free(entry->send_key);
+ silc_cipher_free(entry->receive_key);
silc_ske_free_key_material(keymat);
return FALSE;
}
/* Add to the private keys list */
silc_dlist_add(channel->internal.private_keys, entry);
- if (!channel->internal.curr_key)
+ if (!channel->internal.curr_key) {
channel->internal.curr_key = entry;
+ channel->cipher = silc_cipher_get_name(entry->send_key);
+ channel->hmac = silc_cipher_get_name(entry->send_key);
+ }
/* Free the key material */
silc_ske_free_key_material(keymat);
while ((entry = silc_dlist_get(channel->internal.private_keys))) {
silc_dlist_del(channel->internal.private_keys, entry);
silc_free(entry->name);
- silc_cipher_free(entry->cipher);
+ silc_cipher_free(entry->send_key);
+ silc_cipher_free(entry->receive_key);
silc_hmac_free(entry->hmac);
silc_free(entry);
}
channel->internal.curr_key = NULL;
+ if (channel->internal.send_key)
+ channel->cipher = silc_cipher_get_name(channel->internal.send_key);
+ else
+ channel->cipher = NULL;
+ if (channel->internal.hmac)
+ channel->hmac = silc_hmac_get_name(channel->internal.hmac);
+ else
+ channel->hmac = NULL;
silc_dlist_uninit(channel->internal.private_keys);
channel->internal.private_keys = NULL;
if (entry != key)
continue;
- if (channel->internal.curr_key == entry)
+ if (channel->internal.curr_key == entry) {
channel->internal.curr_key = NULL;
+ channel->cipher = silc_cipher_get_name(channel->internal.send_key);
+ channel->hmac = silc_hmac_get_name(channel->internal.hmac);
+ }
silc_dlist_del(channel->internal.private_keys, entry);
silc_free(entry->name);
- silc_cipher_free(entry->cipher);
+ silc_cipher_free(entry->send_key);
+ silc_cipher_free(entry->receive_key);
silc_hmac_free(entry->hmac);
silc_free(entry);
if (!channel)
return;
channel->internal.curr_key = key;
+ channel->cipher = silc_cipher_get_name(key->send_key);
+ channel->hmac = silc_hmac_get_name(key->hmac);
}
/***************************** Utility routines *****************************/
SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel,
unsigned char *chpk_list,
- SilcUInt32 chpk_list_len)
+ SilcUInt32 chpk_list_len,
+ SilcBool remove_all)
{
SilcArgumentDecodedList a, b;
SilcDList chpks;
SilcBool found;
+ if (remove_all) {
+ /* Remove all channel public keys */
+ if (!channel->channel_pubkeys)
+ return FALSE;
+
+ silc_dlist_start(channel->channel_pubkeys);
+ while ((b = silc_dlist_get(channel->channel_pubkeys)))
+ silc_dlist_del(channel->channel_pubkeys, b);
+
+ silc_dlist_uninit(channel->channel_pubkeys);
+ channel->channel_pubkeys = NULL;
+
+ return TRUE;
+ }
+
+ /* Parse channel public key list and add or remove public keys */
chpks = silc_argument_list_parse_decoded(chpk_list, chpk_list_len,
SILC_ARGUMENT_PUBLIC_KEY);
if (!chpks)