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