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