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                                       SilcMessageFlags flags,
39                                       unsigned char *data, 
40                                       uint32 data_len, 
41                                       int force_send)
42 {
43   SilcSocketConnection sock = conn->sock;
44   SilcBuffer buffer;
45   SilcPacketContext packetdata;
46   SilcCipher cipher;
47   SilcHmac hmac;
48
49   SILC_LOG_DEBUG(("Sending private message"));
50
51   /* Encode private message payload */
52   buffer = silc_private_message_payload_encode(flags,
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_send;
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_get_len(conn->local_id, SILC_ID_CLIENT);
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_get_len(client_entry->id, SILC_ID_CLIENT);
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, FALSE);
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                                            uint32 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_flags(payload),
177                                silc_private_message_get_message(payload, 
178                                                                 NULL));
179
180   /* See if we are away (gone). If we are away we will reply to the
181      sender with the set away message. */
182   if (conn->away && conn->away->away) {
183     /* If it's me, ignore */
184     if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
185       goto out;
186
187     /* Send the away message */
188     silc_client_send_private_message(client, conn, remote_client,
189                                      SILC_MESSAGE_FLAG_AUTOREPLY,
190                                      conn->away->away,
191                                      strlen(conn->away->away), TRUE);
192   }
193
194  out:
195   if (payload)
196     silc_private_message_payload_free(payload);
197   if (remote_id)
198     silc_free(remote_id);
199 }
200
201 /* Function that actually employes the received private message key */
202
203 static void silc_client_private_message_key_cb(SilcClient client,
204                                                SilcClientConnection conn,
205                                                SilcClientEntry *clients,
206                                                uint32 clients_count,
207                                                void *context)
208 {
209   SilcPacketContext *packet = (SilcPacketContext *)context;
210   unsigned char *key;
211   uint16 key_len;
212   unsigned char *cipher;
213   int ret;
214
215   if (!clients)
216     goto out;
217
218   /* Parse the private message key payload */
219   ret = silc_buffer_unformat(packet->buffer,
220                              SILC_STR_UI16_NSTRING(&key, &key_len),
221                              SILC_STR_UI16_STRING(&cipher),
222                              SILC_STR_END);
223   if (!ret)
224     goto out;
225
226   if (key_len > packet->buffer->len)
227     goto out;
228
229   /* Now take the key in use */
230   if (!silc_client_add_private_message_key(client, conn, clients[0],
231                                            cipher, key, key_len, FALSE))
232     goto out;
233
234   /* Print some info for application */
235   client->ops->say(client, conn, 
236                    "Received private message key from %s%s%s %s%s%s", 
237                    clients[0]->nickname,
238                    clients[0]->server ? "@" : "",
239                    clients[0]->server ? clients[0]->server : "",
240                    clients[0]->username ? "(" : "",
241                    clients[0]->username ? clients[0]->username : "",
242                    clients[0]->username ? ")" : "");
243
244  out:
245   silc_packet_context_free(packet);
246 }
247
248 /* Processes incoming Private Message Key payload. The libary always
249    accepts the key and takes it into use. */
250
251 void silc_client_private_message_key(SilcClient client,
252                                      SilcSocketConnection sock,
253                                      SilcPacketContext *packet)
254 {
255   SilcClientID *remote_id;
256
257   if (packet->src_id_type != SILC_ID_CLIENT)
258     return;
259
260   remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
261                              SILC_ID_CLIENT);
262   if (!remote_id)
263     return;
264
265   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
266                                        silc_client_private_message_key_cb,
267                                        silc_packet_context_dup(packet));
268   silc_free(remote_id);
269 }
270
271 /* Adds private message key to the client library. The key will be used to
272    encrypt all private message between the client and the remote client
273    indicated by the `client_entry'. If the `key' is NULL and the boolean
274    value `generate_key' is TRUE the library will generate random key.
275    The `key' maybe for example pre-shared-key, passphrase or similar.
276    The `cipher' MAY be provided but SHOULD be NULL to assure that the
277    requirements of the SILC protocol are met. The API, however, allows
278    to allocate any cipher.
279
280    It is not necessary to set key for normal private message usage. If the
281    key is not set then the private messages are encrypted using normal
282    session keys. Setting the private key, however, increases the security. 
283
284    Returns FALSE if the key is already set for the `client_entry', TRUE
285    otherwise. */
286
287 int silc_client_add_private_message_key(SilcClient client,
288                                         SilcClientConnection conn,
289                                         SilcClientEntry client_entry,
290                                         char *cipher,
291                                         unsigned char *key,
292                                         uint32 key_len,
293                                         int generate_key)
294 {
295   unsigned char private_key[32];
296   uint32 len;
297   int i;
298   SilcSKEKeyMaterial *keymat;
299
300   assert(client_entry);
301
302   /* Return FALSE if key already set */
303   if (client_entry->send_key && client_entry->receive_key)
304     return FALSE;
305
306   if (!cipher)
307     cipher = "aes-256-cbc";
308
309   /* Check the requested cipher */
310   if (!silc_cipher_is_supported(cipher))
311     return FALSE;
312
313   /* Generate key if not provided */
314   if (generate_key == TRUE) {
315     len = 32;
316     for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
317     key = private_key;
318     key_len = len;
319     client_entry->generated = TRUE;
320   }
321
322   /* Save the key */
323   client_entry->key = silc_calloc(key_len, sizeof(*client_entry->key));
324   memcpy(client_entry->key, key, key_len);
325   client_entry->key_len = key_len;
326
327   /* Produce the key material as the protocol defines */
328   keymat = silc_calloc(1, sizeof(*keymat));
329   if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16, 
330                                          client->md5hash, keymat) 
331       != SILC_SKE_STATUS_OK)
332     return FALSE;
333
334   /* Allocate the ciphers */
335   silc_cipher_alloc(cipher, &client_entry->send_key);
336   silc_cipher_alloc(cipher, &client_entry->receive_key);
337
338   /* Set the keys */
339   silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
340                       keymat->enc_key_len);
341   silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
342   silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
343                       keymat->enc_key_len);
344   silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
345
346   /* Free the key material */
347   silc_ske_free_key_material(keymat);
348
349   return TRUE;
350 }
351
352 /* Same as above but takes the key material from the SKE key material
353    structure. This structure is received if the application uses the
354    silc_client_send_key_agreement to negotiate the key material. The
355    `cipher' SHOULD be provided as it is negotiated also in the SKE
356    protocol. */
357
358 int silc_client_add_private_message_key_ske(SilcClient client,
359                                             SilcClientConnection conn,
360                                             SilcClientEntry client_entry,
361                                             char *cipher,
362                                             SilcSKEKeyMaterial *key)
363 {
364   assert(client_entry);
365
366   /* Return FALSE if key already set */
367   if (client_entry->send_key && client_entry->receive_key)
368     return FALSE;
369
370   if (!cipher)
371     cipher = "aes-256-cbc";
372
373   /* Check the requested cipher */
374   if (!silc_cipher_is_supported(cipher))
375     return FALSE;
376
377   /* Allocate the ciphers */
378   silc_cipher_alloc(cipher, &client_entry->send_key);
379   silc_cipher_alloc(cipher, &client_entry->receive_key);
380
381   /* Set the keys */
382   silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
383                       key->enc_key_len);
384   silc_cipher_set_iv(client_entry->send_key, key->send_iv);
385   silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
386                       key->enc_key_len);
387   silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
388
389   return TRUE;
390 }
391
392 /* Sends private message key payload to the remote client indicated by
393    the `client_entry'. If the `force_send' is TRUE the packet is sent
394    immediately. Returns FALSE if error occurs, TRUE otherwise. The
395    application should call this function after setting the key to the
396    client.
397
398    Note that the key sent using this function is sent to the remote client
399    through the SILC network. The packet is protected using normal session
400    keys. */
401
402 int silc_client_send_private_message_key(SilcClient client,
403                                          SilcClientConnection conn,
404                                          SilcClientEntry client_entry,
405                                          int force_send)
406 {
407   SilcSocketConnection sock = conn->sock;
408   SilcBuffer buffer;
409   int cipher_len;
410
411   if (!client_entry->send_key || !client_entry->key)
412     return FALSE;
413
414   SILC_LOG_DEBUG(("Sending private message key"));
415
416   cipher_len = strlen(client_entry->send_key->cipher->name);
417
418   /* Create private message key payload */
419   buffer = silc_buffer_alloc(2 + client_entry->key_len);
420   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
421   silc_buffer_format(buffer,
422                      SILC_STR_UI_SHORT(client_entry->key_len),
423                      SILC_STR_UI_XNSTRING(client_entry->key, 
424                                           client_entry->key_len),
425                      SILC_STR_UI_SHORT(cipher_len),
426                      SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
427                                           cipher_len),
428                      SILC_STR_END);
429
430   /* Send the packet */
431   silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
432                           client_entry->id, SILC_ID_CLIENT, NULL, NULL,
433                           buffer->data, buffer->len, force_send);
434   silc_free(buffer);
435
436   return TRUE;
437 }
438
439 /* Removes the private message from the library. The key won't be used
440    after this to protect the private messages with the remote `client_entry'
441    client. Returns FALSE on error, TRUE otherwise. */
442
443 int silc_client_del_private_message_key(SilcClient client,
444                                         SilcClientConnection conn,
445                                         SilcClientEntry client_entry)
446 {
447   assert(client_entry);
448
449   if (!client_entry->send_key && !client_entry->receive_key)
450     return FALSE;
451
452   silc_cipher_free(client_entry->send_key);
453   silc_cipher_free(client_entry->receive_key);
454
455   if (client_entry->key) {
456     memset(client_entry->key, 0, client_entry->key_len);
457     silc_free(client_entry->key);
458   }
459
460   client_entry->send_key = NULL;
461   client_entry->receive_key = NULL;
462   client_entry->key = NULL;
463
464   return TRUE;
465 }
466
467 /* Returns array of set private message keys associated to the connection
468    `conn'. Returns allocated SilcPrivateMessageKeys array and the array
469    count to the `key_count' argument. The array must be freed by the caller
470    by calling the silc_client_free_private_message_keys function. Note: 
471    the keys returned in the array is in raw format. It might not be desired
472    to show the keys as is. The application might choose not to show the keys
473    at all or to show the fingerprints of the keys. */
474
475 SilcPrivateMessageKeys
476 silc_client_list_private_message_keys(SilcClient client,
477                                       SilcClientConnection conn,
478                                       uint32 *key_count)
479 {
480   SilcPrivateMessageKeys keys;
481   uint32 count = 0;
482   SilcIDCacheEntry id_cache;
483   SilcIDCacheList list;
484   SilcClientEntry entry;
485
486   if (!silc_idcache_find_by_id(conn->client_cache, SILC_ID_CACHE_ANY, 
487                                SILC_ID_CLIENT, &list))
488     return NULL;
489
490   if (!silc_idcache_list_count(list)) {
491     silc_idcache_list_free(list);
492     return NULL;
493   }
494
495   keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
496
497   silc_idcache_list_first(list, &id_cache);
498   while (id_cache) {
499     entry = (SilcClientEntry)id_cache->context;
500
501     if (entry->send_key) {
502       keys[count].client_entry = entry;
503       keys[count].cipher = entry->send_key->cipher->name;
504       keys[count].key = entry->generated == FALSE ? entry->key : NULL;
505       keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
506       count++;
507     }
508
509     if (!silc_idcache_list_next(list, &id_cache))
510       break;
511   }
512
513   if (key_count)
514     *key_count = count;
515
516   return keys;
517 }
518
519 /* Frees the SilcPrivateMessageKeys array returned by the function
520    silc_client_list_private_message_keys. */
521
522 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
523                                            uint32 key_count)
524 {
525   silc_free(keys);
526 }