Integer type name change.
[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   SilcCipher cipher;
48   SilcHmac hmac;
49   int block_len;
50
51   SILC_LOG_DEBUG(("Sending private message"));
52
53   /* Encode private message payload */
54   buffer = silc_private_message_payload_encode(flags,
55                                                data_len, data,
56                                                client_entry->send_key);
57
58   /* If we don't have private message specific key then private messages
59      are just as any normal packet thus call normal packet sending.  If
60      the key exist then the encryption process is a bit different and
61      will be done in the rest of this function. */
62   if (!client_entry->send_key) {
63     silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
64                             client_entry->id, SILC_ID_CLIENT, NULL, NULL,
65                             buffer->data, buffer->len, force_send);
66     goto out;
67   }
68
69   /* We have private message specific key */
70
71   /* Get data used in the encryption */
72   cipher = client_entry->send_key;
73   hmac = conn->hmac_send;
74   block_len = silc_cipher_get_block_len(cipher);
75
76   /* Set the packet context pointers. */
77   packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
78   packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
79   packetdata.src_id = conn->local_id_data;
80   packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
81   packetdata.src_id_type = SILC_ID_CLIENT;
82   packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
83   packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
84   packetdata.dst_id_type = SILC_ID_CLIENT;
85   packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN + 
86     packetdata.src_id_len + packetdata.dst_id_len;
87   packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
88                                           packetdata.src_id_len +
89                                           packetdata.dst_id_len), block_len);
90
91   /* Prepare outgoing data buffer for packet sending */
92   silc_packet_send_prepare(sock, 
93                            SILC_PACKET_HEADER_LEN +
94                            packetdata.src_id_len + 
95                            packetdata.dst_id_len,
96                            packetdata.padlen,
97                            buffer->len);
98   
99   packetdata.buffer = sock->outbuf;
100
101   /* Put the actual encrypted message payload data into the buffer. */
102   silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
103
104   /* Create the outgoing packet */
105   silc_packet_assemble(&packetdata, cipher);
106
107   /* Encrypt the header and padding of the packet. */
108   cipher = conn->send_key;
109   silc_packet_encrypt(cipher, hmac, conn->psn_send++,
110                       sock->outbuf, SILC_PACKET_HEADER_LEN + 
111                       packetdata.src_id_len + packetdata.dst_id_len +
112                       packetdata.padlen);
113
114   SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
115                    sock->outbuf->data, sock->outbuf->len);
116
117   /* Now actually send the packet */
118   silc_client_packet_send_real(client, sock, force_send);
119   silc_free(packetdata.dst_id);
120
121  out:
122   silc_buffer_free(buffer);
123 }     
124
125 static void silc_client_private_message_cb(SilcClient client,
126                                            SilcClientConnection conn,
127                                            SilcClientEntry *clients,
128                                            SilcUInt32 clients_count,
129                                            void *context)
130 {
131   SilcPacketContext *packet = (SilcPacketContext *)context;
132
133   if (!clients) {
134     silc_packet_context_free(packet);
135     return;
136   }
137
138   silc_client_private_message(client, conn->sock, packet);
139   silc_packet_context_free(packet);
140 }
141
142 /* Private message received. This processes the private message and
143    finally displays it on the screen. */
144
145 void silc_client_private_message(SilcClient client, 
146                                  SilcSocketConnection sock, 
147                                  SilcPacketContext *packet)
148 {
149   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
150   SilcPrivateMessagePayload payload = NULL;
151   SilcClientID *remote_id = NULL;
152   SilcClientEntry remote_client;
153   SilcMessageFlags flags;
154
155   if (packet->src_id_type != SILC_ID_CLIENT)
156     goto out;
157
158   remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
159                              SILC_ID_CLIENT);
160   if (!remote_id)
161     goto out;
162
163   /* Check whether we know this client already */
164   remote_client = silc_client_get_client_by_id(client, conn, remote_id);
165   if (!remote_client || !remote_client->nickname) {
166     if (remote_client) {
167       if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
168         remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
169         goto out;
170       }
171       remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
172     }
173
174     /* Resolve the client info */
175     silc_client_get_client_by_id_resolve(client, conn, remote_id,
176                                          silc_client_private_message_cb,
177                                          silc_packet_context_dup(packet));
178     return;
179   }
180
181   /* Parse the payload and decrypt it also if private message key is set */
182   payload = silc_private_message_payload_parse(packet->buffer->data,
183                                                packet->buffer->len,
184                                                remote_client->receive_key);
185   if (!payload) {
186     silc_free(remote_id);
187     return;
188   }
189
190   flags = silc_private_message_get_flags(payload);
191
192   /* Pass the private message to application */
193   client->internal->ops->private_message(
194                                  client, conn, remote_client, flags,
195                                  silc_private_message_get_message(payload, 
196                                                                   NULL));
197
198   /* See if we are away (gone). If we are away we will reply to the
199      sender with the set away message. */
200   if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
201     /* If it's me, ignore */
202     if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
203       goto out;
204
205     /* Send the away message */
206     silc_client_send_private_message(client, conn, remote_client,
207                                      SILC_MESSAGE_FLAG_AUTOREPLY |
208                                      SILC_MESSAGE_FLAG_NOREPLY,
209                                      conn->away->away,
210                                      strlen(conn->away->away), TRUE);
211   }
212
213  out:
214   if (payload)
215     silc_private_message_payload_free(payload);
216   silc_free(remote_id);
217 }
218
219 /* Function that actually employes the received private message key */
220
221 static void silc_client_private_message_key_cb(SilcClient client,
222                                                SilcClientConnection conn,
223                                                SilcClientEntry *clients,
224                                                SilcUInt32 clients_count,
225                                                void *context)
226 {
227   SilcPacketContext *packet = (SilcPacketContext *)context;
228   unsigned char *key;
229   SilcUInt16 key_len;
230   unsigned char *cipher;
231   int ret;
232
233   if (!clients)
234     goto out;
235
236   /* Parse the private message key payload */
237   ret = silc_buffer_unformat(packet->buffer,
238                              SILC_STR_UI16_NSTRING(&key, &key_len),
239                              SILC_STR_UI16_STRING(&cipher),
240                              SILC_STR_END);
241   if (!ret)
242     goto out;
243
244   if (key_len > packet->buffer->len)
245     goto out;
246
247   /* Now take the key in use */
248   if (!silc_client_add_private_message_key(client, conn, clients[0],
249                                            cipher, key, key_len, FALSE, TRUE))
250     goto out;
251
252   /* Print some info for application */
253   client->internal->ops->say(
254                      client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
255                      "Received private message key from %s%s%s %s%s%s", 
256                      clients[0]->nickname,
257                      clients[0]->server ? "@" : "",
258                      clients[0]->server ? clients[0]->server : "",
259                      clients[0]->username ? "(" : "",
260                      clients[0]->username ? clients[0]->username : "",
261                      clients[0]->username ? ")" : "");
262
263  out:
264   silc_packet_context_free(packet);
265 }
266
267 /* Processes incoming Private Message Key payload. The libary always
268    accepts the key and takes it into use. */
269
270 void silc_client_private_message_key(SilcClient client,
271                                      SilcSocketConnection sock,
272                                      SilcPacketContext *packet)
273 {
274   SilcClientID *remote_id;
275
276   if (packet->src_id_type != SILC_ID_CLIENT)
277     return;
278
279   remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
280                              SILC_ID_CLIENT);
281   if (!remote_id)
282     return;
283
284   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
285                                        silc_client_private_message_key_cb,
286                                        silc_packet_context_dup(packet));
287   silc_free(remote_id);
288 }
289
290 /* Adds private message key to the client library. The key will be used to
291    encrypt all private message between the client and the remote client
292    indicated by the `client_entry'. If the `key' is NULL and the boolean
293    value `generate_key' is TRUE the library will generate random key.
294    The `key' maybe for example pre-shared-key, passphrase or similar.
295    The `cipher' MAY be provided but SHOULD be NULL to assure that the
296    requirements of the SILC protocol are met. The API, however, allows
297    to allocate any cipher.
298
299    If `responder' is TRUE then the sending and receiving keys will be
300    set according the client being the receiver of the private key.  If
301    FALSE the client is being the sender (or negotiator) of the private
302    key.
303
304    It is not necessary to set key for normal private message usage. If the
305    key is not set then the private messages are encrypted using normal
306    session keys. Setting the private key, however, increases the security. 
307
308    Returns FALSE if the key is already set for the `client_entry', TRUE
309    otherwise. */
310
311 int silc_client_add_private_message_key(SilcClient client,
312                                         SilcClientConnection conn,
313                                         SilcClientEntry client_entry,
314                                         char *cipher,
315                                         unsigned char *key,
316                                         SilcUInt32 key_len,
317                                         bool generate_key,
318                                         bool responder)
319 {
320   unsigned char private_key[32];
321   SilcUInt32 len;
322   int i;
323   SilcSKEKeyMaterial *keymat;
324
325   assert(client_entry);
326
327   /* Return FALSE if key already set */
328   if (client_entry->send_key && client_entry->receive_key)
329     return FALSE;
330
331   if (!cipher)
332     cipher = SILC_DEFAULT_CIPHER;
333
334   /* Check the requested cipher */
335   if (!silc_cipher_is_supported(cipher))
336     return FALSE;
337
338   /* Generate key if not provided */
339   if (generate_key == TRUE) {
340     len = 32;
341     for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
342     key = private_key;
343     key_len = len;
344     client_entry->generated = TRUE;
345   }
346
347   /* Save the key */
348   client_entry->key = silc_memdup(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                                       SilcUInt32 *key_count)
522 {
523   SilcPrivateMessageKeys keys;
524   SilcUInt32 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                                            SilcUInt32 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 }