updates.
[silc.git] / lib / silcclient / client_prvmsg.c
1 /*
2
3   client_prvmsg.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2001 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; either version 2 of the License, or
12   (at your option) any later version.
13   
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.
18
19 */
20 /* $Id$ */
21 /* This file includes the private message sending and receiving routines
22    and private message key handling routines. */
23
24 #include "clientlibincludes.h"
25 #include "client_internal.h"
26
27 /* Sends private message to remote client. If private message key has
28    not been set with this client then the message will be encrypted using
29    normal session keys. Private messages are special packets in SILC
30    network hence we need this own function for them. This is similiar
31    to silc_client_packet_send_to_channel except that we send private
32    message. The `data' is the private message. If the `force_send' is
33    TRUE the packet is sent immediately. */
34
35 void silc_client_send_private_message(SilcClient client,
36                                       SilcClientConnection conn,
37                                       SilcClientEntry client_entry,
38                                       SilcMessageFlags flags,
39                                       unsigned char *data, 
40                                       uint32 data_len, 
41                                       int force_send)
42 {
43   SilcSocketConnection sock = conn->sock;
44   SilcBuffer buffer;
45   SilcPacketContext packetdata;
46   SilcCipher cipher;
47   SilcHmac hmac;
48
49   SILC_LOG_DEBUG(("Sending private message"));
50
51   /* Encode private message payload */
52   buffer = silc_private_message_payload_encode(flags,
53                                                data_len, data,
54                                                client_entry->send_key);
55
56   /* If we don't have private message specific key then private messages
57      are just as any normal packet thus call normal packet sending.  If
58      the key exist then the encryption process is a bit different and
59      will be done in the rest of this function. */
60   if (!client_entry->send_key) {
61     silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
62                             client_entry->id, SILC_ID_CLIENT, NULL, NULL,
63                             buffer->data, buffer->len, force_send);
64     goto out;
65   }
66
67   /* We have private message specific key */
68
69   /* Get data used in the encryption */
70   cipher = client_entry->send_key;
71   hmac = conn->hmac_send;
72
73   /* Set the packet context pointers. */
74   packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
75   packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
76   packetdata.src_id = conn->local_id_data;
77   packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
78   packetdata.src_id_type = SILC_ID_CLIENT;
79   packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
80   packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
81   packetdata.dst_id_type = SILC_ID_CLIENT;
82   packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN + 
83     packetdata.src_id_len + packetdata.dst_id_len;
84   packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
85                                           packetdata.src_id_len +
86                                           packetdata.dst_id_len));
87
88   /* Prepare outgoing data buffer for packet sending */
89   silc_packet_send_prepare(sock, 
90                            SILC_PACKET_HEADER_LEN +
91                            packetdata.src_id_len + 
92                            packetdata.dst_id_len,
93                            packetdata.padlen,
94                            buffer->len);
95   
96   packetdata.buffer = sock->outbuf;
97
98   /* Put the actual encrypted message payload data into the buffer. */
99   silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
100
101   /* Create the outgoing packet */
102   silc_packet_assemble(&packetdata);
103
104   /* Encrypt the header and padding of the packet. */
105   cipher = conn->send_key;
106   silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
107                       packetdata.src_id_len + packetdata.dst_id_len +
108                       packetdata.padlen);
109
110   SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
111                    sock->outbuf->data, sock->outbuf->len);
112
113   /* Now actually send the packet */
114   silc_client_packet_send_real(client, sock, force_send, FALSE);
115   silc_free(packetdata.dst_id);
116
117  out:
118   silc_buffer_free(buffer);
119 }     
120
121 static void silc_client_private_message_cb(SilcClient client,
122                                            SilcClientConnection conn,
123                                            SilcClientEntry *clients,
124                                            uint32 clients_count,
125                                            void *context)
126 {
127   SilcPacketContext *packet = (SilcPacketContext *)context;
128
129   silc_client_private_message(client, conn->sock, packet);
130   silc_packet_context_free(packet);
131 }
132
133 /* Private message received. This processes the private message and
134    finally displays it on the screen. */
135
136 void silc_client_private_message(SilcClient client, 
137                                  SilcSocketConnection sock, 
138                                  SilcPacketContext *packet)
139 {
140   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
141   SilcPrivateMessagePayload payload = NULL;
142   SilcIDCacheEntry id_cache;
143   SilcClientID *remote_id = NULL;
144   SilcClientEntry remote_client;
145   SilcMessageFlags flags;
146
147   if (packet->src_id_type != SILC_ID_CLIENT)
148     goto out;
149
150   remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
151                              SILC_ID_CLIENT);
152   if (!remote_id)
153     goto out;
154
155   /* Check whether we know this client already */
156   if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)remote_id, 
157                                        NULL, NULL, 
158                                        silc_hash_client_id_compare, NULL,
159                                        &id_cache)) {
160     /* Resolve the client info */
161     silc_client_get_client_by_id_resolve(client, conn, remote_id,
162                                          silc_client_private_message_cb,
163                                          silc_packet_context_dup(packet));
164     return;
165   }
166
167   remote_client = (SilcClientEntry)id_cache->context;
168
169   /* Parse the payload and decrypt it also if private message key is set */
170   payload = silc_private_message_payload_parse(packet->buffer,
171                                                remote_client->send_key);
172   if (!payload) {
173     silc_free(remote_id);
174     return;
175   }
176
177   flags = silc_private_message_get_flags(payload);
178
179   /* Pass the private message to application */
180   client->ops->private_message(client, conn, remote_client, flags,
181                                silc_private_message_get_message(payload, 
182                                                                 NULL));
183
184   /* See if we are away (gone). If we are away we will reply to the
185      sender with the set away message. */
186   if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
187     /* If it's me, ignore */
188     if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
189       goto out;
190
191     /* Send the away message */
192     silc_client_send_private_message(client, conn, remote_client,
193                                      SILC_MESSAGE_FLAG_AUTOREPLY |
194                                      SILC_MESSAGE_FLAG_NOREPLY,
195                                      conn->away->away,
196                                      strlen(conn->away->away), TRUE);
197   }
198
199  out:
200   if (payload)
201     silc_private_message_payload_free(payload);
202   if (remote_id)
203     silc_free(remote_id);
204 }
205
206 /* Function that actually employes the received private message key */
207
208 static void silc_client_private_message_key_cb(SilcClient client,
209                                                SilcClientConnection conn,
210                                                SilcClientEntry *clients,
211                                                uint32 clients_count,
212                                                void *context)
213 {
214   SilcPacketContext *packet = (SilcPacketContext *)context;
215   unsigned char *key;
216   uint16 key_len;
217   unsigned char *cipher;
218   int ret;
219
220   if (!clients)
221     goto out;
222
223   /* Parse the private message key payload */
224   ret = silc_buffer_unformat(packet->buffer,
225                              SILC_STR_UI16_NSTRING(&key, &key_len),
226                              SILC_STR_UI16_STRING(&cipher),
227                              SILC_STR_END);
228   if (!ret)
229     goto out;
230
231   if (key_len > packet->buffer->len)
232     goto out;
233
234   /* Now take the key in use */
235   if (!silc_client_add_private_message_key(client, conn, clients[0],
236                                            cipher, key, key_len, FALSE))
237     goto out;
238
239   /* Print some info for application */
240   client->ops->say(client, conn, 
241                    "Received private message key from %s%s%s %s%s%s", 
242                    clients[0]->nickname,
243                    clients[0]->server ? "@" : "",
244                    clients[0]->server ? clients[0]->server : "",
245                    clients[0]->username ? "(" : "",
246                    clients[0]->username ? clients[0]->username : "",
247                    clients[0]->username ? ")" : "");
248
249  out:
250   silc_packet_context_free(packet);
251 }
252
253 /* Processes incoming Private Message Key payload. The libary always
254    accepts the key and takes it into use. */
255
256 void silc_client_private_message_key(SilcClient client,
257                                      SilcSocketConnection sock,
258                                      SilcPacketContext *packet)
259 {
260   SilcClientID *remote_id;
261
262   if (packet->src_id_type != SILC_ID_CLIENT)
263     return;
264
265   remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
266                              SILC_ID_CLIENT);
267   if (!remote_id)
268     return;
269
270   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
271                                        silc_client_private_message_key_cb,
272                                        silc_packet_context_dup(packet));
273   silc_free(remote_id);
274 }
275
276 /* Adds private message key to the client library. The key will be used to
277    encrypt all private message between the client and the remote client
278    indicated by the `client_entry'. If the `key' is NULL and the boolean
279    value `generate_key' is TRUE the library will generate random key.
280    The `key' maybe for example pre-shared-key, passphrase or similar.
281    The `cipher' MAY be provided but SHOULD be NULL to assure that the
282    requirements of the SILC protocol are met. The API, however, allows
283    to allocate any cipher.
284
285    It is not necessary to set key for normal private message usage. If the
286    key is not set then the private messages are encrypted using normal
287    session keys. Setting the private key, however, increases the security. 
288
289    Returns FALSE if the key is already set for the `client_entry', TRUE
290    otherwise. */
291
292 int silc_client_add_private_message_key(SilcClient client,
293                                         SilcClientConnection conn,
294                                         SilcClientEntry client_entry,
295                                         char *cipher,
296                                         unsigned char *key,
297                                         uint32 key_len,
298                                         int generate_key)
299 {
300   unsigned char private_key[32];
301   uint32 len;
302   int i;
303   SilcSKEKeyMaterial *keymat;
304
305   assert(client_entry);
306
307   /* Return FALSE if key already set */
308   if (client_entry->send_key && client_entry->receive_key)
309     return FALSE;
310
311   if (!cipher)
312     cipher = "aes-256-cbc";
313
314   /* Check the requested cipher */
315   if (!silc_cipher_is_supported(cipher))
316     return FALSE;
317
318   /* Generate key if not provided */
319   if (generate_key == TRUE) {
320     len = 32;
321     for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
322     key = private_key;
323     key_len = len;
324     client_entry->generated = TRUE;
325   }
326
327   /* Save the key */
328   client_entry->key = silc_calloc(key_len, sizeof(*client_entry->key));
329   memcpy(client_entry->key, key, key_len);
330   client_entry->key_len = key_len;
331
332   /* Produce the key material as the protocol defines */
333   keymat = silc_calloc(1, sizeof(*keymat));
334   if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16, 
335                                          client->md5hash, keymat) 
336       != SILC_SKE_STATUS_OK)
337     return FALSE;
338
339   /* Allocate the ciphers */
340   silc_cipher_alloc(cipher, &client_entry->send_key);
341   silc_cipher_alloc(cipher, &client_entry->receive_key);
342
343   /* Set the keys */
344   silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
345                       keymat->enc_key_len);
346   silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
347   silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
348                       keymat->enc_key_len);
349   silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
350
351   /* Free the key material */
352   silc_ske_free_key_material(keymat);
353
354   return TRUE;
355 }
356
357 /* Same as above but takes the key material from the SKE key material
358    structure. This structure is received if the application uses the
359    silc_client_send_key_agreement to negotiate the key material. The
360    `cipher' SHOULD be provided as it is negotiated also in the SKE
361    protocol. */
362
363 int silc_client_add_private_message_key_ske(SilcClient client,
364                                             SilcClientConnection conn,
365                                             SilcClientEntry client_entry,
366                                             char *cipher,
367                                             SilcSKEKeyMaterial *key)
368 {
369   assert(client_entry);
370
371   /* Return FALSE if key already set */
372   if (client_entry->send_key && client_entry->receive_key)
373     return FALSE;
374
375   if (!cipher)
376     cipher = "aes-256-cbc";
377
378   /* Check the requested cipher */
379   if (!silc_cipher_is_supported(cipher))
380     return FALSE;
381
382   /* Allocate the ciphers */
383   silc_cipher_alloc(cipher, &client_entry->send_key);
384   silc_cipher_alloc(cipher, &client_entry->receive_key);
385
386   /* Set the keys */
387   silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
388                       key->enc_key_len);
389   silc_cipher_set_iv(client_entry->send_key, key->send_iv);
390   silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
391                       key->enc_key_len);
392   silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
393
394   return TRUE;
395 }
396
397 /* Sends private message key payload to the remote client indicated by
398    the `client_entry'. If the `force_send' is TRUE the packet is sent
399    immediately. Returns FALSE if error occurs, TRUE otherwise. The
400    application should call this function after setting the key to the
401    client.
402
403    Note that the key sent using this function is sent to the remote client
404    through the SILC network. The packet is protected using normal session
405    keys. */
406
407 int silc_client_send_private_message_key(SilcClient client,
408                                          SilcClientConnection conn,
409                                          SilcClientEntry client_entry,
410                                          int force_send)
411 {
412   SilcSocketConnection sock = conn->sock;
413   SilcBuffer buffer;
414   int cipher_len;
415
416   if (!client_entry->send_key || !client_entry->key)
417     return FALSE;
418
419   SILC_LOG_DEBUG(("Sending private message key"));
420
421   cipher_len = strlen(client_entry->send_key->cipher->name);
422
423   /* Create private message key payload */
424   buffer = silc_buffer_alloc(2 + client_entry->key_len);
425   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
426   silc_buffer_format(buffer,
427                      SILC_STR_UI_SHORT(client_entry->key_len),
428                      SILC_STR_UI_XNSTRING(client_entry->key, 
429                                           client_entry->key_len),
430                      SILC_STR_UI_SHORT(cipher_len),
431                      SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
432                                           cipher_len),
433                      SILC_STR_END);
434
435   /* Send the packet */
436   silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
437                           client_entry->id, SILC_ID_CLIENT, NULL, NULL,
438                           buffer->data, buffer->len, force_send);
439   silc_free(buffer);
440
441   return TRUE;
442 }
443
444 /* Removes the private message from the library. The key won't be used
445    after this to protect the private messages with the remote `client_entry'
446    client. Returns FALSE on error, TRUE otherwise. */
447
448 int silc_client_del_private_message_key(SilcClient client,
449                                         SilcClientConnection conn,
450                                         SilcClientEntry client_entry)
451 {
452   assert(client_entry);
453
454   if (!client_entry->send_key && !client_entry->receive_key)
455     return FALSE;
456
457   silc_cipher_free(client_entry->send_key);
458   silc_cipher_free(client_entry->receive_key);
459
460   if (client_entry->key) {
461     memset(client_entry->key, 0, client_entry->key_len);
462     silc_free(client_entry->key);
463   }
464
465   client_entry->send_key = NULL;
466   client_entry->receive_key = NULL;
467   client_entry->key = NULL;
468
469   return TRUE;
470 }
471
472 /* Returns array of set private message keys associated to the connection
473    `conn'. Returns allocated SilcPrivateMessageKeys array and the array
474    count to the `key_count' argument. The array must be freed by the caller
475    by calling the silc_client_free_private_message_keys function. Note: 
476    the keys returned in the array is in raw format. It might not be desired
477    to show the keys as is. The application might choose not to show the keys
478    at all or to show the fingerprints of the keys. */
479
480 SilcPrivateMessageKeys
481 silc_client_list_private_message_keys(SilcClient client,
482                                       SilcClientConnection conn,
483                                       uint32 *key_count)
484 {
485   SilcPrivateMessageKeys keys;
486   uint32 count = 0;
487   SilcIDCacheEntry id_cache;
488   SilcIDCacheList list;
489   SilcClientEntry entry;
490
491   if (!silc_idcache_get_all(conn->client_cache, &list))
492     return NULL;
493
494   if (!silc_idcache_list_count(list)) {
495     silc_idcache_list_free(list);
496     return NULL;
497   }
498
499   keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
500
501   silc_idcache_list_first(list, &id_cache);
502   while (id_cache) {
503     entry = (SilcClientEntry)id_cache->context;
504
505     if (entry->send_key) {
506       keys[count].client_entry = entry;
507       keys[count].cipher = entry->send_key->cipher->name;
508       keys[count].key = entry->generated == FALSE ? entry->key : NULL;
509       keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
510       count++;
511     }
512
513     if (!silc_idcache_list_next(list, &id_cache))
514       break;
515   }
516
517   if (key_count)
518     *key_count = count;
519
520   return keys;
521 }
522
523 /* Frees the SilcPrivateMessageKeys array returned by the function
524    silc_client_list_private_message_keys. */
525
526 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
527                                            uint32 key_count)
528 {
529   silc_free(keys);
530 }
531
532 /* Sets away `message'.  The away message may be set when the client's
533    mode is changed to SILC_UMODE_GONE and the client whishes to reply
534    to anyone who sends private message.  The `message' will be sent
535    automatically back to the the client who send private message.  If
536    away message is already set this replaces the old message with the
537    new one.  If `message' is NULL the old away message is removed. 
538    The sender may freely free the memory of the `message'. */
539
540 void silc_client_set_away_message(SilcClient client,
541                                   SilcClientConnection conn,
542                                   char *message)
543 {
544   if (!message && conn->away) {
545     silc_free(conn->away->away);
546     silc_free(conn->away);
547     conn->away = NULL;
548   }
549
550   if (message) {
551     if (!conn->away)
552       conn->away = silc_calloc(1, sizeof(*conn->away));
553     if (conn->away->away)
554       silc_free(conn->away->away);
555     conn->away->away = strdup(message);
556   }
557 }