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