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