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