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