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