450fb40537b3e7a5cf910c99c1b9ad116cf25c83
[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   int block_len;
49
50   SILC_LOG_DEBUG(("Sending private message"));
51
52   /* Encode private message payload */
53   buffer = silc_private_message_payload_encode(flags,
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_send;
73   block_len = silc_cipher_get_block_len(cipher);
74
75   /* Set the packet context pointers. */
76   packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
77   packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
78   packetdata.src_id = conn->local_id_data;
79   packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
80   packetdata.src_id_type = SILC_ID_CLIENT;
81   packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
82   packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
83   packetdata.dst_id_type = SILC_ID_CLIENT;
84   packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN + 
85     packetdata.src_id_len + packetdata.dst_id_len;
86   packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
87                                           packetdata.src_id_len +
88                                           packetdata.dst_id_len), block_len);
89
90   /* Prepare outgoing data buffer for packet sending */
91   silc_packet_send_prepare(sock, 
92                            SILC_PACKET_HEADER_LEN +
93                            packetdata.src_id_len + 
94                            packetdata.dst_id_len,
95                            packetdata.padlen,
96                            buffer->len);
97   
98   packetdata.buffer = sock->outbuf;
99
100   /* Put the actual encrypted message payload data into the buffer. */
101   silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
102
103   /* Create the outgoing packet */
104   silc_packet_assemble(&packetdata, cipher);
105
106   /* Encrypt the header and padding of the packet. */
107   cipher = conn->send_key;
108   silc_packet_encrypt(cipher, hmac, conn->psn_send++,
109                       sock->outbuf, SILC_PACKET_HEADER_LEN + 
110                       packetdata.src_id_len + packetdata.dst_id_len +
111                       packetdata.padlen);
112
113   SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
114                    sock->outbuf->data, sock->outbuf->len);
115
116   /* Now actually send the packet */
117   silc_client_packet_send_real(client, sock, force_send);
118   silc_free(packetdata.dst_id);
119
120  out:
121   silc_buffer_free(buffer);
122 }     
123
124 static void silc_client_private_message_cb(SilcClient client,
125                                            SilcClientConnection conn,
126                                            SilcClientEntry *clients,
127                                            uint32 clients_count,
128                                            void *context)
129 {
130   SilcPacketContext *packet = (SilcPacketContext *)context;
131
132   if (!clients) {
133     silc_packet_context_free(packet);
134     return;
135   }
136
137   silc_client_private_message(client, conn->sock, packet);
138   silc_packet_context_free(packet);
139 }
140
141 /* Private message received. This processes the private message and
142    finally displays it on the screen. */
143
144 void silc_client_private_message(SilcClient client, 
145                                  SilcSocketConnection sock, 
146                                  SilcPacketContext *packet)
147 {
148   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
149   SilcPrivateMessagePayload payload = NULL;
150   SilcClientID *remote_id = NULL;
151   SilcClientEntry remote_client;
152   SilcMessageFlags flags;
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   client->internal->ops->private_message(
193                                  client, conn, remote_client, flags,
194                                  silc_private_message_get_message(payload, 
195                                                                   NULL));
196
197   /* See if we are away (gone). If we are away we will reply to the
198      sender with the set away message. */
199   if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
200     /* If it's me, ignore */
201     if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
202       goto out;
203
204     /* Send the away message */
205     silc_client_send_private_message(client, conn, remote_client,
206                                      SILC_MESSAGE_FLAG_AUTOREPLY |
207                                      SILC_MESSAGE_FLAG_NOREPLY,
208                                      conn->away->away,
209                                      strlen(conn->away->away), TRUE);
210   }
211
212  out:
213   if (payload)
214     silc_private_message_payload_free(payload);
215   silc_free(remote_id);
216 }
217
218 /* Function that actually employes the received private message key */
219
220 static void silc_client_private_message_key_cb(SilcClient client,
221                                                SilcClientConnection conn,
222                                                SilcClientEntry *clients,
223                                                uint32 clients_count,
224                                                void *context)
225 {
226   SilcPacketContext *packet = (SilcPacketContext *)context;
227   unsigned char *key;
228   uint16 key_len;
229   unsigned char *cipher;
230   int ret;
231
232   if (!clients)
233     goto out;
234
235   /* Parse the private message key payload */
236   ret = silc_buffer_unformat(packet->buffer,
237                              SILC_STR_UI16_NSTRING(&key, &key_len),
238                              SILC_STR_UI16_STRING(&cipher),
239                              SILC_STR_END);
240   if (!ret)
241     goto out;
242
243   if (key_len > packet->buffer->len)
244     goto out;
245
246   /* Now take the key in use */
247   if (!silc_client_add_private_message_key(client, conn, clients[0],
248                                            cipher, key, key_len, FALSE, TRUE))
249     goto out;
250
251   /* Print some info for application */
252   client->internal->ops->say(
253                      client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
254                      "Received private message key from %s%s%s %s%s%s", 
255                      clients[0]->nickname,
256                      clients[0]->server ? "@" : "",
257                      clients[0]->server ? clients[0]->server : "",
258                      clients[0]->username ? "(" : "",
259                      clients[0]->username ? clients[0]->username : "",
260                      clients[0]->username ? ")" : "");
261
262  out:
263   silc_packet_context_free(packet);
264 }
265
266 /* Processes incoming Private Message Key payload. The libary always
267    accepts the key and takes it into use. */
268
269 void silc_client_private_message_key(SilcClient client,
270                                      SilcSocketConnection sock,
271                                      SilcPacketContext *packet)
272 {
273   SilcClientID *remote_id;
274
275   if (packet->src_id_type != SILC_ID_CLIENT)
276     return;
277
278   remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
279                              SILC_ID_CLIENT);
280   if (!remote_id)
281     return;
282
283   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
284                                        silc_client_private_message_key_cb,
285                                        silc_packet_context_dup(packet));
286   silc_free(remote_id);
287 }
288
289 /* Adds private message key to the client library. The key will be used to
290    encrypt all private message between the client and the remote client
291    indicated by the `client_entry'. If the `key' is NULL and the boolean
292    value `generate_key' is TRUE the library will generate random key.
293    The `key' maybe for example pre-shared-key, passphrase or similar.
294    The `cipher' MAY be provided but SHOULD be NULL to assure that the
295    requirements of the SILC protocol are met. The API, however, allows
296    to allocate any cipher.
297
298    If `responder' is TRUE then the sending and receiving keys will be
299    set according the client being the receiver of the private key.  If
300    FALSE the client is being the sender (or negotiator) of the private
301    key.
302
303    It is not necessary to set key for normal private message usage. If the
304    key is not set then the private messages are encrypted using normal
305    session keys. Setting the private key, however, increases the security. 
306
307    Returns FALSE if the key is already set for the `client_entry', TRUE
308    otherwise. */
309
310 int silc_client_add_private_message_key(SilcClient client,
311                                         SilcClientConnection conn,
312                                         SilcClientEntry client_entry,
313                                         char *cipher,
314                                         unsigned char *key,
315                                         uint32 key_len,
316                                         bool generate_key,
317                                         bool responder)
318 {
319   unsigned char private_key[32];
320   uint32 len;
321   int i;
322   SilcSKEKeyMaterial *keymat;
323
324   assert(client_entry);
325
326   /* Return FALSE if key already set */
327   if (client_entry->send_key && client_entry->receive_key)
328     return FALSE;
329
330   if (!cipher)
331     cipher = SILC_DEFAULT_CIPHER;
332
333   /* Check the requested cipher */
334   if (!silc_cipher_is_supported(cipher))
335     return FALSE;
336
337   /* Generate key if not provided */
338   if (generate_key == TRUE) {
339     len = 32;
340     for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
341     key = private_key;
342     key_len = len;
343     client_entry->generated = TRUE;
344   }
345
346   /* Save the key */
347   client_entry->key = silc_calloc(key_len, sizeof(*client_entry->key));
348   memcpy(client_entry->key, key, key_len);
349   client_entry->key_len = key_len;
350
351   /* Produce the key material as the protocol defines */
352   keymat = silc_calloc(1, sizeof(*keymat));
353   if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16, 
354                                          client->internal->md5hash, keymat) 
355       != SILC_SKE_STATUS_OK)
356     return FALSE;
357
358   /* Allocate the ciphers */
359   silc_cipher_alloc(cipher, &client_entry->send_key);
360   silc_cipher_alloc(cipher, &client_entry->receive_key);
361
362   /* Set the keys */
363   if (responder == TRUE) {
364     silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
365                         keymat->enc_key_len);
366     silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
367     silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
368                         keymat->enc_key_len);
369     silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
370   } else {
371     silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
372                         keymat->enc_key_len);
373     silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
374     silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
375                         keymat->enc_key_len);
376     silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
377   }
378
379   /* Free the key material */
380   silc_ske_free_key_material(keymat);
381
382   return TRUE;
383 }
384
385 /* Same as above but takes the key material from the SKE key material
386    structure. This structure is received if the application uses the
387    silc_client_send_key_agreement to negotiate the key material. The
388    `cipher' SHOULD be provided as it is negotiated also in the SKE
389    protocol. */
390
391 int silc_client_add_private_message_key_ske(SilcClient client,
392                                             SilcClientConnection conn,
393                                             SilcClientEntry client_entry,
394                                             char *cipher,
395                                             SilcSKEKeyMaterial *key,
396                                             bool responder)
397 {
398   assert(client_entry);
399
400   /* Return FALSE if key already set */
401   if (client_entry->send_key && client_entry->receive_key)
402     return FALSE;
403
404   if (!cipher)
405     cipher = SILC_DEFAULT_CIPHER;
406
407   /* Check the requested cipher */
408   if (!silc_cipher_is_supported(cipher))
409     return FALSE;
410
411   /* Allocate the ciphers */
412   silc_cipher_alloc(cipher, &client_entry->send_key);
413   silc_cipher_alloc(cipher, &client_entry->receive_key);
414
415   /* Set the keys */
416   if (responder == TRUE) {
417     silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
418                         key->enc_key_len);
419     silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
420     silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
421                         key->enc_key_len);
422     silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
423   } else {
424     silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
425                         key->enc_key_len);
426     silc_cipher_set_iv(client_entry->send_key, key->send_iv);
427     silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
428                         key->enc_key_len);
429     silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
430   }
431
432   return TRUE;
433 }
434
435 /* Sends private message key payload to the remote client indicated by
436    the `client_entry'. If the `force_send' is TRUE the packet is sent
437    immediately. Returns FALSE if error occurs, TRUE otherwise. The
438    application should call this function after setting the key to the
439    client.
440
441    Note that the key sent using this function is sent to the remote client
442    through the SILC network. The packet is protected using normal session
443    keys. */
444
445 int silc_client_send_private_message_key(SilcClient client,
446                                          SilcClientConnection conn,
447                                          SilcClientEntry client_entry,
448                                          int force_send)
449 {
450   SilcSocketConnection sock = conn->sock;
451   SilcBuffer buffer;
452   int cipher_len;
453
454   if (!client_entry->send_key || !client_entry->key)
455     return FALSE;
456
457   SILC_LOG_DEBUG(("Sending private message key"));
458
459   cipher_len = strlen(client_entry->send_key->cipher->name);
460
461   /* Create private message key payload */
462   buffer = silc_buffer_alloc(2 + client_entry->key_len);
463   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
464   silc_buffer_format(buffer,
465                      SILC_STR_UI_SHORT(client_entry->key_len),
466                      SILC_STR_UI_XNSTRING(client_entry->key, 
467                                           client_entry->key_len),
468                      SILC_STR_UI_SHORT(cipher_len),
469                      SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
470                                           cipher_len),
471                      SILC_STR_END);
472
473   /* Send the packet */
474   silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
475                           client_entry->id, SILC_ID_CLIENT, NULL, NULL,
476                           buffer->data, buffer->len, force_send);
477   silc_free(buffer);
478
479   return TRUE;
480 }
481
482 /* Removes the private message from the library. The key won't be used
483    after this to protect the private messages with the remote `client_entry'
484    client. Returns FALSE on error, TRUE otherwise. */
485
486 int silc_client_del_private_message_key(SilcClient client,
487                                         SilcClientConnection conn,
488                                         SilcClientEntry client_entry)
489 {
490   assert(client_entry);
491
492   if (!client_entry->send_key && !client_entry->receive_key)
493     return FALSE;
494
495   silc_cipher_free(client_entry->send_key);
496   silc_cipher_free(client_entry->receive_key);
497
498   if (client_entry->key) {
499     memset(client_entry->key, 0, client_entry->key_len);
500     silc_free(client_entry->key);
501   }
502
503   client_entry->send_key = NULL;
504   client_entry->receive_key = NULL;
505   client_entry->key = NULL;
506
507   return TRUE;
508 }
509
510 /* Returns array of set private message keys associated to the connection
511    `conn'. Returns allocated SilcPrivateMessageKeys array and the array
512    count to the `key_count' argument. The array must be freed by the caller
513    by calling the silc_client_free_private_message_keys function. Note: 
514    the keys returned in the array is in raw format. It might not be desired
515    to show the keys as is. The application might choose not to show the keys
516    at all or to show the fingerprints of the keys. */
517
518 SilcPrivateMessageKeys
519 silc_client_list_private_message_keys(SilcClient client,
520                                       SilcClientConnection conn,
521                                       uint32 *key_count)
522 {
523   SilcPrivateMessageKeys keys;
524   uint32 count = 0;
525   SilcIDCacheEntry id_cache;
526   SilcIDCacheList list;
527   SilcClientEntry entry;
528
529   if (!silc_idcache_get_all(conn->client_cache, &list))
530     return NULL;
531
532   if (!silc_idcache_list_count(list)) {
533     silc_idcache_list_free(list);
534     return NULL;
535   }
536
537   keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
538
539   silc_idcache_list_first(list, &id_cache);
540   while (id_cache) {
541     entry = (SilcClientEntry)id_cache->context;
542
543     if (entry->send_key) {
544       keys[count].client_entry = entry;
545       keys[count].cipher = entry->send_key->cipher->name;
546       keys[count].key = entry->generated == FALSE ? entry->key : NULL;
547       keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
548       count++;
549     }
550
551     if (!silc_idcache_list_next(list, &id_cache))
552       break;
553   }
554
555   if (key_count)
556     *key_count = count;
557
558   return keys;
559 }
560
561 /* Frees the SilcPrivateMessageKeys array returned by the function
562    silc_client_list_private_message_keys. */
563
564 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
565                                            uint32 key_count)
566 {
567   silc_free(keys);
568 }
569
570 /* Sets away `message'.  The away message may be set when the client's
571    mode is changed to SILC_UMODE_GONE and the client whishes to reply
572    to anyone who sends private message.  The `message' will be sent
573    automatically back to the the client who send private message.  If
574    away message is already set this replaces the old message with the
575    new one.  If `message' is NULL the old away message is removed. 
576    The sender may freely free the memory of the `message'. */
577
578 void silc_client_set_away_message(SilcClient client,
579                                   SilcClientConnection conn,
580                                   char *message)
581 {
582   if (!message && conn->away) {
583     silc_free(conn->away->away);
584     silc_free(conn->away);
585     conn->away = NULL;
586   }
587
588   if (message) {
589     if (!conn->away)
590       conn->away = silc_calloc(1, sizeof(*conn->away));
591     if (conn->away->away)
592       silc_free(conn->away->away);
593     conn->away->away = strdup(message);
594   }
595 }