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