5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2004, 2006 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /************************** Channel Message Send ****************************/
27 /* Sends channel message to `channel'. */
29 SilcBool silc_client_send_channel_message(SilcClient client,
30 SilcClientConnection conn,
31 SilcChannelEntry channel,
32 SilcChannelPrivateKey key,
33 SilcMessageFlags flags,
44 SILC_LOG_DEBUG(("Sending channel message"));
46 if (!client || !conn || !channel)
48 if (flags & SILC_MESSAGE_FLAG_SIGNED && !hash)
51 chu = silc_client_on_channel(channel, conn->local_entry);
53 client->internal->ops->say(conn->client, conn,
54 SILC_CLIENT_MESSAGE_AUDIT,
55 "Cannot talk to channel: not joined");
59 /* Check if it is allowed to send messages to this channel by us. */
60 if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chu->mode)
62 if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
63 chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
64 !(chu->mode & SILC_CHANNEL_UMODE_CHANFO))
66 if (chu->mode & SILC_CHANNEL_UMODE_QUIET)
69 /* Take the key to be used */
70 if (channel->internal.private_keys) {
72 /* Use key application specified */
75 } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
76 channel->internal.curr_key) {
77 /* Use current private key */
78 cipher = channel->internal.curr_key->cipher;
79 hmac = channel->internal.curr_key->hmac;
80 } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
81 !channel->internal.curr_key &&
82 channel->internal.private_keys) {
83 /* Use just some private key since we don't know what to use
84 and private keys are set. */
85 silc_dlist_start(channel->internal.private_keys);
86 key = silc_dlist_get(channel->internal.private_keys);
90 /* Use this key as current private key */
91 channel->internal.curr_key = key;
93 /* Use normal channel key generated by the server */
94 cipher = channel->internal.channel_key;
95 hmac = channel->internal.hmac;
98 /* Use normal channel key generated by the server */
99 cipher = channel->internal.channel_key;
100 hmac = channel->internal.hmac;
103 if (!cipher || !hmac) {
104 SILC_LOG_ERROR(("No cipher and HMAC for channel"));
108 /* Encode the message payload. This also encrypts the message payload. */
109 buffer = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
110 cipher, hmac, client->rng, NULL,
111 conn->private_key, hash, NULL);
113 SILC_LOG_ERROR(("Error encoding channel message"));
117 /* Send the channel message */
118 ret = silc_packet_send_ext(conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0,
119 0, NULL, SILC_ID_CHANNEL, &channel->id,
120 silc_buffer_datalen(buffer), NULL, NULL);
122 silc_buffer_free(buffer);
126 /************************* Channel Message Receive **************************/
128 /* Client resolving callback. Continues with the channel message processing */
130 static void silc_client_channel_message_resolved(SilcClient client,
131 SilcClientConnection conn,
136 /* If no client found, ignore the channel message, a silent error */
138 silc_fsm_next(context, silc_client_channel_message_error);
140 /* Continue processing the channel message packet */
141 SILC_FSM_CALL_CONTINUE(context);
144 /* Process received channel message */
146 SILC_FSM_STATE(silc_client_channel_message)
148 SilcClientConnection conn = fsm_context;
149 SilcClient client = conn->client;
150 SilcPacket packet = state_context;
151 SilcBuffer buffer = &packet->buffer;
152 SilcMessagePayload payload = NULL;
153 SilcChannelEntry channel;
154 SilcClientEntry client_entry;
155 SilcClientID remote_id;
156 SilcChannelID channel_id;
157 unsigned char *message;
158 SilcUInt32 message_len;
159 SilcChannelPrivateKey key = NULL;
161 SILC_LOG_DEBUG(("Received channel message"));
163 if (packet->dst_id_type != SILC_ID_CHANNEL) {
164 /** Invalid packet */
165 silc_fsm_next(fsm, silc_client_channel_message_error);
166 return SILC_FSM_CONTINUE;
169 if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
170 &remote_id, sizeof(remote_id))) {
171 /** Invalid source ID */
172 silc_fsm_next(fsm, silc_client_channel_message_error);
173 return SILC_FSM_CONTINUE;
176 /* Get sender client entry */
177 client_entry = silc_client_get_client_by_id(client, conn, &remote_id);
178 if (!client_entry || !client_entry->nickname[0]) {
179 /** Resolve client info */
180 silc_client_unref_client(client, conn, client_entry);
181 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
182 client, conn, &remote_id, NULL,
183 silc_client_channel_message_resolved,
188 if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
189 &channel_id, sizeof(channel_id))) {
190 /** Invalid destination ID */
191 silc_fsm_next(fsm, silc_client_channel_message_error);
192 return SILC_FSM_CONTINUE;
195 /* Find the channel */
196 channel = silc_client_get_channel_by_id(client, conn, &channel_id);
198 /** Unknown channel */
199 silc_fsm_next(fsm, silc_client_channel_message_error);
200 return SILC_FSM_CONTINUE;
203 /* If there is no channel private key then just decrypt the message
204 with the channel key. If private keys are set then just go through
205 all private keys and check what decrypts correctly. */
206 if (!channel->internal.private_keys) {
207 /* Parse the channel message payload. This also decrypts the payload */
208 payload = silc_message_payload_parse(silc_buffer_data(buffer),
209 silc_buffer_len(buffer), FALSE,
210 FALSE, channel->internal.channel_key,
211 channel->internal.hmac, NULL,
214 /* If decryption failed and we have just performed channel key rekey
215 we will use the old key in decryption. If that fails too then we
216 cannot do more and will drop the packet. */
221 if (!channel->internal.old_channel_keys ||
222 !silc_dlist_count(channel->internal.old_channel_keys))
225 SILC_LOG_DEBUG(("Attempting to decrypt with old channel key(s)"));
227 silc_dlist_end(channel->internal.old_channel_keys);
228 silc_dlist_end(channel->internal.old_hmacs);
229 while ((cipher = silc_dlist_get(channel->internal.old_channel_keys))) {
230 hmac = silc_dlist_get(channel->internal.old_hmacs);
234 payload = silc_message_payload_parse(silc_buffer_data(buffer),
235 silc_buffer_len(buffer),
236 FALSE, FALSE, cipher, hmac,
245 /* If the private key mode is not set on the channel then try the actual
246 channel key first before trying private keys. */
247 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
248 payload = silc_message_payload_parse(silc_buffer_data(buffer),
249 silc_buffer_len(buffer),
251 channel->internal.channel_key,
252 channel->internal.hmac, NULL,
256 silc_dlist_start(channel->internal.private_keys);
257 while ((key = silc_dlist_get(channel->internal.private_keys))) {
258 /* Parse the message payload. This also decrypts the payload */
259 payload = silc_message_payload_parse(silc_buffer_data(buffer),
260 silc_buffer_len(buffer),
261 FALSE, FALSE, key->cipher,
262 key->hmac, NULL, FALSE, NULL);
266 if (key == SILC_LIST_END)
271 message = silc_message_get_data(payload, &message_len);
273 /* Pass the message to application */
274 client->internal->ops->channel_message(
275 client, conn, client_entry, channel, payload,
276 key, silc_message_get_flags(payload),
277 message, message_len);
280 silc_client_unref_client(client, conn, client_entry);
281 silc_client_unref_channel(client, conn, channel);
283 silc_message_payload_free(payload);
284 return SILC_FSM_FINISH;
287 /* Channel message error. */
289 SILC_FSM_STATE(silc_client_channel_message_error)
291 SilcPacket packet = state_context;
292 silc_packet_free(packet);
293 return SILC_FSM_FINISH;
296 /******************************* Channel Key ********************************/
298 /* Timeout callback that is called after a short period of time after the
299 new channel key has been created. This removes the first channel key
302 SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
304 SilcChannelEntry channel = (SilcChannelEntry)context;
308 if (channel->internal.old_channel_keys) {
309 silc_dlist_start(channel->internal.old_channel_keys);
310 key = silc_dlist_get(channel->internal.old_channel_keys);
312 silc_dlist_del(channel->internal.old_channel_keys, key);
313 silc_cipher_free(key);
317 if (channel->internal.old_hmacs) {
318 silc_dlist_start(channel->internal.old_hmacs);
319 hmac = silc_dlist_get(channel->internal.old_hmacs);
321 silc_dlist_del(channel->internal.old_hmacs, hmac);
322 silc_hmac_free(hmac);
327 /* Saves channel key from encoded `key_payload'. This is used when we receive
328 Channel Key Payload and when we are processing JOIN command reply. */
330 SilcBool silc_client_save_channel_key(SilcClient client,
331 SilcClientConnection conn,
332 SilcBuffer key_payload,
333 SilcChannelEntry channel)
335 unsigned char *id_string, *key, *cipher, *hmac, hash[SILC_HASH_MAXLEN];
338 SilcChannelKeyPayload payload;
340 payload = silc_channel_key_payload_parse(silc_buffer_data(key_payload),
341 silc_buffer_len(key_payload));
345 id_string = silc_channel_key_get_id(payload, &tmp_len);
347 silc_channel_key_payload_free(payload);
351 if (!silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) {
352 silc_channel_key_payload_free(payload);
358 channel = silc_client_get_channel_by_id(client, conn, &id);
360 silc_channel_key_payload_free(payload);
364 silc_client_ref_channel(client, conn, channel);
367 /* Save the old key for a short period of time so that we can decrypt
368 channel message even after the rekey if some client would be sending
369 messages with the old key after the rekey. */
370 if (!channel->internal.old_channel_keys)
371 channel->internal.old_channel_keys = silc_dlist_init();
372 if (!channel->internal.old_hmacs)
373 channel->internal.old_hmacs = silc_dlist_init();
374 if (channel->internal.old_channel_keys && channel->internal.old_hmacs) {
375 silc_dlist_add(channel->internal.old_channel_keys,
376 channel->internal.channel_key);
377 silc_dlist_add(channel->internal.old_hmacs, channel->internal.hmac);
378 silc_schedule_task_add_timeout(client->schedule,
379 silc_client_save_channel_key_rekey,
383 /* Get channel cipher */
384 cipher = silc_channel_key_get_cipher(payload, NULL);
385 if (!silc_cipher_alloc(cipher, &channel->internal.channel_key)) {
386 client->internal->ops->say(
388 SILC_CLIENT_MESSAGE_AUDIT,
389 "Cannot talk to channel: unsupported cipher %s",
391 silc_client_unref_channel(client, conn, channel);
392 silc_channel_key_payload_free(payload);
396 /* Set the cipher key */
397 key = silc_channel_key_get_key(payload, &tmp_len);
398 silc_cipher_set_key(channel->internal.channel_key, key, tmp_len * 8);
400 /* Get channel HMAC */
401 hmac = (channel->internal.hmac ?
402 (char *)silc_hmac_get_name(channel->internal.hmac) :
404 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
405 client->internal->ops->say(
407 SILC_CLIENT_MESSAGE_AUDIT,
408 "Cannot talk to channel: unsupported HMAC %s",
410 silc_client_unref_channel(client, conn, channel);
411 silc_channel_key_payload_free(payload);
416 silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key,
418 silc_hmac_set_key(channel->internal.hmac, hash,
419 silc_hash_len(silc_hmac_get_hash(channel->internal.hmac)));
420 memset(hash, 0, sizeof(hash));
422 silc_client_unref_channel(client, conn, channel);
427 /* Received channel key packet. The key will replace old channel key. */
429 SILC_FSM_STATE(silc_client_channel_key)
431 SilcClientConnection conn = fsm_context;
432 SilcClient client = conn->client;
433 SilcPacket packet = state_context;
435 SILC_LOG_DEBUG(("Received channel key"));
438 silc_client_save_channel_key(client, conn, &packet->buffer, NULL);
439 silc_packet_free(packet);
441 return SILC_FSM_FINISH;
444 /**************************** Channel Private Key ***************************/
446 /* Add new channel private key */
448 SilcBool silc_client_add_channel_private_key(SilcClient client,
449 SilcClientConnection conn,
450 SilcChannelEntry channel,
456 SilcChannelPrivateKey *ret_key)
458 SilcChannelPrivateKey entry;
459 unsigned char hash[SILC_HASH_MAXLEN];
460 SilcSKEKeyMaterial keymat;
462 if (!client || !conn || !channel)
466 cipher = SILC_DEFAULT_CIPHER;
468 hmac = SILC_DEFAULT_HMAC;
470 if (!silc_cipher_is_supported(cipher))
472 if (!silc_hmac_is_supported(hmac))
475 if (!channel->internal.private_keys) {
476 channel->internal.private_keys = silc_dlist_init();
477 if (!channel->internal.private_keys)
481 /* Produce the key material */
482 keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
488 entry = silc_calloc(1, sizeof(*entry));
490 silc_ske_free_key_material(keymat);
493 entry->name = name ? strdup(name) : NULL;
495 /* Allocate the cipher and set the key*/
496 if (!silc_cipher_alloc(cipher, &entry->cipher)) {
498 silc_free(entry->name);
499 silc_ske_free_key_material(keymat);
502 silc_cipher_set_key(entry->cipher, keymat->send_enc_key,
503 keymat->enc_key_len);
505 /* Generate HMAC key from the channel key data and set it */
506 if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
508 silc_free(entry->name);
509 silc_cipher_free(entry->cipher);
510 silc_ske_free_key_material(keymat);
513 silc_hash_make(silc_hmac_get_hash(entry->hmac), keymat->send_enc_key,
514 keymat->enc_key_len / 8, hash);
515 silc_hmac_set_key(entry->hmac, hash,
516 silc_hash_len(silc_hmac_get_hash(entry->hmac)));
517 memset(hash, 0, sizeof(hash));
519 /* Add to the private keys list */
520 silc_dlist_add(channel->internal.private_keys, entry);
522 if (!channel->internal.curr_key)
523 channel->internal.curr_key = entry;
525 /* Free the key material */
526 silc_ske_free_key_material(keymat);
534 /* Removes all private keys from the `channel'. The old channel key is used
535 after calling this to protect the channel messages. Returns FALSE on
536 on error, TRUE otherwise. */
538 SilcBool silc_client_del_channel_private_keys(SilcClient client,
539 SilcClientConnection conn,
540 SilcChannelEntry channel)
542 SilcChannelPrivateKey entry;
544 if (!client || !conn || !channel)
547 if (!channel->internal.private_keys)
550 silc_dlist_start(channel->internal.private_keys);
551 while ((entry = silc_dlist_get(channel->internal.private_keys))) {
552 silc_dlist_del(channel->internal.private_keys, entry);
553 silc_free(entry->name);
554 silc_cipher_free(entry->cipher);
555 silc_hmac_free(entry->hmac);
559 channel->internal.curr_key = NULL;
561 silc_dlist_uninit(channel->internal.private_keys);
562 channel->internal.private_keys = NULL;
567 /* Removes and frees private key `key' from the channel `channel'. The `key'
568 is retrieved by calling the function silc_client_list_channel_private_keys.
569 The key is not used after this. If the key was last private key then the
570 old channel key is used hereafter to protect the channel messages. This
571 returns FALSE on error, TRUE otherwise. */
573 SilcBool silc_client_del_channel_private_key(SilcClient client,
574 SilcClientConnection conn,
575 SilcChannelEntry channel,
576 SilcChannelPrivateKey key)
578 SilcChannelPrivateKey entry;
580 if (!client || !conn || !channel)
583 if (!channel->internal.private_keys)
586 silc_dlist_start(channel->internal.private_keys);
587 while ((entry = silc_dlist_get(channel->internal.private_keys))) {
591 if (channel->internal.curr_key == entry)
592 channel->internal.curr_key = NULL;
594 silc_dlist_del(channel->internal.private_keys, entry);
595 silc_free(entry->name);
596 silc_cipher_free(entry->cipher);
597 silc_hmac_free(entry->hmac);
600 if (silc_dlist_count(channel->internal.private_keys) == 0) {
601 silc_dlist_uninit(channel->internal.private_keys);
602 channel->internal.private_keys = NULL;
611 /* Returns array (pointers) of private keys associated to the `channel'.
612 The caller must free the array by calling the function
613 silc_client_free_channel_private_keys. The pointers in the array may be
614 used to delete the specific key by giving the pointer as argument to the
615 function silc_client_del_channel_private_key. */
617 SilcDList silc_client_list_channel_private_keys(SilcClient client,
618 SilcClientConnection conn,
619 SilcChannelEntry channel)
621 SilcChannelPrivateKey entry;
624 if (!client || !conn || !channel)
627 if (!channel->internal.private_keys)
630 list = silc_dlist_init();
634 silc_dlist_start(channel->internal.private_keys);
635 while ((entry = silc_dlist_get(channel->internal.private_keys)))
636 silc_dlist_add(list, entry);
641 /* Sets the `key' to be used as current channel private key on the
642 `channel'. Packet sent after calling this function will be secured
645 void silc_client_current_channel_private_key(SilcClient client,
646 SilcClientConnection conn,
647 SilcChannelEntry channel,
648 SilcChannelPrivateKey key)
652 channel->internal.curr_key = key;
655 /***************************** Utility routines *****************************/
657 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
658 channel indicated by the `channel'. NULL if client is not joined on
661 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
662 SilcClientEntry client_entry)
666 if (silc_hash_table_find(channel->user_list, client_entry, NULL,
673 /* Adds client to channel */
675 SilcBool silc_client_add_to_channel(SilcChannelEntry channel,
676 SilcClientEntry client_entry,
681 if (silc_client_on_channel(channel, client_entry))
684 chu = silc_calloc(1, sizeof(*chu));
688 chu->client = client_entry;
689 chu->channel = channel;
691 silc_hash_table_add(channel->user_list, client_entry, chu);
692 silc_hash_table_add(client_entry->channels, channel, chu);
697 /* Removes client from a channel */
699 SilcBool silc_client_remove_from_channel(SilcChannelEntry channel,
700 SilcClientEntry client_entry)
704 chu = silc_client_on_channel(channel, client_entry);
708 silc_hash_table_del(chu->client->channels, chu->channel);
709 silc_hash_table_del(chu->channel->user_list, chu->client);
715 /* Removes a client entry from all channels it has joined. */
717 void silc_client_remove_from_channels(SilcClient client,
718 SilcClientConnection conn,
719 SilcClientEntry client_entry)
721 SilcHashTableList htl;
724 silc_hash_table_list(client_entry->channels, &htl);
725 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
726 silc_hash_table_del(chu->client->channels, chu->channel);
727 silc_hash_table_del(chu->channel->user_list, chu->client);
731 silc_hash_table_list_reset(&htl);