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