Started implementing protocol version 1.1 and narrowing down
[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
154   if (packet->src_id_type != SILC_ID_CLIENT)
155     goto out;
156
157   remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
158                              SILC_ID_CLIENT);
159   if (!remote_id)
160     goto out;
161
162   /* Check whether we know this client already */
163   remote_client = silc_client_get_client_by_id(client, conn, remote_id);
164   if (!remote_client || !remote_client->nickname) {
165     if (remote_client) {
166       if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
167         remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
168         goto out;
169       }
170       remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
171     }
172
173     /* Resolve the client info */
174     silc_client_get_client_by_id_resolve(client, conn, remote_id,
175                                          silc_client_private_message_cb,
176                                          silc_packet_context_dup(packet));
177     return;
178   }
179
180   /* Parse the payload and decrypt it also if private message key is set */
181   payload = silc_private_message_payload_parse(packet->buffer->data,
182                                                packet->buffer->len,
183                                                remote_client->receive_key);
184   if (!payload) {
185     silc_free(remote_id);
186     return;
187   }
188
189   flags = silc_private_message_get_flags(payload);
190
191   /* Pass the private message to application */
192   message = silc_private_message_get_message(payload, &message_len);
193   client->internal->ops->private_message(client, conn, remote_client, flags,
194                                          message, message_len);
195
196   /* See if we are away (gone). If we are away we will reply to the
197      sender with the set away message. */
198   if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
199     /* If it's me, ignore */
200     if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
201       goto out;
202
203     /* Send the away message */
204     silc_client_send_private_message(client, conn, remote_client,
205                                      SILC_MESSAGE_FLAG_AUTOREPLY |
206                                      SILC_MESSAGE_FLAG_NOREPLY,
207                                      conn->away->away,
208                                      strlen(conn->away->away), TRUE);
209   }
210
211  out:
212   if (payload)
213     silc_private_message_payload_free(payload);
214   silc_free(remote_id);
215 }
216
217 /* Function that actually employes the received private message key */
218
219 static void silc_client_private_message_key_cb(SilcClient client,
220                                                SilcClientConnection conn,
221                                                SilcClientEntry *clients,
222                                                SilcUInt32 clients_count,
223                                                void *context)
224 {
225   SilcPacketContext *packet = (SilcPacketContext *)context;
226   unsigned char *key;
227   SilcUInt16 key_len;
228   unsigned char *cipher;
229   int ret;
230
231   if (!clients)
232     goto out;
233
234   /* Parse the private message key payload */
235   ret = silc_buffer_unformat(packet->buffer,
236                              SILC_STR_UI16_NSTRING(&key, &key_len),
237                              SILC_STR_UI16_STRING(&cipher),
238                              SILC_STR_END);
239   if (!ret)
240     goto out;
241
242   if (key_len > packet->buffer->len)
243     goto out;
244
245   /* Now take the key in use */
246   if (!silc_client_add_private_message_key(client, conn, clients[0],
247                                            cipher, key, key_len, FALSE, TRUE))
248     goto out;
249
250   /* Print some info for application */
251   client->internal->ops->say(
252                      client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
253                      "Received private message key from %s%s%s %s%s%s", 
254                      clients[0]->nickname,
255                      clients[0]->server ? "@" : "",
256                      clients[0]->server ? clients[0]->server : "",
257                      clients[0]->username ? "(" : "",
258                      clients[0]->username ? clients[0]->username : "",
259                      clients[0]->username ? ")" : "");
260
261  out:
262   silc_packet_context_free(packet);
263 }
264
265 /* Processes incoming Private Message Key payload. The libary always
266    accepts the key and takes it into use. */
267
268 void silc_client_private_message_key(SilcClient client,
269                                      SilcSocketConnection sock,
270                                      SilcPacketContext *packet)
271 {
272   SilcClientID *remote_id;
273
274   if (packet->src_id_type != SILC_ID_CLIENT)
275     return;
276
277   remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
278                              SILC_ID_CLIENT);
279   if (!remote_id)
280     return;
281
282   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
283                                        silc_client_private_message_key_cb,
284                                        silc_packet_context_dup(packet));
285   silc_free(remote_id);
286 }
287
288 /* Adds private message key to the client library. The key will be used to
289    encrypt all private message between the client and the remote client
290    indicated by the `client_entry'. If the `key' is NULL and the boolean
291    value `generate_key' is TRUE the library will generate random key.
292    The `key' maybe for example pre-shared-key, passphrase or similar.
293    The `cipher' MAY be provided but SHOULD be NULL to assure that the
294    requirements of the SILC protocol are met. The API, however, allows
295    to allocate any cipher.
296
297    If `responder' is TRUE then the sending and receiving keys will be
298    set according the client being the receiver of the private key.  If
299    FALSE the client is being the sender (or negotiator) of the private
300    key.
301
302    It is not necessary to set key for normal private message usage. If the
303    key is not set then the private messages are encrypted using normal
304    session keys. Setting the private key, however, increases the security. 
305
306    Returns FALSE if the key is already set for the `client_entry', TRUE
307    otherwise. */
308
309 int silc_client_add_private_message_key(SilcClient client,
310                                         SilcClientConnection conn,
311                                         SilcClientEntry client_entry,
312                                         char *cipher,
313                                         unsigned char *key,
314                                         SilcUInt32 key_len,
315                                         bool generate_key,
316                                         bool responder)
317 {
318   unsigned char private_key[32];
319   SilcUInt32 len;
320   int i;
321   SilcSKEKeyMaterial *keymat;
322
323   assert(client_entry);
324
325   /* Return FALSE if key already set */
326   if (client_entry->send_key && client_entry->receive_key)
327     return FALSE;
328
329   if (!cipher)
330     cipher = SILC_DEFAULT_CIPHER;
331
332   /* Check the requested cipher */
333   if (!silc_cipher_is_supported(cipher))
334     return FALSE;
335
336   /* Generate key if not provided */
337   if (generate_key == TRUE) {
338     len = 32;
339     for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
340     key = private_key;
341     key_len = len;
342     client_entry->generated = TRUE;
343   }
344
345   /* Save the key */
346   client_entry->key = silc_memdup(key, key_len);
347   client_entry->key_len = key_len;
348
349   /* Produce the key material as the protocol defines */
350   keymat = silc_calloc(1, sizeof(*keymat));
351   if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16, 
352                                          client->internal->md5hash, keymat) 
353       != SILC_SKE_STATUS_OK)
354     return FALSE;
355
356   /* Allocate the ciphers */
357   silc_cipher_alloc(cipher, &client_entry->send_key);
358   silc_cipher_alloc(cipher, &client_entry->receive_key);
359
360   /* Set the keys */
361   if (responder == TRUE) {
362     silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
363                         keymat->enc_key_len);
364     silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
365     silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
366                         keymat->enc_key_len);
367     silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
368   } else {
369     silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
370                         keymat->enc_key_len);
371     silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
372     silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
373                         keymat->enc_key_len);
374     silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
375   }
376
377   /* Free the key material */
378   silc_ske_free_key_material(keymat);
379
380   return TRUE;
381 }
382
383 /* Same as above but takes the key material from the SKE key material
384    structure. This structure is received if the application uses the
385    silc_client_send_key_agreement to negotiate the key material. The
386    `cipher' SHOULD be provided as it is negotiated also in the SKE
387    protocol. */
388
389 int silc_client_add_private_message_key_ske(SilcClient client,
390                                             SilcClientConnection conn,
391                                             SilcClientEntry client_entry,
392                                             char *cipher,
393                                             SilcSKEKeyMaterial *key,
394                                             bool responder)
395 {
396   assert(client_entry);
397
398   /* Return FALSE if key already set */
399   if (client_entry->send_key && client_entry->receive_key)
400     return FALSE;
401
402   if (!cipher)
403     cipher = SILC_DEFAULT_CIPHER;
404
405   /* Check the requested cipher */
406   if (!silc_cipher_is_supported(cipher))
407     return FALSE;
408
409   /* Allocate the ciphers */
410   silc_cipher_alloc(cipher, &client_entry->send_key);
411   silc_cipher_alloc(cipher, &client_entry->receive_key);
412
413   /* Set the keys */
414   if (responder == TRUE) {
415     silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
416                         key->enc_key_len);
417     silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
418     silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
419                         key->enc_key_len);
420     silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
421   } else {
422     silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
423                         key->enc_key_len);
424     silc_cipher_set_iv(client_entry->send_key, key->send_iv);
425     silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
426                         key->enc_key_len);
427     silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
428   }
429
430   return TRUE;
431 }
432
433 /* Sends private message key payload to the remote client indicated by
434    the `client_entry'. If the `force_send' is TRUE the packet is sent
435    immediately. Returns FALSE if error occurs, TRUE otherwise. The
436    application should call this function after setting the key to the
437    client.
438
439    Note that the key sent using this function is sent to the remote client
440    through the SILC network. The packet is protected using normal session
441    keys. */
442
443 int silc_client_send_private_message_key(SilcClient client,
444                                          SilcClientConnection conn,
445                                          SilcClientEntry client_entry,
446                                          int force_send)
447 {
448   SilcSocketConnection sock = conn->sock;
449   SilcBuffer buffer;
450   int cipher_len;
451
452   if (!client_entry->send_key || !client_entry->key)
453     return FALSE;
454
455   SILC_LOG_DEBUG(("Sending private message key"));
456
457   cipher_len = strlen(client_entry->send_key->cipher->name);
458
459   /* Create private message key payload */
460   buffer = silc_buffer_alloc(2 + client_entry->key_len);
461   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
462   silc_buffer_format(buffer,
463                      SILC_STR_UI_SHORT(client_entry->key_len),
464                      SILC_STR_UI_XNSTRING(client_entry->key, 
465                                           client_entry->key_len),
466                      SILC_STR_UI_SHORT(cipher_len),
467                      SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
468                                           cipher_len),
469                      SILC_STR_END);
470
471   /* Send the packet */
472   silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
473                           client_entry->id, SILC_ID_CLIENT, NULL, NULL,
474                           buffer->data, buffer->len, force_send);
475   silc_free(buffer);
476
477   return TRUE;
478 }
479
480 /* Removes the private message from the library. The key won't be used
481    after this to protect the private messages with the remote `client_entry'
482    client. Returns FALSE on error, TRUE otherwise. */
483
484 int silc_client_del_private_message_key(SilcClient client,
485                                         SilcClientConnection conn,
486                                         SilcClientEntry client_entry)
487 {
488   assert(client_entry);
489
490   if (!client_entry->send_key && !client_entry->receive_key)
491     return FALSE;
492
493   silc_cipher_free(client_entry->send_key);
494   silc_cipher_free(client_entry->receive_key);
495
496   if (client_entry->key) {
497     memset(client_entry->key, 0, client_entry->key_len);
498     silc_free(client_entry->key);
499   }
500
501   client_entry->send_key = NULL;
502   client_entry->receive_key = NULL;
503   client_entry->key = NULL;
504
505   return TRUE;
506 }
507
508 /* Returns array of set private message keys associated to the connection
509    `conn'. Returns allocated SilcPrivateMessageKeys array and the array
510    count to the `key_count' argument. The array must be freed by the caller
511    by calling the silc_client_free_private_message_keys function. Note: 
512    the keys returned in the array is in raw format. It might not be desired
513    to show the keys as is. The application might choose not to show the keys
514    at all or to show the fingerprints of the keys. */
515
516 SilcPrivateMessageKeys
517 silc_client_list_private_message_keys(SilcClient client,
518                                       SilcClientConnection conn,
519                                       SilcUInt32 *key_count)
520 {
521   SilcPrivateMessageKeys keys;
522   SilcUInt32 count = 0;
523   SilcIDCacheEntry id_cache;
524   SilcIDCacheList list;
525   SilcClientEntry entry;
526
527   if (!silc_idcache_get_all(conn->client_cache, &list))
528     return NULL;
529
530   if (!silc_idcache_list_count(list)) {
531     silc_idcache_list_free(list);
532     return NULL;
533   }
534
535   keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
536
537   silc_idcache_list_first(list, &id_cache);
538   while (id_cache) {
539     entry = (SilcClientEntry)id_cache->context;
540
541     if (entry->send_key) {
542       keys[count].client_entry = entry;
543       keys[count].cipher = entry->send_key->cipher->name;
544       keys[count].key = entry->generated == FALSE ? entry->key : NULL;
545       keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
546       count++;
547     }
548
549     if (!silc_idcache_list_next(list, &id_cache))
550       break;
551   }
552
553   if (key_count)
554     *key_count = count;
555
556   return keys;
557 }
558
559 /* Frees the SilcPrivateMessageKeys array returned by the function
560    silc_client_list_private_message_keys. */
561
562 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
563                                            SilcUInt32 key_count)
564 {
565   silc_free(keys);
566 }
567
568 /* Sets away `message'.  The away message may be set when the client's
569    mode is changed to SILC_UMODE_GONE and the client whishes to reply
570    to anyone who sends private message.  The `message' will be sent
571    automatically back to the the client who send private message.  If
572    away message is already set this replaces the old message with the
573    new one.  If `message' is NULL the old away message is removed. 
574    The sender may freely free the memory of the `message'. */
575
576 void silc_client_set_away_message(SilcClient client,
577                                   SilcClientConnection conn,
578                                   char *message)
579 {
580   if (!message && conn->away) {
581     silc_free(conn->away->away);
582     silc_free(conn->away);
583     conn->away = NULL;
584   }
585
586   if (message) {
587     if (!conn->away)
588       conn->away = silc_calloc(1, sizeof(*conn->away));
589     if (conn->away->away)
590       silc_free(conn->away->away);
591     conn->away->away = strdup(message);
592   }
593 }