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