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