Added debugs.
[crypto.git] / lib / silcclient / client_prvmsg.c
1 /*
2
3   client_prvmsg.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2007 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silc.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
24
25 /************************** Private Message Send ****************************/
26
27 typedef struct {
28   SilcClient client;
29   SilcClientConnection conn;
30   SilcClientEntry client_entry;
31 } *SilcClientPrvmsgContext;
32
33 /* Message payload encoding callback */
34
35 static void silc_client_send_private_message_final(SilcBuffer message,
36                                                    void *context)
37 {
38   SilcClientPrvmsgContext p = context;
39
40   /* Send the private message packet */
41   if (message)
42     silc_packet_send_ext(p->conn->stream, SILC_PACKET_PRIVATE_MESSAGE,
43                          p->client_entry->internal.send_key ?
44                          SILC_PACKET_FLAG_PRIVMSG_KEY : 0,
45                          0, NULL, SILC_ID_CLIENT, &p->client_entry->id,
46                          silc_buffer_datalen(message), NULL, NULL);
47
48   silc_client_unref_client(p->client, p->conn, p->client_entry);
49   silc_free(p);
50 }
51
52 /* Sends private message to remote client. */
53
54 SilcBool silc_client_send_private_message(SilcClient client,
55                                           SilcClientConnection conn,
56                                           SilcClientEntry client_entry,
57                                           SilcMessageFlags flags,
58                                           SilcHash hash,
59                                           unsigned char *data,
60                                           SilcUInt32 data_len)
61 {
62   SilcClientPrvmsgContext p;
63   SilcID sid, rid;
64
65   if (silc_unlikely(!client || !conn || !client_entry))
66     return FALSE;
67   if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash)) {
68     SILC_LOG_ERROR(("Cannot send signed message without hash, missing "
69                     "arguments"));
70     return FALSE;
71   }
72   if (silc_unlikely(conn->internal->disconnected))
73     return FALSE;
74
75   SILC_LOG_DEBUG(("Sending private message"));
76
77   sid.type = SILC_ID_CLIENT;
78   sid.u.client_id = conn->local_entry->id;
79   rid.type = SILC_ID_CLIENT;
80   rid.u.client_id = client_entry->id;
81
82   p = silc_calloc(1, sizeof(*p));
83   if (!p)
84     return FALSE;
85
86   p->client = client;
87   p->conn = conn;
88   p->client_entry = silc_client_ref_client(client, conn, client_entry);
89
90   /* Encode private message payload */
91   silc_message_payload_encode(flags, data, data_len,
92                               (!client_entry->internal.send_key ? FALSE :
93                                !client_entry->internal.generated),
94                               TRUE, client_entry->internal.send_key,
95                               client_entry->internal.hmac_send,
96                               client->rng, NULL, conn->private_key,
97                               hash, &sid, &rid, NULL,
98                               silc_client_send_private_message_final, p);
99
100   return TRUE;
101 }
102
103 /************************* Private Message Receive **************************/
104
105 /* Client resolving callback.  Continues with the private message processing */
106
107 static void silc_client_private_message_resolved(SilcClient client,
108                                                  SilcClientConnection conn,
109                                                  SilcStatus status,
110                                                  SilcDList clients,
111                                                  void *context)
112 {
113   /* If no client found, ignore the private message, a silent error */
114   if (!clients)
115     silc_fsm_next(context, silc_client_private_message_error);
116
117   /* Continue processing the private message packet */
118   SILC_FSM_CALL_CONTINUE(context);
119 }
120
121 /* Private message received. */
122
123 SILC_FSM_STATE(silc_client_private_message)
124 {
125   SilcClientConnection conn = fsm_context;
126   SilcClient client = conn->client;
127   SilcPacket packet = state_context;
128   SilcMessagePayload payload = NULL;
129   SilcClientID remote_id;
130   SilcClientEntry remote_client = NULL;
131   SilcMessageFlags flags;
132   unsigned char *message;
133   SilcUInt32 message_len;
134
135   SILC_LOG_DEBUG(("Received private message"));
136
137   if (silc_unlikely(packet->src_id_type != SILC_ID_CLIENT)) {
138     /** Invalid packet */
139     silc_fsm_next(fsm, silc_client_private_message_error);
140     return SILC_FSM_CONTINUE;
141   }
142
143   if (silc_unlikely(!silc_id_str2id(packet->src_id, packet->src_id_len,
144                                     SILC_ID_CLIENT, &remote_id,
145                                     sizeof(remote_id)))) {
146     /** Invalid source ID */
147     silc_fsm_next(fsm, silc_client_private_message_error);
148     return SILC_FSM_CONTINUE;
149   }
150
151   /* Check whether we know this client already */
152   remote_client = silc_client_get_client_by_id(client, conn, &remote_id);
153   if (!remote_client || !remote_client->nickname[0]) {
154     /** Resolve client info */
155     silc_client_unref_client(client, conn, remote_client);
156     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
157                                          client, conn, &remote_id, NULL,
158                                          silc_client_private_message_resolved,
159                                          fsm));
160     /* NOT REACHED */
161   }
162
163   if (silc_unlikely(packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY &&
164                     !remote_client->internal.receive_key &&
165                     !remote_client->internal.hmac_receive))
166     goto out;
167
168   /* Parse the payload and decrypt it also if private message key is set */
169   payload =
170     silc_message_payload_parse(silc_buffer_datalen(&packet->buffer),
171                                TRUE, !remote_client->internal.generated,
172                                remote_client->internal.receive_key,
173                                remote_client->internal.hmac_receive,
174                                packet->src_id, packet->src_id_len,
175                                packet->dst_id, packet->dst_id_len,
176                                NULL, FALSE, NULL);
177   if (silc_unlikely(!payload))
178     goto out;
179
180   /* Pass the private message to application */
181   flags = silc_message_get_flags(payload);
182   message = silc_message_get_data(payload, &message_len);
183   client->internal->ops->private_message(client, conn, remote_client, payload,
184                                          flags, message, message_len);
185
186   /* See if we are away (gone). If we are away we will reply to the
187      sender with the set away message. */
188   if (conn->internal->away_message &&
189       !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
190     /* If it's me, ignore */
191     if (SILC_ID_CLIENT_COMPARE(&remote_id, conn->local_id))
192       goto out;
193
194     /* Send the away message */
195     silc_client_send_private_message(client, conn, remote_client,
196                                      SILC_MESSAGE_FLAG_AUTOREPLY |
197                                      SILC_MESSAGE_FLAG_NOREPLY, NULL,
198                                      conn->internal->away_message,
199                                      strlen(conn->internal->away_message));
200   }
201
202  out:
203   /** Packet processed */
204   silc_packet_free(packet);
205   silc_client_unref_client(client, conn, remote_client);
206   if (payload)
207     silc_message_payload_free(payload);
208   return SILC_FSM_FINISH;
209 }
210
211 /* Private message error. */
212
213 SILC_FSM_STATE(silc_client_private_message_error)
214 {
215   SilcPacket packet = state_context;
216   silc_packet_free(packet);
217   return SILC_FSM_FINISH;
218 }
219
220 /* Initialize private message waiter for the `conn' connection. */
221
222 SilcBool silc_client_private_message_wait_init(SilcClient client,
223                                                SilcClientConnection conn,
224                                                SilcClientEntry client_entry)
225 {
226   SilcID id;
227
228   if (client_entry->internal.prv_waiter)
229     return TRUE;
230
231   /* We want SILC_PACKET_PRIVATE_MESSAGE packets from this source ID. */
232   id.type = SILC_ID_CLIENT;
233   id.u.client_id = client_entry->id;
234
235   client_entry->internal.prv_waiter =
236     silc_packet_wait_init(conn->stream, &id, SILC_PACKET_PRIVATE_MESSAGE, -1);
237   if (!client_entry->internal.prv_waiter)
238     return FALSE;
239
240   return TRUE;
241 }
242
243 /* Uninitializes private message waiter. */
244
245 void silc_client_private_message_wait_uninit(SilcClient client,
246                                              SilcClientConnection conn,
247                                              SilcClientEntry client_entry)
248 {
249   if (!client_entry->internal.prv_waiter)
250     return;
251   silc_packet_wait_uninit(client_entry->internal.prv_waiter, conn->stream);
252   client_entry->internal.prv_waiter = NULL;
253 }
254
255 /* Blocks the calling process or thread until private message has been
256    received from the specified client. */
257
258 SilcBool silc_client_private_message_wait(SilcClient client,
259                                           SilcClientConnection conn,
260                                           SilcClientEntry client_entry,
261                                           SilcMessagePayload *payload)
262 {
263   SilcPacket packet;
264
265   if (!client_entry->internal.prv_waiter)
266     return FALSE;
267
268   /* Block until private message arrives */
269   do {
270     if ((silc_packet_wait(client_entry->internal.prv_waiter, 0, &packet)) < 0)
271       return FALSE;
272
273     /* Parse the payload and decrypt it also if private message key is set */
274     *payload =
275       silc_message_payload_parse(silc_buffer_data(&packet->buffer),
276                                  silc_buffer_len(&packet->buffer),
277                                  TRUE, !client_entry->internal.generated,
278                                  client_entry->internal.receive_key,
279                                  client_entry->internal.hmac_receive,
280                                  packet->src_id, packet->src_id_len,
281                                  packet->dst_id, packet->dst_id_len,
282                                  NULL, FALSE, NULL);
283     if (!(*payload)) {
284       silc_packet_free(packet);
285       continue;
286     }
287
288     break;
289   } while (1);
290
291   silc_packet_free(packet);
292   return TRUE;
293 }
294
295 /*************************** Private Message Key ****************************/
296
297 /* Sends private message key request.  Sender of this packet is initiator
298    when setting the private message key. */
299
300 static SilcBool
301 silc_client_send_private_message_key_request(SilcClient client,
302                                              SilcClientConnection conn,
303                                              SilcClientEntry client_entry)
304 {
305   const char *cipher, *hmac;
306
307   SILC_LOG_DEBUG(("Sending private message key request"));
308
309   cipher = silc_cipher_get_name(client_entry->internal.send_key);
310   hmac = silc_hmac_get_name(client_entry->internal.hmac_send);
311
312   /* Send the packet */
313   return silc_packet_send_va_ext(conn->stream,
314                                  SILC_PACKET_PRIVATE_MESSAGE_KEY,
315                                  0, 0, NULL, SILC_ID_CLIENT,
316                                  &client_entry->id, NULL, NULL,
317                                  SILC_STR_UI_SHORT(strlen(cipher)),
318                                  SILC_STR_DATA(cipher, strlen(cipher)),
319                                  SILC_STR_UI_SHORT(strlen(hmac)),
320                                  SILC_STR_DATA(hmac, strlen(hmac)),
321                                  SILC_STR_END);
322 }
323
324 /* Client resolving callback.  Here we simply mark that we are the responder
325    side of this private message key request.  */
326
327 static void silc_client_private_message_key_cb(SilcClient client,
328                                                SilcClientConnection conn,
329                                                SilcStatus status,
330                                                SilcDList clients,
331                                                void *context)
332 {
333   SilcFSMThread thread = context;
334   SilcPacket packet = silc_fsm_get_state_context(thread);
335   unsigned char *cipher = NULL, *hmac = NULL;
336   SilcClientEntry client_entry;
337   int ret;
338
339   if (!clients) {
340     silc_packet_free(packet);
341     silc_fsm_finish(thread);
342     return;
343   }
344
345   /* Parse the private message key payload */
346   ret = silc_buffer_unformat(&packet->buffer,
347                              SILC_STR_UI16_STRING_ALLOC(&cipher),
348                              SILC_STR_UI16_STRING_ALLOC(&hmac),
349                              SILC_STR_END);
350   if (!ret)
351     goto out;
352
353   /* Mark that we are responder */
354   client_entry = silc_dlist_get(clients);
355   client_entry->internal.prv_resp = TRUE;
356
357   /* XXX we should notify application that remote wants to set up the
358      static key.  And we should tell if we already have key with remote.
359      Application should return status telling whether to delete the key
360      or not. */
361
362  out:
363   silc_free(cipher);
364   silc_free(hmac);
365   silc_packet_free(packet);
366   silc_fsm_finish(thread);
367 }
368
369 /* Processes incoming Private Message Key payload to indicate that the
370    sender whishes to set up a static private message key. */
371
372 SILC_FSM_STATE(silc_client_private_message_key)
373 {
374   SilcClientConnection conn = fsm_context;
375   SilcClient client = conn->client;
376   SilcPacket packet = state_context;
377   SilcClientID remote_id;
378
379   if (packet->src_id_type != SILC_ID_CLIENT) {
380     silc_packet_free(packet);
381     return SILC_FSM_FINISH;
382   }
383
384   if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
385                       &remote_id, sizeof(remote_id))) {
386     silc_packet_free(packet);
387     return SILC_FSM_FINISH;
388   }
389
390   /* Always resolve the remote client.  The actual packet is processed
391      in the resolving callback. */
392   SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
393                                        client, conn, &remote_id, NULL,
394                                        silc_client_private_message_key_cb,
395                                        fsm));
396 }
397
398 /* Adds new private message key to `client_entry'.  If we are setting this
399    before receiving request for it from `client_entry' we will send the
400    request to the client.  Otherwise, we are responder side. */
401
402 SilcBool silc_client_add_private_message_key(SilcClient client,
403                                              SilcClientConnection conn,
404                                              SilcClientEntry client_entry,
405                                              const char *cipher,
406                                              const char *hmac,
407                                              unsigned char *key,
408                                              SilcUInt32 key_len)
409 {
410   SilcSKEKeyMaterial keymat;
411   SilcBool ret;
412
413   if (!client || !client_entry)
414     return FALSE;
415
416   /* Return FALSE if key already set */
417   if (client_entry->internal.send_key && client_entry->internal.receive_key)
418     return FALSE;
419
420   if (!cipher)
421     cipher = SILC_DEFAULT_CIPHER;
422   if (!hmac)
423     hmac = SILC_DEFAULT_HMAC;
424
425   /* Check the requested cipher and HMAC */
426   if (!silc_cipher_is_supported(cipher))
427     return FALSE;
428   if (!silc_hmac_is_supported(hmac))
429     return FALSE;
430
431   /* Save the key */
432   client_entry->internal.key = silc_memdup(key, key_len);
433   client_entry->internal.key_len = key_len;
434
435   /* Produce the key material as the protocol defines */
436   keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
437                                               conn->internal->sha1hash);
438   if (!keymat)
439     return FALSE;
440
441   /* Set the key into use */
442   ret = silc_client_add_private_message_key_ske(client, conn, client_entry,
443                                                 cipher, hmac, keymat);
444   client_entry->internal.generated = FALSE;
445
446   /* Free the key material */
447   silc_ske_free_key_material(keymat);
448
449   /* If we are setting the key without a request from the remote client,
450      we will send request to remote. */
451   if (!client_entry->internal.prv_resp)
452     silc_client_send_private_message_key_request(client, conn, client_entry);
453
454   return ret;
455 }
456
457 /* Same as above but takes the key material from the SKE key material
458    structure. */
459
460 SilcBool silc_client_add_private_message_key_ske(SilcClient client,
461                                                  SilcClientConnection conn,
462                                                  SilcClientEntry client_entry,
463                                                  const char *cipher,
464                                                  const char *hmac,
465                                                  SilcSKEKeyMaterial keymat)
466 {
467   if (!client || !client_entry)
468     return FALSE;
469
470   /* Return FALSE if key already set */
471   if (client_entry->internal.send_key && client_entry->internal.receive_key)
472     return FALSE;
473
474   if (!cipher)
475     cipher = SILC_DEFAULT_CIPHER;
476   if (!hmac)
477     hmac = SILC_DEFAULT_HMAC;
478
479   /* Check the requested cipher and HMAC */
480   if (!silc_cipher_is_supported(cipher))
481     return FALSE;
482   if (!silc_hmac_is_supported(hmac))
483     return FALSE;
484
485   client_entry->internal.generated = TRUE;
486
487   /* Allocate the cipher and HMAC */
488   if (!silc_cipher_alloc(cipher, &client_entry->internal.send_key))
489     return FALSE;
490   if (!silc_cipher_alloc(cipher, &client_entry->internal.receive_key))
491     return FALSE;
492   if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_send))
493     return FALSE;
494   if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_receive))
495     return FALSE;
496
497   /* Set the keys */
498   if (client_entry->internal.prv_resp) {
499     silc_cipher_set_key(client_entry->internal.send_key,
500                         keymat->receive_enc_key,
501                         keymat->enc_key_len, TRUE);
502     silc_cipher_set_iv(client_entry->internal.send_key,
503                        keymat->receive_iv);
504     silc_cipher_set_key(client_entry->internal.receive_key,
505                         keymat->send_enc_key,
506                         keymat->enc_key_len, FALSE);
507     silc_cipher_set_iv(client_entry->internal.receive_key, keymat->send_iv);
508     silc_hmac_set_key(client_entry->internal.hmac_send,
509                       keymat->receive_hmac_key,
510                       keymat->hmac_key_len);
511     silc_hmac_set_key(client_entry->internal.hmac_receive,
512                       keymat->send_hmac_key,
513                       keymat->hmac_key_len);
514   } else {
515     silc_cipher_set_key(client_entry->internal.send_key,
516                         keymat->send_enc_key,
517                         keymat->enc_key_len, TRUE);
518     silc_cipher_set_iv(client_entry->internal.send_key,
519                        keymat->send_iv);
520     silc_cipher_set_key(client_entry->internal.receive_key,
521                         keymat->receive_enc_key,
522                         keymat->enc_key_len, FALSE);
523     silc_cipher_set_iv(client_entry->internal.receive_key, keymat->receive_iv);
524     silc_hmac_set_key(client_entry->internal.hmac_send,
525                       keymat->send_hmac_key,
526                       keymat->hmac_key_len);
527     silc_hmac_set_key(client_entry->internal.hmac_receive,
528                       keymat->receive_hmac_key,
529                       keymat->hmac_key_len);
530   }
531
532   return TRUE;
533 }
534
535 /* Removes the private message from the library. The key won't be used
536    after this to protect the private messages with the remote `client_entry'
537    client. Returns FALSE on error, TRUE otherwise. */
538
539 SilcBool silc_client_del_private_message_key(SilcClient client,
540                                              SilcClientConnection conn,
541                                              SilcClientEntry client_entry)
542 {
543   if (!client || !client_entry)
544     return FALSE;
545
546   if (!client_entry->internal.send_key && !client_entry->internal.receive_key)
547     return FALSE;
548
549   silc_cipher_free(client_entry->internal.send_key);
550   silc_cipher_free(client_entry->internal.receive_key);
551
552   if (client_entry->internal.key) {
553     memset(client_entry->internal.key, 0, client_entry->internal.key_len);
554     silc_free(client_entry->internal.key);
555   }
556
557   client_entry->internal.send_key = NULL;
558   client_entry->internal.receive_key = NULL;
559   client_entry->internal.key = NULL;
560   client_entry->internal.prv_resp = FALSE;
561
562   return TRUE;
563 }
564
565 /* Returns array of set private message keys associated to the connection
566    `conn'. Returns allocated SilcPrivateMessageKeys array and the array
567    count to the `key_count' argument. The array must be freed by the caller
568    by calling the silc_client_free_private_message_keys function. Note:
569    the keys returned in the array is in raw format. It might not be desired
570    to show the keys as is. The application might choose not to show the keys
571    at all or to show the fingerprints of the keys. */
572
573 SilcPrivateMessageKeys
574 silc_client_list_private_message_keys(SilcClient client,
575                                       SilcClientConnection conn,
576                                       SilcUInt32 *key_count)
577 {
578   SilcPrivateMessageKeys keys;
579   SilcUInt32 count = 0;
580   SilcList list;
581   SilcIDCacheEntry id_cache;
582   SilcClientEntry entry;
583
584   if (!client || !conn)
585     return NULL;
586
587   silc_mutex_lock(conn->internal->lock);
588   if (!silc_idcache_get_all(conn->internal->client_cache, &list)) {
589     silc_mutex_unlock(conn->internal->lock);
590     return NULL;
591   }
592
593   keys = silc_calloc(silc_list_count(list), sizeof(*keys));
594   if (!keys) {
595     silc_mutex_unlock(conn->internal->lock);
596     return NULL;
597   }
598
599   silc_list_start(list);
600   while ((id_cache = silc_list_get(list))) {
601     entry = id_cache->context;
602     if (entry->internal.send_key) {
603       keys[count].client_entry = entry;
604       keys[count].cipher = (char *)silc_cipher_get_name(entry->internal.
605                                                         send_key);
606       keys[count].key = (entry->internal.generated == FALSE ?
607                          entry->internal.key : NULL);
608       keys[count].key_len = (entry->internal.generated == FALSE ?
609                              entry->internal.key_len : 0);
610       count++;
611     }
612   }
613
614   silc_mutex_unlock(conn->internal->lock);
615
616   if (key_count)
617     *key_count = count;
618
619   return keys;
620 }
621
622 /* Frees the SilcPrivateMessageKeys array returned by the function
623    silc_client_list_private_message_keys. */
624
625 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
626                                            SilcUInt32 key_count)
627 {
628   silc_free(keys);
629 }
630
631 /* Return private message key from the client entry. */
632
633 SilcBool
634 silc_client_private_message_key_is_set(SilcClient client,
635                                        SilcClientConnection conn,
636                                        SilcClientEntry client_entry)
637 {
638   return client_entry->internal.send_key != NULL;
639 }
640
641 /* Sets away `message'.  The away message may be set when the client's
642    mode is changed to SILC_UMODE_GONE and the client whishes to reply
643    to anyone who sends private message.  The `message' will be sent
644    automatically back to the the client who send private message.  If
645    away message is already set this replaces the old message with the
646    new one.  If `message' is NULL the old away message is removed.
647    The sender may freely free the memory of the `message'. */
648
649 SilcBool silc_client_set_away_message(SilcClient client,
650                                       SilcClientConnection conn,
651                                       char *message)
652 {
653   if (!client || !conn)
654     return FALSE;
655
656   if (!message) {
657     silc_free(conn->internal->away_message);
658     conn->internal->away_message = NULL;
659     return TRUE;
660   }
661
662   if (conn->internal->away_message)
663     silc_free(conn->internal->away_message);
664
665   conn->internal->away_message = strdup(message);
666   if (!conn->internal->away_message)
667     return FALSE;
668
669   return TRUE;
670 }