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   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,
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                                        silc_client_private_message_key_cb,
291                                        silc_packet_context_dup(packet));
292   silc_free(remote_id);
293 }
294
295 /* Adds private message key to the client library. The key will be used to
296    encrypt all private message between the client and the remote client
297    indicated by the `client_entry'. If the `key' is NULL and the boolean
298    value `generate_key' is TRUE the library will generate random key.
299    The `key' maybe for example pre-shared-key, passphrase or similar.
300    The `cipher' MAY be provided but SHOULD be NULL to assure that the
301    requirements of the SILC protocol are met. The API, however, allows
302    to allocate any cipher.
303
304    If `responder' is TRUE then the sending and receiving keys will be
305    set according the client being the receiver of the private key.  If
306    FALSE the client is being the sender (or negotiator) of the private
307    key.
308
309    It is not necessary to set key for normal private message usage. If the
310    key is not set then the private messages are encrypted using normal
311    session keys. Setting the private key, however, increases the security. 
312
313    Returns FALSE if the key is already set for the `client_entry', TRUE
314    otherwise. */
315
316 int silc_client_add_private_message_key(SilcClient client,
317                                         SilcClientConnection conn,
318                                         SilcClientEntry client_entry,
319                                         char *cipher,
320                                         unsigned char *key,
321                                         SilcUInt32 key_len,
322                                         bool generate_key,
323                                         bool responder)
324 {
325   unsigned char private_key[32];
326   SilcUInt32 len;
327   int i;
328   SilcSKEKeyMaterial *keymat;
329
330   assert(client_entry);
331
332   /* Return FALSE if key already set */
333   if (client_entry->send_key && client_entry->receive_key)
334     return FALSE;
335
336   if (!cipher)
337     cipher = SILC_DEFAULT_CIPHER;
338
339   /* Check the requested cipher */
340   if (!silc_cipher_is_supported(cipher))
341     return FALSE;
342
343   /* Generate key if not provided */
344   if (generate_key == TRUE) {
345     len = 32;
346     for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
347     key = private_key;
348     key_len = len;
349     client_entry->generated = TRUE;
350   }
351
352   /* Save the key */
353   client_entry->key = silc_memdup(key, key_len);
354   client_entry->key_len = key_len;
355
356   /* Produce the key material as the protocol defines */
357   keymat = silc_calloc(1, sizeof(*keymat));
358   if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16, 
359                                          client->internal->md5hash, keymat) 
360       != SILC_SKE_STATUS_OK)
361     return FALSE;
362
363   /* Allocate the ciphers */
364   silc_cipher_alloc(cipher, &client_entry->send_key);
365   silc_cipher_alloc(cipher, &client_entry->receive_key);
366
367   /* Set the keys */
368   if (responder == TRUE) {
369     silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
370                         keymat->enc_key_len);
371     silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
372     silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
373                         keymat->enc_key_len);
374     silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
375   } else {
376     silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
377                         keymat->enc_key_len);
378     silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
379     silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
380                         keymat->enc_key_len);
381     silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
382   }
383
384   /* Free the key material */
385   silc_ske_free_key_material(keymat);
386
387   return TRUE;
388 }
389
390 /* Same as above but takes the key material from the SKE key material
391    structure. This structure is received if the application uses the
392    silc_client_send_key_agreement to negotiate the key material. The
393    `cipher' SHOULD be provided as it is negotiated also in the SKE
394    protocol. */
395
396 int silc_client_add_private_message_key_ske(SilcClient client,
397                                             SilcClientConnection conn,
398                                             SilcClientEntry client_entry,
399                                             char *cipher,
400                                             SilcSKEKeyMaterial *key,
401                                             bool responder)
402 {
403   assert(client_entry);
404
405   /* Return FALSE if key already set */
406   if (client_entry->send_key && client_entry->receive_key)
407     return FALSE;
408
409   if (!cipher)
410     cipher = SILC_DEFAULT_CIPHER;
411
412   /* Check the requested cipher */
413   if (!silc_cipher_is_supported(cipher))
414     return FALSE;
415
416   /* Allocate the ciphers */
417   silc_cipher_alloc(cipher, &client_entry->send_key);
418   silc_cipher_alloc(cipher, &client_entry->receive_key);
419
420   /* Set the keys */
421   if (responder == TRUE) {
422     silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
423                         key->enc_key_len);
424     silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
425     silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
426                         key->enc_key_len);
427     silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
428   } else {
429     silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
430                         key->enc_key_len);
431     silc_cipher_set_iv(client_entry->send_key, key->send_iv);
432     silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
433                         key->enc_key_len);
434     silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
435   }
436
437   return TRUE;
438 }
439
440 /* Sends private message key payload to the remote client indicated by
441    the `client_entry'. If the `force_send' is TRUE the packet is sent
442    immediately. Returns FALSE if error occurs, TRUE otherwise. The
443    application should call this function after setting the key to the
444    client.
445
446    Note that the key sent using this function is sent to the remote client
447    through the SILC network. The packet is protected using normal session
448    keys. */
449
450 int silc_client_send_private_message_key(SilcClient client,
451                                          SilcClientConnection conn,
452                                          SilcClientEntry client_entry,
453                                          int force_send)
454 {
455   SilcSocketConnection sock = conn->sock;
456   SilcBuffer buffer;
457   int cipher_len;
458
459   if (!client_entry->send_key || !client_entry->key)
460     return FALSE;
461
462   SILC_LOG_DEBUG(("Sending private message key"));
463
464   cipher_len = strlen(client_entry->send_key->cipher->name);
465
466   /* Create private message key payload */
467   buffer = silc_buffer_alloc(2 + client_entry->key_len);
468   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
469   silc_buffer_format(buffer,
470                      SILC_STR_UI_SHORT(client_entry->key_len),
471                      SILC_STR_UI_XNSTRING(client_entry->key, 
472                                           client_entry->key_len),
473                      SILC_STR_UI_SHORT(cipher_len),
474                      SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
475                                           cipher_len),
476                      SILC_STR_END);
477
478   /* Send the packet */
479   silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
480                           client_entry->id, SILC_ID_CLIENT, NULL, NULL,
481                           buffer->data, buffer->len, force_send);
482   silc_free(buffer);
483
484   return TRUE;
485 }
486
487 /* Removes the private message from the library. The key won't be used
488    after this to protect the private messages with the remote `client_entry'
489    client. Returns FALSE on error, TRUE otherwise. */
490
491 int silc_client_del_private_message_key(SilcClient client,
492                                         SilcClientConnection conn,
493                                         SilcClientEntry client_entry)
494 {
495   assert(client_entry);
496
497   if (!client_entry->send_key && !client_entry->receive_key)
498     return FALSE;
499
500   silc_cipher_free(client_entry->send_key);
501   silc_cipher_free(client_entry->receive_key);
502
503   if (client_entry->key) {
504     memset(client_entry->key, 0, client_entry->key_len);
505     silc_free(client_entry->key);
506   }
507
508   client_entry->send_key = NULL;
509   client_entry->receive_key = NULL;
510   client_entry->key = NULL;
511
512   return TRUE;
513 }
514
515 /* Returns array of set private message keys associated to the connection
516    `conn'. Returns allocated SilcPrivateMessageKeys array and the array
517    count to the `key_count' argument. The array must be freed by the caller
518    by calling the silc_client_free_private_message_keys function. Note: 
519    the keys returned in the array is in raw format. It might not be desired
520    to show the keys as is. The application might choose not to show the keys
521    at all or to show the fingerprints of the keys. */
522
523 SilcPrivateMessageKeys
524 silc_client_list_private_message_keys(SilcClient client,
525                                       SilcClientConnection conn,
526                                       SilcUInt32 *key_count)
527 {
528   SilcPrivateMessageKeys keys;
529   SilcUInt32 count = 0;
530   SilcIDCacheEntry id_cache;
531   SilcIDCacheList list;
532   SilcClientEntry entry;
533
534   if (!silc_idcache_get_all(conn->client_cache, &list))
535     return NULL;
536
537   if (!silc_idcache_list_count(list)) {
538     silc_idcache_list_free(list);
539     return NULL;
540   }
541
542   keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
543
544   silc_idcache_list_first(list, &id_cache);
545   while (id_cache) {
546     entry = (SilcClientEntry)id_cache->context;
547
548     if (entry->send_key) {
549       keys[count].client_entry = entry;
550       keys[count].cipher = entry->send_key->cipher->name;
551       keys[count].key = entry->generated == FALSE ? entry->key : NULL;
552       keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
553       count++;
554     }
555
556     if (!silc_idcache_list_next(list, &id_cache))
557       break;
558   }
559
560   if (key_count)
561     *key_count = count;
562
563   return keys;
564 }
565
566 /* Frees the SilcPrivateMessageKeys array returned by the function
567    silc_client_list_private_message_keys. */
568
569 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
570                                            SilcUInt32 key_count)
571 {
572   silc_free(keys);
573 }
574
575 /* Sets away `message'.  The away message may be set when the client's
576    mode is changed to SILC_UMODE_GONE and the client whishes to reply
577    to anyone who sends private message.  The `message' will be sent
578    automatically back to the the client who send private message.  If
579    away message is already set this replaces the old message with the
580    new one.  If `message' is NULL the old away message is removed. 
581    The sender may freely free the memory of the `message'. */
582
583 void silc_client_set_away_message(SilcClient client,
584                                   SilcClientConnection conn,
585                                   char *message)
586 {
587   if (!message && conn->away) {
588     silc_free(conn->away->away);
589     silc_free(conn->away);
590     conn->away = NULL;
591   }
592
593   if (message) {
594     if (!conn->away)
595       conn->away = silc_calloc(1, sizeof(*conn->away));
596     if (conn->away->away)
597       silc_free(conn->away->away);
598     conn->away->away = strdup(message);
599   }
600 }