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