5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 /* This file includes channel message sending and receiving routines,
22 channel key receiving and setting, and channel private key handling
25 #include "silcincludes.h"
26 #include "silcclient.h"
27 #include "client_internal.h"
29 /* Sends packet to the `channel'. Packet to channel is always encrypted
30 differently from "normal" packets. SILC header of the packet is
31 encrypted with the next receiver's key and the rest of the packet is
32 encrypted with the channel specific key. Padding and HMAC is computed
33 with the next receiver's key. The `data' is the channel message. If
34 the `force_send' is TRUE then the packet is sent immediately. */
36 void silc_client_send_channel_message(SilcClient client,
37 SilcClientConnection conn,
38 SilcChannelEntry channel,
39 SilcChannelPrivateKey key,
40 SilcMessageFlags flags,
46 SilcSocketConnection sock;
48 SilcPacketContext packetdata;
49 const SilcBufferStruct packet;
52 unsigned char *id_string;
57 assert(client && conn && channel);
59 SILC_LOG_DEBUG(("Sending packet to channel"));
61 chu = silc_client_on_channel(channel, conn->local_entry);
63 SILC_LOG_ERROR(("Cannot send message to channel we are not joined"));
67 /* Check if it is allowed to send messages to this channel by us. */
68 if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chu->mode)
70 if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
71 chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
72 !(chu->mode & SILC_CHANNEL_UMODE_CHANFO))
74 if (chu->mode & SILC_CHANNEL_UMODE_QUIET)
77 /* Take the key to be used */
78 if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
80 /* Use key application specified */
83 } else if (channel->curr_key) {
84 /* Use current private key */
85 cipher = channel->curr_key->cipher;
86 hmac = channel->curr_key->hmac;
87 } else if (!channel->curr_key && channel->private_keys) {
88 /* Use just some private key since we don't know what to use
89 and private keys are set. */
90 silc_dlist_start(channel->private_keys);
91 key = silc_dlist_get(channel->private_keys);
95 /* Use this key as current private key */
96 channel->curr_key = key;
98 /* Use normal channel key generated by the server */
99 cipher = channel->channel_key;
100 hmac = channel->hmac;
103 /* Use normal channel key generated by the server */
104 cipher = channel->channel_key;
105 hmac = channel->hmac;
108 if (!cipher || !hmac)
111 block_len = silc_cipher_get_block_len(cipher);
114 iv_len = silc_cipher_get_block_len(cipher);
115 if (channel->iv[0] == '\0')
116 for (i = 0; i < iv_len; i++) channel->iv[i] =
117 silc_rng_get_byte(client->rng);
119 silc_hash_make(client->md5hash, channel->iv, iv_len, channel->iv);
121 /* Encode the channel payload. This also encrypts the message payload. */
122 payload = silc_channel_message_payload_encode(flags, data_len, data, iv_len,
123 channel->iv, cipher, hmac,
126 /* Get data used in packet header encryption, keys and stuff. */
127 cipher = conn->internal->send_key;
128 hmac = conn->internal->hmac_send;
129 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
131 /* Set the packet context pointers. The destination ID is always
132 the Channel ID of the channel. Server and router will handle the
133 distribution of the packet. */
134 data = payload->data;
135 data_len = payload->len;
136 packetdata.flags = 0;
137 packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
138 packetdata.src_id = conn->local_id_data;
139 packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
140 packetdata.src_id_type = SILC_ID_CLIENT;
141 packetdata.dst_id = id_string;
142 packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
143 packetdata.dst_id_type = SILC_ID_CHANNEL;
144 data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
145 packetdata.src_id_len +
146 packetdata.dst_id_len);
147 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
148 packetdata.src_id_len + packetdata.dst_id_len;
149 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
150 packetdata.src_id_len +
151 packetdata.dst_id_len), block_len);
153 /* Create the outgoing packet */
154 if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
155 data, data_len, (const SilcBuffer)&packet)) {
156 SILC_LOG_ERROR(("Error assembling packet"));
160 /* Encrypt the header and padding of the packet. This is encrypted
161 with normal session key shared with our server. */
162 silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
163 (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
164 packetdata.src_id_len + packetdata.dst_id_len +
167 SILC_LOG_HEXDUMP(("Packet to channel, len %d", packet.len),
168 packet.data, packet.len);
170 /* Now actually send the packet */
171 silc_client_packet_send_real(client, sock, force_send);
174 silc_buffer_free(payload);
175 silc_free(id_string);
179 SilcChannelMessagePayload payload;
180 SilcChannelID *channel_id;
181 } *SilcChannelClientResolve;
183 static void silc_client_channel_message_cb(SilcClient client,
184 SilcClientConnection conn,
185 SilcClientEntry *clients,
186 SilcUInt32 clients_count,
189 SilcChannelClientResolve res = (SilcChannelClientResolve)context;
191 if (clients_count == 1) {
192 SilcChannelEntry channel;
193 unsigned char *message;
194 SilcUInt32 message_len;
196 channel = silc_client_get_channel_by_id(client, conn, res->channel_id);
200 /* If this client is not on channel, add it there since it clearly
202 if (!silc_client_on_channel(channel, clients[0])) {
203 SilcChannelUser chu = silc_calloc(1, sizeof(*chu));
204 chu->client = clients[0];
205 chu->channel = channel;
206 silc_hash_table_add(channel->user_list, clients[0], chu);
207 silc_hash_table_add(clients[0]->channels, channel, chu);
210 message = silc_channel_message_get_data(res->payload, &message_len);
212 /* Pass the message to application */
213 client->internal->ops->channel_message(
214 client, conn, clients[0], channel,
215 silc_channel_message_get_flags(res->payload),
216 message, message_len);
220 silc_channel_message_payload_free(res->payload);
221 silc_free(res->channel_id);
225 /* Process received message to a channel (or from a channel, really). This
226 decrypts the channel message with channel specific key and parses the
227 channel payload. Finally it displays the message on the screen. */
229 void silc_client_channel_message(SilcClient client,
230 SilcSocketConnection sock,
231 SilcPacketContext *packet)
233 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
234 SilcBuffer buffer = packet->buffer;
235 SilcChannelMessagePayload payload = NULL;
236 SilcChannelID *id = NULL;
237 SilcChannelEntry channel;
238 SilcClientEntry client_entry;
239 SilcClientID *client_id = NULL;
240 unsigned char *message;
241 SilcUInt32 message_len;
243 SILC_LOG_DEBUG(("Start"));
246 if (packet->dst_id_type != SILC_ID_CHANNEL)
249 client_id = silc_id_str2id(packet->src_id, packet->src_id_len,
253 id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL);
257 /* Find the channel entry from channels on this connection */
258 channel = silc_client_get_channel_by_id(client, conn, id);
262 /* If there is no channel private key then just decrypt the message
263 with the channel key. If private keys are set then just go through
264 all private keys and check what decrypts correctly. */
265 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
266 /* Parse the channel message payload. This also decrypts the payload */
267 payload = silc_channel_message_payload_parse(buffer->data, buffer->len,
268 channel->channel_key,
271 /* If decryption failed and we have just performed channel key rekey
272 we will use the old key in decryption. If that fails too then we
273 cannot do more and will drop the packet. */
275 if (!channel->old_channel_key) {
279 payload = silc_channel_message_payload_parse(buffer->data, buffer->len,
280 channel->old_channel_key,
286 } else if (channel->private_keys) {
287 SilcChannelPrivateKey entry;
289 silc_dlist_start(channel->private_keys);
290 while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
291 /* Parse the channel message payload. This also decrypts the payload */
292 payload = silc_channel_message_payload_parse(buffer->data, buffer->len,
298 if (entry == SILC_LIST_END)
304 /* Find client entry */
305 client_entry = silc_client_get_client_by_id(client, conn, client_id);
306 if (!client_entry || !client_entry->nickname ||
307 !silc_client_on_channel(channel, client_entry)) {
308 /* Resolve the client info */
309 SilcChannelClientResolve res = silc_calloc(1, sizeof(*res));
310 res->payload = payload;
311 res->channel_id = id;
312 silc_client_get_client_by_id_resolve(client, conn, client_id, NULL,
313 silc_client_channel_message_cb,
320 message = silc_channel_message_get_data(payload, &message_len);
322 /* Pass the message to application */
323 client->internal->ops->channel_message(
324 client, conn, client_entry, channel,
325 silc_channel_message_get_flags(payload),
326 message, message_len);
330 silc_free(client_id);
332 silc_channel_message_payload_free(payload);
335 /* Timeout callback that is called after a short period of time after the
336 new channel key has been created. This removes the old channel key all
339 SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
341 SilcChannelEntry channel = (SilcChannelEntry)context;
343 if (channel->old_channel_key)
344 silc_cipher_free(channel->old_channel_key);
345 if (channel->old_hmac)
346 silc_hmac_free(channel->old_hmac);
347 channel->old_channel_key = NULL;
348 channel->old_hmac = NULL;
349 channel->rekey_task = NULL;
352 /* Saves channel key from encoded `key_payload'. This is used when we
353 receive Channel Key Payload and when we are processing JOIN command
356 void silc_client_save_channel_key(SilcClient client,
357 SilcClientConnection conn,
358 SilcBuffer key_payload,
359 SilcChannelEntry channel)
361 unsigned char *id_string, *key, *cipher, *hmac, hash[32];
364 SilcChannelKeyPayload payload;
366 payload = silc_channel_key_payload_parse(key_payload->data,
371 id_string = silc_channel_key_get_id(payload, &tmp_len);
373 silc_channel_key_payload_free(payload);
377 id = silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL);
379 silc_channel_key_payload_free(payload);
385 channel = silc_client_get_channel_by_id(client, conn, id);
390 hmac = (channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) :
393 /* Save the old key for a short period of time so that we can decrypt
394 channel message even after the rekey if some client would be sending
395 messages with the old key after the rekey. */
396 if (channel->old_channel_key)
397 silc_cipher_free(channel->old_channel_key);
398 if (channel->old_hmac)
399 silc_hmac_free(channel->old_hmac);
400 if (channel->rekey_task)
401 silc_schedule_task_del(client->schedule, channel->rekey_task);
402 channel->old_channel_key = channel->channel_key;
403 channel->old_hmac = channel->hmac;
404 channel->rekey_task =
405 silc_schedule_task_add(client->schedule, 0,
406 silc_client_save_channel_key_rekey, channel,
407 10, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
409 /* Free the old channel key data */
410 silc_free(channel->key);
413 key = silc_channel_key_get_key(payload, &tmp_len);
414 cipher = silc_channel_key_get_cipher(payload, NULL);
415 channel->key_len = tmp_len * 8;
416 channel->key = silc_memdup(key, tmp_len);
418 if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
419 client->internal->ops->say(
421 SILC_CLIENT_MESSAGE_AUDIT,
422 "Cannot talk to channel: unsupported cipher %s",
427 /* Set the cipher key */
428 silc_cipher_set_key(channel->channel_key, key, channel->key_len);
430 /* Generate HMAC key from the channel key data and set it */
431 silc_hmac_alloc(hmac, NULL, &channel->hmac);
432 silc_hash_make(silc_hmac_get_hash(channel->hmac), key, tmp_len, hash);
433 silc_hmac_set_key(channel->hmac, hash,
434 silc_hash_len(silc_hmac_get_hash(channel->hmac)));
435 memset(hash, 0, sizeof(hash));
439 silc_channel_key_payload_free(payload);
442 /* Processes received key for channel. The received key will be used
443 to protect the traffic on the channel for now on. Client must receive
444 the key to the channel before talking on the channel is possible.
445 This is the key that server has generated, this is not the channel
446 private key, it is entirely local setting. */
448 void silc_client_receive_channel_key(SilcClient client,
449 SilcSocketConnection sock,
452 SILC_LOG_DEBUG(("Received key for channel"));
455 silc_client_save_channel_key(client, sock->user_data, packet, NULL);
458 /* Adds private key for channel. This may be set only if the channel's mode
459 mask includes the SILC_CHANNEL_MODE_PRIVKEY. This returns FALSE if the
460 mode is not set. When channel has private key then the messages are
461 encrypted using that key. All clients on the channel must also know the
462 key in order to decrypt the messages. However, it is possible to have
463 several private keys per one channel. In this case only some of the
464 clients on the channel may know the one key and only some the other key.
466 If `cipher' and/or `hmac' is NULL then default values will be used
467 (aes-256-cbc for cipher and hmac-sha1-96 for hmac).
469 The private key for channel is optional. If it is not set then the
470 channel messages are encrypted using the channel key generated by the
471 server. However, setting the private key (or keys) for the channel
472 significantly adds security. If more than one key is set the library
473 will automatically try all keys at the message decryption phase. Note:
474 setting many keys slows down the decryption phase as all keys has to
475 be tried in order to find the correct decryption key. However, setting
476 a few keys does not have big impact to the decryption performace.
478 NOTE: that this is entirely local setting. The key set using this function
479 is not sent to the network at any phase.
481 NOTE: If the key material was originated by the SKE protocol (using
482 silc_client_send_key_agreement) then the `key' MUST be the
483 key->send_enc_key as this is dictated by the SILC protocol. However,
484 currently it is not expected that the SKE key material would be used
485 as channel private key. However, this API allows it. */
487 int silc_client_add_channel_private_key(SilcClient client,
488 SilcClientConnection conn,
489 SilcChannelEntry channel,
496 SilcChannelPrivateKey entry;
497 unsigned char hash[32];
498 SilcSKEKeyMaterial *keymat;
500 assert(client && channel);
502 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
506 cipher = SILC_DEFAULT_CIPHER;
508 hmac = SILC_DEFAULT_HMAC;
510 if (!silc_cipher_is_supported(cipher))
513 if (!silc_hmac_is_supported(hmac))
516 /* Produce the key material */
517 keymat = silc_calloc(1, sizeof(*keymat));
518 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
519 client->md5hash, keymat)
520 != SILC_SKE_STATUS_OK)
523 /* Remove the current key, if it exists. */
524 if (channel->channel_key) {
525 silc_cipher_free(channel->channel_key);
526 memset(channel->key, 0, channel->key_len / 8);
527 silc_free(channel->key);
528 channel->channel_key = NULL;
530 channel->key_len = 0;
533 silc_hmac_free(channel->hmac);
534 channel->hmac = NULL;
537 if (!channel->private_keys)
538 channel->private_keys = silc_dlist_init();
541 entry = silc_calloc(1, sizeof(*entry));
542 entry->name = name ? strdup(name) : NULL;
543 entry->key = silc_memdup(keymat->send_enc_key, keymat->enc_key_len / 8);
544 entry->key_len = keymat->enc_key_len / 8;
546 /* Allocate the cipher and set the key*/
547 silc_cipher_alloc(cipher, &entry->cipher);
548 silc_cipher_set_key(entry->cipher, entry->key, keymat->enc_key_len);
550 /* Generate HMAC key from the channel key data and set it */
551 silc_hmac_alloc(hmac, NULL, &entry->hmac);
552 silc_hash_make(silc_hmac_get_hash(entry->hmac), entry->key,
553 entry->key_len, hash);
554 silc_hmac_set_key(entry->hmac, hash,
555 silc_hash_len(silc_hmac_get_hash(entry->hmac)));
556 memset(hash, 0, sizeof(hash));
558 /* Add to the private keys list */
559 silc_dlist_add(channel->private_keys, entry);
561 if (!channel->curr_key)
562 channel->curr_key = entry;
564 /* Free the key material */
565 silc_ske_free_key_material(keymat);
570 /* Removes all private keys from the `channel'. The old channel key is used
571 after calling this to protect the channel messages. Returns FALSE on
572 on error, TRUE otherwise. */
574 int silc_client_del_channel_private_keys(SilcClient client,
575 SilcClientConnection conn,
576 SilcChannelEntry channel)
578 SilcChannelPrivateKey entry;
580 assert(client && channel);
582 if (!channel->private_keys)
585 silc_dlist_start(channel->private_keys);
586 while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
587 silc_dlist_del(channel->private_keys, entry);
588 memset(entry->key, 0, entry->key_len);
589 silc_free(entry->key);
590 silc_free(entry->name);
591 silc_cipher_free(entry->cipher);
592 silc_hmac_free(entry->hmac);
596 channel->curr_key = NULL;
598 silc_dlist_uninit(channel->private_keys);
599 channel->private_keys = NULL;
604 /* Removes and frees private key `key' from the channel `channel'. The `key'
605 is retrieved by calling the function silc_client_list_channel_private_keys.
606 The key is not used after this. If the key was last private key then the
607 old channel key is used hereafter to protect the channel messages. This
608 returns FALSE on error, TRUE otherwise. */
610 int silc_client_del_channel_private_key(SilcClient client,
611 SilcClientConnection conn,
612 SilcChannelEntry channel,
613 SilcChannelPrivateKey key)
615 SilcChannelPrivateKey entry;
617 assert(client && channel);
619 if (!channel->private_keys)
622 silc_dlist_start(channel->private_keys);
623 while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
625 if (channel->curr_key == entry)
626 channel->curr_key = NULL;
628 silc_dlist_del(channel->private_keys, entry);
629 memset(entry->key, 0, entry->key_len);
630 silc_free(entry->key);
631 silc_free(entry->name);
632 silc_cipher_free(entry->cipher);
633 silc_hmac_free(entry->hmac);
636 if (silc_dlist_count(channel->private_keys) == 0) {
637 silc_dlist_uninit(channel->private_keys);
638 channel->private_keys = NULL;
648 /* Returns array (pointers) of private keys associated to the `channel'.
649 The caller must free the array by calling the function
650 silc_client_free_channel_private_keys. The pointers in the array may be
651 used to delete the specific key by giving the pointer as argument to the
652 function silc_client_del_channel_private_key. */
654 SilcChannelPrivateKey *
655 silc_client_list_channel_private_keys(SilcClient client,
656 SilcClientConnection conn,
657 SilcChannelEntry channel,
658 SilcUInt32 *key_count)
660 SilcChannelPrivateKey *keys = NULL, entry;
661 SilcUInt32 count = 0;
663 assert(client && channel);
665 if (!channel->private_keys)
668 silc_dlist_start(channel->private_keys);
669 while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
670 keys = silc_realloc(keys, sizeof(*keys) * (count + 1));
681 /* Frees the SilcChannelPrivateKey array. */
683 void silc_client_free_channel_private_keys(SilcChannelPrivateKey *keys,
684 SilcUInt32 key_count)
689 /* Sets the `key' to be used as current channel private key on the
690 `channel'. Packet sent after calling this function will be secured
693 void silc_client_current_channel_private_key(SilcClient client,
694 SilcClientConnection conn,
695 SilcChannelEntry channel,
696 SilcChannelPrivateKey key)
698 assert(client && channel);
699 channel->curr_key = key;
702 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
703 channel indicated by the `channel'. NULL if client is not joined on
706 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
707 SilcClientEntry client_entry)
711 if (silc_hash_table_find(channel->user_list, client_entry, NULL,