Added SILC Server library.
[silc.git] / lib / silcclient / client_channel.c
1 /*
2
3   client_channel.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2004 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* $Id$ */
20 /* This file includes channel message sending and receiving routines,
21    channel key receiving and setting, and channel private key handling
22    routines. */
23
24 #include "silc.h"
25 #include "silcclient.h"
26 #include "client_internal.h"
27
28 /* Sends packet to the `channel'. Packet to channel is always encrypted
29    differently from "normal" packets. SILC header of the packet is
30    encrypted with the next receiver's key and the rest of the packet is
31    encrypted with the channel specific key. Padding and HMAC is computed
32    with the next receiver's key. The `data' is the channel message. If
33    the `force_send' is TRUE then the packet is sent immediately. */
34
35 SilcBool silc_client_send_channel_message(SilcClient client,
36                                       SilcClientConnection conn,
37                                       SilcChannelEntry channel,
38                                       SilcChannelPrivateKey key,
39                                       SilcMessageFlags flags,
40                                       unsigned char *data,
41                                       SilcUInt32 data_len,
42                                       SilcBool force_send)
43 {
44   SilcSocketConnection sock;
45   SilcBuffer payload;
46   SilcPacketContext packetdata;
47   const SilcBufferStruct packet;
48   SilcCipher cipher;
49   SilcHmac hmac;
50   unsigned char *id_string;
51   int block_len;
52   SilcChannelUser chu;
53   SilcBool ret = FALSE;
54
55   assert(client && conn && channel);
56   sock = conn->sock;
57   SILC_LOG_DEBUG(("Sending packet to channel"));
58
59   chu = silc_client_on_channel(channel, conn->local_entry);
60   if (!chu) {
61     SILC_LOG_ERROR(("Cannot send message to channel we are not joined"));
62     return FALSE;
63   }
64
65   /* Check if it is allowed to send messages to this channel by us. */
66   if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chu->mode)
67     return FALSE;
68   if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
69       chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
70       !(chu->mode & SILC_CHANNEL_UMODE_CHANFO))
71     return FALSE;
72   if (chu->mode & SILC_CHANNEL_UMODE_QUIET)
73     return FALSE;
74
75   /* Take the key to be used */
76   if (channel->private_keys) {
77     if (key) {
78       /* Use key application specified */
79       cipher = key->cipher;
80       hmac = key->hmac;
81     } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
82                channel->curr_key) {
83       /* Use current private key */
84       cipher = channel->curr_key->cipher;
85       hmac = channel->curr_key->hmac;
86     } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
87                !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);
92       cipher = key->cipher;
93       hmac = key->hmac;
94
95       /* Use this key as current private key */
96       channel->curr_key = key;
97     } else {
98       /* Use normal channel key generated by the server */
99       cipher = channel->channel_key;
100       hmac = channel->hmac;
101     }
102   } else {
103     /* Use normal channel key generated by the server */
104     cipher = channel->channel_key;
105     hmac = channel->hmac;
106   }
107
108   if (!cipher || !hmac) {
109     SILC_LOG_ERROR(("No cipher and HMAC for channel"));
110     return FALSE;
111   }
112
113   block_len = silc_cipher_get_block_len(cipher);
114
115   /* Encode the message payload. This also encrypts the message payload. */
116   payload = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
117                                         cipher, hmac, client->rng, NULL,
118                                         client->private_key, client->sha1hash);
119   if (!payload) {
120     SILC_LOG_ERROR(("Error encoding channel message"));
121     return FALSE;
122   }
123
124   /* Get data used in packet header encryption, keys and stuff. */
125   cipher = conn->internal->send_key;
126   hmac = conn->internal->hmac_send;
127   id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
128
129   /* Set the packet context pointers. The destination ID is always
130      the Channel ID of the channel. Server and router will handle the
131      distribution of the packet. */
132   data = payload->data;
133   data_len = payload->len;
134   packetdata.flags = 0;
135   packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
136   packetdata.src_id = conn->local_id_data;
137   packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
138   packetdata.src_id_type = SILC_ID_CLIENT;
139   packetdata.dst_id = id_string;
140   packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
141   packetdata.dst_id_type = SILC_ID_CHANNEL;
142   data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
143                                  packetdata.src_id_len +
144                                  packetdata.dst_id_len);
145   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
146     packetdata.src_id_len + packetdata.dst_id_len;
147   SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
148                       packetdata.src_id_len +
149                       packetdata.dst_id_len), block_len, packetdata.padlen);
150
151   /* Create the outgoing packet */
152   if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
153                             data, data_len, (const SilcBuffer)&packet)) {
154     SILC_LOG_ERROR(("Error assembling packet"));
155     goto out;
156   }
157
158   /* Encrypt the header and padding of the packet. This is encrypted
159      with normal session key shared with our server. */
160   silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
161                       (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
162                       packetdata.src_id_len + packetdata.dst_id_len +
163                       packetdata.padlen);
164
165   SILC_LOG_HEXDUMP(("Packet to channel, len %d", packet.len),
166                     packet.data, packet.len);
167
168   /* Now actually send the packet */
169   silc_client_packet_send_real(client, sock, force_send);
170
171   /* Check for mandatory rekey */
172   if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD)
173     silc_schedule_task_add(client->schedule, sock->sock,
174                            silc_client_rekey_callback, sock, 0, 1,
175                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
176
177   ret = TRUE;
178
179  out:
180   silc_buffer_free(payload);
181   silc_free(id_string);
182
183   return ret;
184 }
185
186 typedef struct {
187   SilcMessagePayload payload;
188   SilcChannelID *channel_id;
189   SilcChannelPrivateKey key;
190 } *SilcChannelClientResolve;
191
192 static void silc_client_channel_message_cb(SilcClient client,
193                                            SilcClientConnection conn,
194                                            SilcClientEntry *clients,
195                                            SilcUInt32 clients_count,
196                                            void *context)
197 {
198   SilcChannelClientResolve res = (SilcChannelClientResolve)context;
199
200   if (clients_count == 1) {
201     SilcChannelEntry channel;
202     unsigned char *message;
203     SilcUInt32 message_len;
204
205     channel = silc_client_get_channel_by_id(client, conn, res->channel_id);
206     if (!channel)
207       goto out;
208
209     /* If this client is not on channel, add it there since it clearly
210        is there. */
211     if (!silc_client_on_channel(channel, clients[0])) {
212       SilcChannelUser chu = silc_calloc(1, sizeof(*chu));
213       chu->client = clients[0];
214       chu->channel = channel;
215       silc_hash_table_add(channel->user_list, clients[0], chu);
216       silc_hash_table_add(clients[0]->channels, channel, chu);
217     }
218
219     message = silc_message_get_data(res->payload, &message_len);
220
221     /* Pass the message to application */
222     client->internal->ops->channel_message(
223                             client, conn, clients[0], channel, res->payload,
224                             res->key, silc_message_get_flags(res->payload),
225                             message, message_len);
226   }
227
228  out:
229   silc_message_payload_free(res->payload);
230   silc_free(res->channel_id);
231   silc_free(res);
232 }
233
234 /* Process received message to a channel (or from a channel, really). This
235    decrypts the channel message with channel specific key and parses the
236    message payload. Finally it displays the message on the screen. */
237
238 void silc_client_channel_message(SilcClient client,
239                                  SilcSocketConnection sock,
240                                  SilcPacketContext *packet)
241 {
242   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
243   SilcBuffer buffer = packet->buffer;
244   SilcMessagePayload payload = NULL;
245   SilcChannelID *id = NULL;
246   SilcChannelEntry channel;
247   SilcClientEntry client_entry;
248   SilcClientID *client_id = NULL;
249   unsigned char *message;
250   SilcUInt32 message_len;
251   SilcChannelPrivateKey key = NULL;
252
253   SILC_LOG_DEBUG(("Received channel message"));
254
255   /* Sanity checks */
256   if (packet->dst_id_type != SILC_ID_CHANNEL)
257     goto out;
258
259   client_id = silc_id_str2id(packet->src_id, packet->src_id_len,
260                              SILC_ID_CLIENT);
261   if (!client_id)
262     goto out;
263   id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL);
264   if (!id)
265     goto out;
266
267   /* Find the channel entry from channels on this connection */
268   channel = silc_client_get_channel_by_id(client, conn, id);
269   if (!channel)
270     goto out;
271
272   /* If there is no channel private key then just decrypt the message
273      with the channel key. If private keys are set then just go through
274      all private keys and check what decrypts correctly. */
275   if (!channel->private_keys) {
276     /* Parse the channel message payload. This also decrypts the payload */
277     payload = silc_message_payload_parse(buffer->data, buffer->len, FALSE,
278                                          FALSE, channel->channel_key,
279                                          channel->hmac);
280
281     /* If decryption failed and we have just performed channel key rekey
282        we will use the old key in decryption. If that fails too then we
283        cannot do more and will drop the packet. */
284     if (!payload) {
285       SilcCipher key;
286       SilcHmac hmac;
287       int i;
288
289       if (!channel->old_channel_keys ||
290           !silc_dlist_count(channel->old_channel_keys))
291         goto out;
292
293       SILC_LOG_DEBUG(("Attempting to decrypt with old channel key(s)"));
294
295       silc_dlist_end(channel->old_channel_keys);
296       silc_dlist_end(channel->old_hmacs);
297       for (i = 0; i < silc_dlist_count(channel->old_channel_keys); i++) {
298         key = silc_dlist_get(channel->old_channel_keys);
299         hmac = silc_dlist_get(channel->old_hmacs);
300         if (!key || !hmac)
301           break;
302
303         payload = silc_message_payload_parse(buffer->data, buffer->len,
304                                              FALSE, FALSE, key, hmac);
305         if (payload)
306           break;
307       }
308       if (!payload)
309         goto out;
310     }
311   } else {
312     /* If the private key mode, however is not set on the channel then
313        try the actual channel key first before trying private keys. */
314     if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
315       payload = silc_message_payload_parse(buffer->data, buffer->len, FALSE,
316                                            FALSE, channel->channel_key,
317                                            channel->hmac);
318
319     if (!payload) {
320       silc_dlist_start(channel->private_keys);
321       while ((key = silc_dlist_get(channel->private_keys))
322              != SILC_LIST_END) {
323         /* Parse the message payload. This also decrypts the payload */
324         payload = silc_message_payload_parse(buffer->data, buffer->len,
325                                              FALSE, FALSE,
326                                              key->cipher, key->hmac);
327         if (payload)
328           break;
329       }
330       if (key == SILC_LIST_END)
331         goto out;
332     }
333   }
334
335   /* Find client entry */
336   client_entry = silc_client_get_client_by_id(client, conn, client_id);
337   if (!client_entry || !client_entry->nickname ||
338       !silc_client_on_channel(channel, client_entry)) {
339     /* Resolve the client info */
340     SilcChannelClientResolve res = silc_calloc(1, sizeof(*res));
341     res->payload = payload;
342     res->channel_id = id;
343     res->key = key;
344     silc_client_get_client_by_id_resolve(client, conn, client_id, NULL,
345                                          silc_client_channel_message_cb,
346                                          res);
347     payload = NULL;
348     id = NULL;
349     goto out;
350   }
351
352   message = silc_message_get_data(payload, &message_len);
353
354   /* Pass the message to application */
355   client->internal->ops->channel_message(
356                              client, conn, client_entry, channel, payload,
357                              key, silc_message_get_flags(payload),
358                              message, message_len);
359
360  out:
361   silc_free(id);
362   silc_free(client_id);
363   if (payload)
364     silc_message_payload_free(payload);
365 }
366
367 /* Timeout callback that is called after a short period of time after the
368    new channel key has been created.  This removes the first channel key
369    in the list. */
370
371 SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
372 {
373   SilcChannelEntry channel = (SilcChannelEntry)context;
374   SilcCipher key;
375   SilcHmac hmac;
376
377   if (channel->old_channel_keys) {
378     silc_dlist_start(channel->old_channel_keys);
379     key = silc_dlist_get(channel->old_channel_keys);
380     if (key) {
381       silc_dlist_del(channel->old_channel_keys, key);
382       silc_cipher_free(key);
383     }
384   }
385
386   if (channel->old_hmacs) {
387     silc_dlist_start(channel->old_hmacs);
388     hmac = silc_dlist_get(channel->old_hmacs);
389     if (hmac) {
390       silc_dlist_del(channel->old_hmacs, hmac);
391       silc_hmac_free(hmac);
392     }
393   }
394 }
395
396 /* Saves channel key from encoded `key_payload'. This is used when we
397    receive Channel Key Payload and when we are processing JOIN command
398    reply. */
399
400 void silc_client_save_channel_key(SilcClient client,
401                                   SilcClientConnection conn,
402                                   SilcBuffer key_payload,
403                                   SilcChannelEntry channel)
404 {
405   unsigned char *id_string, *key, *cipher, *hmac, hash[SILC_HASH_MAXLEN];
406   SilcUInt32 tmp_len;
407   SilcChannelID *id;
408   SilcChannelKeyPayload payload;
409
410   payload = silc_channel_key_payload_parse(key_payload->data,
411                                            key_payload->len);
412   if (!payload)
413     return;
414
415   id_string = silc_channel_key_get_id(payload, &tmp_len);
416   if (!id_string) {
417     silc_channel_key_payload_free(payload);
418     return;
419   }
420
421   id = silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL);
422   if (!id) {
423     silc_channel_key_payload_free(payload);
424     return;
425   }
426
427   /* Find channel. */
428   if (!channel) {
429     channel = silc_client_get_channel_by_id(client, conn, id);
430     if (!channel)
431       goto out;
432   }
433
434   hmac = (channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) :
435           SILC_DEFAULT_HMAC);
436
437   /* Save the old key for a short period of time so that we can decrypt
438      channel message even after the rekey if some client would be sending
439      messages with the old key after the rekey. */
440   if (!channel->old_channel_keys)
441     channel->old_channel_keys = silc_dlist_init();
442   if (!channel->old_hmacs)
443     channel->old_hmacs = silc_dlist_init();
444   silc_dlist_add(channel->old_channel_keys, channel->channel_key);
445   silc_dlist_add(channel->old_hmacs, channel->hmac);
446   silc_schedule_task_add(client->schedule, 0,
447                          silc_client_save_channel_key_rekey, channel,
448                          10, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
449
450   /* Free the old channel key data */
451   silc_free(channel->key);
452
453   /* Save the key */
454   key = silc_channel_key_get_key(payload, &tmp_len);
455   cipher = silc_channel_key_get_cipher(payload, NULL);
456   channel->key_len = tmp_len * 8;
457   channel->key = silc_memdup(key, tmp_len);
458
459   if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
460     client->internal->ops->say(
461                            conn->client, conn,
462                            SILC_CLIENT_MESSAGE_AUDIT,
463                            "Cannot talk to channel: unsupported cipher %s",
464                            cipher);
465     goto out;
466   }
467
468   /* Set the cipher key */
469   silc_cipher_set_key(channel->channel_key, key, channel->key_len);
470
471   /* Generate HMAC key from the channel key data and set it */
472   silc_hmac_alloc(hmac, NULL, &channel->hmac);
473   silc_hash_make(silc_hmac_get_hash(channel->hmac), key, tmp_len, hash);
474   silc_hmac_set_key(channel->hmac, hash,
475                     silc_hash_len(silc_hmac_get_hash(channel->hmac)));
476   memset(hash, 0, sizeof(hash));
477
478  out:
479   silc_free(id);
480   silc_channel_key_payload_free(payload);
481 }
482
483 /* Processes received key for channel. The received key will be used
484    to protect the traffic on the channel for now on. Client must receive
485    the key to the channel before talking on the channel is possible.
486    This is the key that server has generated, this is not the channel
487    private key, it is entirely local setting. */
488
489 void silc_client_receive_channel_key(SilcClient client,
490                                      SilcSocketConnection sock,
491                                      SilcBuffer packet)
492 {
493   SILC_LOG_DEBUG(("Received key for channel"));
494
495   /* Save the key */
496   silc_client_save_channel_key(client, sock->user_data, packet, NULL);
497 }
498
499 /* Adds private key for channel. When channel has private key then the
500    messages are encrypted using that key. All clients on the channel must
501    also know the key in order to decrypt the messages. However, it is
502    possible to have several private keys per one channel. In this case
503    only some of the clients on the channel may know the one key and only
504    some the other key.
505
506    If `cipher' and/or `hmac' is NULL then default values will be used
507    (aes-256-cbc for cipher and hmac-sha1-96 for hmac).
508
509    The private key for channel is optional. If it is not set then the
510    channel messages are encrypted using the channel key generated by the
511    server. However, setting the private key (or keys) for the channel
512    significantly adds security. If more than one key is set the library
513    will automatically try all keys at the message decryption phase. Note:
514    setting many keys slows down the decryption phase as all keys has to
515    be tried in order to find the correct decryption key. However, setting
516    a few keys does not have big impact to the decryption performace.
517
518    NOTE: that this is entirely local setting. The key set using this function
519    is not sent to the network at any phase.
520
521    NOTE: If the key material was originated by the SKE protocol (using
522    silc_client_send_key_agreement) then the `key' MUST be the
523    key->send_enc_key as this is dictated by the SILC protocol. However,
524    currently it is not expected that the SKE key material would be used
525    as channel private key. However, this API allows it. */
526
527 SilcBool silc_client_add_channel_private_key(SilcClient client,
528                                          SilcClientConnection conn,
529                                          SilcChannelEntry channel,
530                                          const char *name,
531                                          char *cipher,
532                                          char *hmac,
533                                          unsigned char *key,
534                                          SilcUInt32 key_len,
535                                          SilcChannelPrivateKey *ret_key)
536 {
537   SilcChannelPrivateKey entry;
538   unsigned char hash[SILC_HASH_MAXLEN];
539   SilcSKEKeyMaterial *keymat;
540
541   assert(client && channel);
542
543   if (!cipher)
544     cipher = SILC_DEFAULT_CIPHER;
545   if (!hmac)
546     hmac = SILC_DEFAULT_HMAC;
547
548   if (!silc_cipher_is_supported(cipher))
549     return FALSE;
550
551   if (!silc_hmac_is_supported(hmac))
552     return FALSE;
553
554   /* Produce the key material */
555   keymat = silc_calloc(1, sizeof(*keymat));
556   if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
557                                          client->sha1hash, keymat)
558       != SILC_SKE_STATUS_OK)
559     return FALSE;
560
561   if (!channel->private_keys)
562     channel->private_keys = silc_dlist_init();
563
564   /* Save the key */
565   entry = silc_calloc(1, sizeof(*entry));
566   entry->name = name ? strdup(name) : NULL;
567   entry->key = silc_memdup(keymat->send_enc_key, keymat->enc_key_len / 8);
568   entry->key_len = keymat->enc_key_len / 8;
569
570   /* Allocate the cipher and set the key*/
571   silc_cipher_alloc(cipher, &entry->cipher);
572   silc_cipher_set_key(entry->cipher, entry->key, keymat->enc_key_len);
573
574   /* Generate HMAC key from the channel key data and set it */
575   silc_hmac_alloc(hmac, NULL, &entry->hmac);
576   silc_hash_make(silc_hmac_get_hash(entry->hmac), entry->key,
577                  entry->key_len, hash);
578   silc_hmac_set_key(entry->hmac, hash,
579                     silc_hash_len(silc_hmac_get_hash(entry->hmac)));
580   memset(hash, 0, sizeof(hash));
581
582   /* Add to the private keys list */
583   silc_dlist_add(channel->private_keys, entry);
584
585   if (!channel->curr_key)
586     channel->curr_key = entry;
587
588   /* Free the key material */
589   silc_ske_free_key_material(keymat);
590
591   if (ret_key)
592     *ret_key = entry;
593
594   return TRUE;
595 }
596
597 /* Removes all private keys from the `channel'. The old channel key is used
598    after calling this to protect the channel messages. Returns FALSE on
599    on error, TRUE otherwise. */
600
601 SilcBool silc_client_del_channel_private_keys(SilcClient client,
602                                          SilcClientConnection conn,
603                                          SilcChannelEntry channel)
604 {
605   SilcChannelPrivateKey entry;
606
607   assert(client && channel);
608
609   if (!channel->private_keys)
610     return FALSE;
611
612   silc_dlist_start(channel->private_keys);
613   while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
614     silc_dlist_del(channel->private_keys, entry);
615     memset(entry->key, 0, entry->key_len);
616     silc_free(entry->key);
617     silc_free(entry->name);
618     silc_cipher_free(entry->cipher);
619     silc_hmac_free(entry->hmac);
620     silc_free(entry);
621   }
622
623   channel->curr_key = NULL;
624
625   silc_dlist_uninit(channel->private_keys);
626   channel->private_keys = NULL;
627
628   return TRUE;
629 }
630
631 /* Removes and frees private key `key' from the channel `channel'. The `key'
632    is retrieved by calling the function silc_client_list_channel_private_keys.
633    The key is not used after this. If the key was last private key then the
634    old channel key is used hereafter to protect the channel messages. This
635    returns FALSE on error, TRUE otherwise. */
636
637 SilcBool silc_client_del_channel_private_key(SilcClient client,
638                                         SilcClientConnection conn,
639                                         SilcChannelEntry channel,
640                                         SilcChannelPrivateKey key)
641 {
642   SilcChannelPrivateKey entry;
643
644   assert(client && channel);
645
646   if (!channel->private_keys)
647     return FALSE;
648
649   silc_dlist_start(channel->private_keys);
650   while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
651     if (entry == key) {
652       if (channel->curr_key == entry)
653         channel->curr_key = NULL;
654
655       silc_dlist_del(channel->private_keys, entry);
656       memset(entry->key, 0, entry->key_len);
657       silc_free(entry->key);
658       silc_free(entry->name);
659       silc_cipher_free(entry->cipher);
660       silc_hmac_free(entry->hmac);
661       silc_free(entry);
662
663       if (silc_dlist_count(channel->private_keys) == 0) {
664         silc_dlist_uninit(channel->private_keys);
665         channel->private_keys = NULL;
666       }
667
668       return TRUE;
669     }
670   }
671
672   return FALSE;
673 }
674
675 /* Returns array (pointers) of private keys associated to the `channel'.
676    The caller must free the array by calling the function
677    silc_client_free_channel_private_keys. The pointers in the array may be
678    used to delete the specific key by giving the pointer as argument to the
679    function silc_client_del_channel_private_key. */
680
681 SilcChannelPrivateKey *
682 silc_client_list_channel_private_keys(SilcClient client,
683                                       SilcClientConnection conn,
684                                       SilcChannelEntry channel,
685                                       SilcUInt32 *key_count)
686 {
687   SilcChannelPrivateKey *keys = NULL, entry;
688   SilcUInt32 count = 0;
689
690   assert(client && channel);
691
692   if (!channel->private_keys)
693     return NULL;
694
695   silc_dlist_start(channel->private_keys);
696   while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
697     keys = silc_realloc(keys, sizeof(*keys) * (count + 1));
698     keys[count] = entry;
699     count++;
700   }
701
702   if (key_count)
703     *key_count = count;
704
705   return keys;
706 }
707
708 /* Frees the SilcChannelPrivateKey array. */
709
710 void silc_client_free_channel_private_keys(SilcChannelPrivateKey *keys,
711                                            SilcUInt32 key_count)
712 {
713   silc_free(keys);
714 }
715
716 /* Sets the `key' to be used as current channel private key on the
717    `channel'.  Packet sent after calling this function will be secured
718    with `key'. */
719
720 void silc_client_current_channel_private_key(SilcClient client,
721                                              SilcClientConnection conn,
722                                              SilcChannelEntry channel,
723                                              SilcChannelPrivateKey key)
724 {
725   assert(client && channel);
726   channel->curr_key = key;
727 }
728
729 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
730    channel indicated by the `channel'. NULL if client is not joined on
731    the channel. */
732
733 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
734                                        SilcClientEntry client_entry)
735 {
736   SilcChannelUser chu;
737
738   if (silc_hash_table_find(channel->user_list, client_entry, NULL,
739                            (void *)&chu))
740     return chu;
741
742   return NULL;
743 }