5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 Pekka Riikonen
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.
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.
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /************************** Private Message Send ****************************/
27 /* Sends private message to remote client. */
29 SilcBool silc_client_send_private_message(SilcClient client,
30 SilcClientConnection conn,
31 SilcClientEntry client_entry,
32 SilcMessageFlags flags,
39 SILC_LOG_DEBUG(("Sending private message"));
41 if (!client || !conn || !client_entry)
44 /* Encode private message payload */
46 silc_message_payload_encode(flags, data, data_len,
47 (!client_entry->internal.send_key ? FALSE :
48 !client_entry->internal.generated),
49 TRUE, client_entry->internal.send_key,
50 client_entry->internal.hmac_send,
51 client->rng, NULL, conn->private_key,
52 client->sha1hash, NULL);
54 SILC_LOG_ERROR(("Error encoding private message"));
58 /* Send the private message packet */
59 ret = silc_packet_send_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE,
60 client_entry->internal.send_key ?
61 SILC_PACKET_FLAG_PRIVMSG_KEY : 0,
62 0, NULL, SILC_ID_CLIENT, &client_entry->id,
63 silc_buffer_datalen(buffer), NULL, NULL);
65 silc_buffer_free(buffer);
69 /************************* Private Message Receive **************************/
71 /* Private message waiting context */
75 SilcDList message_queue;
76 unsigned int stopped : 1;
77 } *SilcClientPrivateMessageWait;
79 /* Client resolving callback. This continues the private message packet
80 processing in the packet processor thread, which is in waiting state
81 (for incoming packets) when we get here. We can safely continue in
82 the thread and then return back to waiting when we do it synchronously. */
84 static void silc_client_private_message_resolved(SilcClient client,
85 SilcClientConnection conn,
91 silc_packet_free(context);
95 /* Continue processing the private message packet */
96 silc_fsm_set_state_context(&conn->internal->packet_thread, context);
97 silc_fsm_next(&conn->internal->packet_thread, silc_client_private_message);
98 silc_fsm_continue_sync(&conn->internal->packet_thread);
101 /* Private message received. */
103 SILC_FSM_STATE(silc_client_private_message)
105 SilcClientConnection conn = fsm_context;
106 SilcClient client = conn->client;
107 SilcPacket packet = state_context;
108 SilcMessagePayload payload = NULL;
109 SilcClientID remote_id;
110 SilcClientEntry remote_client = NULL;
111 SilcMessageFlags flags;
112 unsigned char *message;
113 SilcUInt32 message_len;
114 SilcClientPrivateMessageWait pmw;
116 if (packet->src_id_type != SILC_ID_CLIENT)
119 if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
120 &remote_id, sizeof(remote_id)))
123 /* Check whether we know this client already */
124 remote_client = silc_client_get_client_by_id(client, conn, &remote_id);
125 if (!remote_client || !remote_client->nickname[0]) {
126 /* Resolve the client info. We return back to packet thread to receive
127 other packets while we wait for the resolving to finish. */
128 silc_client_unref_client(client, conn, remote_client);
129 silc_client_get_client_by_id_resolve(client, conn, &remote_id, NULL,
130 silc_client_private_message_resolved,
132 silc_fsm_next(fsm, silc_client_connection_st_packet);
133 return SILC_FSM_CONTINUE;
136 if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY &&
137 !remote_client->internal.receive_key &&
138 !remote_client->internal.hmac_receive)
141 /* Parse the payload and decrypt it also if private message key is set */
143 silc_message_payload_parse(silc_buffer_datalen(&packet->buffer),
144 TRUE, !remote_client->internal.generated,
145 remote_client->internal.receive_key,
146 remote_client->internal.hmac_receive,
151 #if 0 /* We need to rethink this. This doesn't work with multiple
152 waiters, and performance is suboptimal. */
153 /* Check if some thread is waiting for this private message */
154 silc_mutex_lock(conn->internal->lock);
155 if (conn->internal->privmsg_wait &&
156 silc_hash_table_find_ext(conn->internal->privmsg_wait,
157 &remote_client->id, NULL, (void **)&pmw,
158 NULL, NULL, silc_hash_id_compare_full,
159 SILC_32_TO_PTR(SILC_ID_CLIENT))) {
160 /* Signal that message was received */
161 silc_mutex_unlock(conn->internal->lock);
162 silc_mutex_lock(pmw->wait_lock);
164 silc_dlist_add(pmw->message_queue, payload);
165 silc_cond_broadcast(pmw->wait_cond);
166 silc_mutex_unlock(pmw->wait_lock);
167 silc_packet_free(packet);
170 silc_mutex_unlock(pmw->wait_lock);
172 silc_mutex_unlock(conn->internal->lock);
175 /* Pass the private message to application */
176 flags = silc_message_get_flags(payload);
177 message = silc_message_get_data(payload, &message_len);
178 client->internal->ops->private_message(client, conn, remote_client, payload,
179 flags, message, message_len);
181 /* See if we are away (gone). If we are away we will reply to the
182 sender with the set away message. */
183 if (conn->internal->away && conn->internal->away->away &&
184 !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
185 /* If it's me, ignore */
186 if (SILC_ID_CLIENT_COMPARE(&remote_id, conn->local_id))
189 /* Send the away message */
190 silc_client_send_private_message(client, conn, remote_client,
191 SILC_MESSAGE_FLAG_AUTOREPLY |
192 SILC_MESSAGE_FLAG_NOREPLY,
193 conn->internal->away->away,
194 strlen(conn->internal->away->away));
198 /** Packet processed */
199 silc_client_unref_client(client, conn, remote_client);
201 silc_message_payload_free(payload);
202 silc_packet_free(packet);
203 silc_fsm_next(fsm, silc_client_connection_st_packet);
204 return SILC_FSM_CONTINUE;
207 #if 0 /* XXX we need to rethink this */
208 /* Initialize private message waiting in a thread. */
210 void *silc_client_private_message_wait_init(SilcClientConnection conn,
211 SilcClientEntry client_entry)
213 SilcClientPrivateMessageWait pmw;
215 pmw = silc_calloc(1, sizeof(*pmw));
219 pmw->message_queue = silc_dlist_init();
220 if (!pmw->message_queue) {
225 /* Allocate mutex and conditional variable */
226 if (!silc_mutex_alloc(&pmw->wait_lock)) {
227 silc_dlist_uninit(pmw->message_queue);
231 if (!silc_cond_alloc(&pmw->wait_cond)) {
232 silc_dlist_uninit(pmw->message_queue);
233 silc_mutex_free(pmw->wait_lock);
238 silc_mutex_lock(conn->internal->lock);
240 /* Allocate waiting hash table */
241 if (!conn->internal->privmsg_wait) {
242 conn->internal->privmsg_wait =
243 silc_hash_table_alloc(0, silc_hash_id,
244 SILC_32_TO_PTR(SILC_ID_CLIENT),
245 silc_hash_id_compare,
246 SILC_32_TO_PTR(SILC_ID_CLIENT), NULL, NULL, TRUE);
247 if (!conn->internal->privmsg_wait) {
248 silc_mutex_unlock(conn->internal->lock);
249 silc_dlist_uninit(pmw->message_queue);
250 silc_mutex_free(pmw->wait_lock);
251 silc_cond_free(pmw->wait_cond);
257 /* Add to waiting hash table */
258 silc_hash_table_add(conn->internal->privmsg_wait, client_entry->id, pmw);
260 silc_mutex_unlock(conn->internal->lock);
265 /* Uninitialize private message waiting. */
267 void silc_client_private_message_wait_uninit(SilcClientConnection conn,
268 SilcClientEntry client_entry,
271 SilcClientPrivateMessageWait pmw = waiter;
272 SilcMessagePayload payload;
274 /* Signal any threads to stop waiting */
275 silc_mutex_lock(pmw->wait_lock);
277 silc_cond_broadcast(pmw->wait_cond);
278 silc_mutex_unlock(pmw->wait_lock);
280 /* Re-acquire lock and free resources */
281 silc_mutex_lock(pmw->wait_lock);
283 /* Free any remaining message */
284 silc_dlist_start(pmw->message_queue);
285 while ((payload = silc_dlist_get(pmw->message_queue)))
286 silc_message_payload_free(payload);
288 silc_dlist_uninit(pmw->message_queue);
289 silc_cond_free(pmw->wait_cond);
290 silc_mutex_unlock(pmw->wait_lock);
291 silc_mutex_free(pmw->wait_lock);
293 silc_mutex_lock(conn->internal->lock);
294 silc_hash_table_del_by_context(conn->internal->privmsg_wait,
295 client_entry->id, pmw);
296 silc_mutex_unlock(conn->internal->lock);
301 /* Blocks the calling process or thread until a private message has been
302 received from the specified client. */
304 SilcBool silc_client_private_message_wait(SilcClientConnection conn,
305 SilcClientEntry client_entry,
307 SilcMessagePayload *payload)
309 SilcClientPrivateMessageWait pmw = waiter;
312 silc_mutex_lock(pmw->wait_lock);
314 /* Wait here until private message has been received */
315 while (silc_dlist_count(pmw->message_queue) == 0) {
317 silc_mutex_unlock(pmw->wait_lock);
320 silc_cond_wait(pmw->wait_cond, pmw->wait_lock);
324 silc_dlist_start(pmw->message_queue);
325 *payload = silc_dlist_get(pmw->message_queue);
326 silc_dlist_del(pmw->message_queue, *payload);
328 silc_mutex_unlock(pmw->wait_lock);
334 /*************************** Private Message Key ****************************/
336 /* Client resolving callback. Here we simply mark that we are the responder
337 side of this private message key request. */
339 static void silc_client_private_message_key_cb(SilcClient client,
340 SilcClientConnection conn,
345 SilcPacket packet = context;
346 unsigned char *cipher = NULL, *hmac = NULL;
347 SilcClientEntry client_entry;
351 silc_packet_free(packet);
355 /* Parse the private message key payload */
356 ret = silc_buffer_unformat(&packet->buffer,
357 SILC_STR_UI16_STRING_ALLOC(&cipher),
358 SILC_STR_UI16_STRING_ALLOC(&hmac),
363 /* Mark that we are responder */
364 client_entry = silc_dlist_get(clients);
365 client_entry->internal.prv_resp = TRUE;
367 /* XXX we should notify application that remote wants to set up the
373 silc_packet_free(packet);
376 /* Processes incoming Private Message Key payload to indicate that the
377 sender whishes to set up a static private message key. */
379 SILC_FSM_STATE(silc_client_private_message_key)
381 SilcClientConnection conn = fsm_context;
382 SilcClient client = conn->client;
383 SilcPacket packet = state_context;
384 SilcClientID remote_id;
386 if (packet->src_id_type != SILC_ID_CLIENT) {
387 silc_packet_free(packet);
391 if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
392 &remote_id, sizeof(remote_id))) {
393 silc_packet_free(packet);
397 /* Always resolve the remote client. The actual packet is processed
398 in the resolving callback. */
399 silc_client_get_client_by_id_resolve(client, conn, &remote_id, NULL,
400 silc_client_private_message_key_cb,
404 silc_fsm_next(fsm, silc_client_connection_st_packet);
405 return SILC_FSM_CONTINUE;
408 /* Adds private message key to the client library. The key will be used to
409 encrypt all private message between the client and the remote client
410 indicated by the `client_entry'. If the `key' is NULL and the boolean
411 value `generate_key' is TRUE the library will generate random key.
412 The `key' maybe for example pre-shared-key, passphrase or similar.
413 The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure
414 that the requirements of the SILC protocol are met. The API, however,
415 allows to allocate any cipher and HMAC.
417 If `responder' is TRUE then the sending and receiving keys will be
418 set according the client being the receiver of the private key. If
419 FALSE the client is being the sender (or negotiator) of the private
422 It is not necessary to set key for normal private message usage. If the
423 key is not set then the private messages are encrypted using normal
424 session keys. Setting the private key, however, increases the security.
426 Returns FALSE if the key is already set for the `client_entry', TRUE
429 SilcBool silc_client_add_private_message_key(SilcClient client,
430 SilcClientConnection conn,
431 SilcClientEntry client_entry,
436 SilcBool generate_key,
439 unsigned char private_key[32];
441 SilcSKEKeyMaterial keymat;
445 if (!client || !client_entry)
448 /* Return FALSE if key already set */
449 if (client_entry->internal.send_key && client_entry->internal.receive_key)
453 cipher = SILC_DEFAULT_CIPHER;
455 hmac = SILC_DEFAULT_HMAC;
457 /* Check the requested cipher and HMAC */
458 if (!silc_cipher_is_supported(cipher))
460 if (!silc_hmac_is_supported(hmac))
463 /* Generate key if not provided */
464 if (generate_key == TRUE) {
466 for (i = 0; i < len; i++)
467 private_key[i] = silc_rng_get_byte_fast(client->rng);
473 client_entry->internal.key = silc_memdup(key, key_len);
474 client_entry->internal.key_len = key_len;
476 /* Produce the key material as the protocol defines */
477 keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
482 /* Set the key into use */
483 ret = silc_client_add_private_message_key_ske(client, conn, client_entry,
484 cipher, hmac, keymat,
488 client_entry->internal.generated = FALSE;
490 /* Free the key material */
491 silc_ske_free_key_material(keymat);
496 /* Same as above but takes the key material from the SKE key material
497 structure. This structure is received if the application uses the
498 silc_client_send_key_agreement to negotiate the key material. The
499 `cipher' and `hmac' SHOULD be provided as it is negotiated also in
502 SilcBool silc_client_add_private_message_key_ske(SilcClient client,
503 SilcClientConnection conn,
504 SilcClientEntry client_entry,
507 SilcSKEKeyMaterial keymat,
510 if (!client || !client_entry)
513 /* Return FALSE if key already set */
514 if (client_entry->internal.send_key && client_entry->internal.receive_key)
518 cipher = SILC_DEFAULT_CIPHER;
520 hmac = SILC_DEFAULT_HMAC;
522 /* Check the requested cipher and HMAC */
523 if (!silc_cipher_is_supported(cipher))
525 if (!silc_hmac_is_supported(hmac))
528 client_entry->internal.generated = TRUE;
530 /* Allocate the cipher and HMAC */
531 if (!silc_cipher_alloc(cipher, &client_entry->internal.send_key))
533 if (!silc_cipher_alloc(cipher, &client_entry->internal.receive_key))
535 if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_send))
537 if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_receive))
541 if (responder == TRUE) {
542 silc_cipher_set_key(client_entry->internal.send_key,
543 keymat->receive_enc_key,
544 keymat->enc_key_len);
545 silc_cipher_set_iv(client_entry->internal.send_key,
547 silc_cipher_set_key(client_entry->internal.receive_key,
548 keymat->send_enc_key,
549 keymat->enc_key_len);
550 silc_cipher_set_iv(client_entry->internal.receive_key, keymat->send_iv);
551 silc_hmac_set_key(client_entry->internal.hmac_send,
552 keymat->receive_hmac_key,
553 keymat->hmac_key_len);
554 silc_hmac_set_key(client_entry->internal.hmac_receive,
555 keymat->send_hmac_key,
556 keymat->hmac_key_len);
558 silc_cipher_set_key(client_entry->internal.send_key,
559 keymat->send_enc_key,
560 keymat->enc_key_len);
561 silc_cipher_set_iv(client_entry->internal.send_key,
563 silc_cipher_set_key(client_entry->internal.receive_key,
564 keymat->receive_enc_key,
565 keymat->enc_key_len);
566 silc_cipher_set_iv(client_entry->internal.receive_key, keymat->receive_iv);
567 silc_hmac_set_key(client_entry->internal.hmac_send,
568 keymat->send_hmac_key,
569 keymat->hmac_key_len);
570 silc_hmac_set_key(client_entry->internal.hmac_receive,
571 keymat->receive_hmac_key,
572 keymat->hmac_key_len);
578 /* Sends private message key indicator. The sender of this packet is
579 going to be the initiator, if and when, the users set up a static
580 private message key (not Key Agreement). */
583 silc_client_send_private_message_key_request(SilcClient client,
584 SilcClientConnection conn,
585 SilcClientEntry client_entry)
587 SilcBufferStruct buffer;
588 int cipher_len, hmac_len;
589 const char *cipher, *hmac;
592 if (!client || !conn || !client_entry)
595 if (!client_entry->internal.send_key && !client_entry->internal.receive_key)
598 SILC_LOG_DEBUG(("Sending private message key indicator"));
600 cipher = silc_cipher_get_name(client_entry->internal.send_key);
601 cipher_len = strlen(cipher);
602 hmac = silc_hmac_get_name(client_entry->internal.hmac_send);
603 hmac_len = strlen(hmac);
605 /* Create private message key payload */
606 memset(&buffer, 0, sizeof(buffer));
607 if (silc_buffer_format(&buffer,
608 SILC_STR_UI_SHORT(cipher_len),
609 SILC_STR_UI_XNSTRING(cipher,
611 SILC_STR_UI_SHORT(hmac_len),
612 SILC_STR_UI_XNSTRING(hmac,
617 /* Send the packet */
618 ret = silc_packet_send_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE_KEY,
619 0, 0, NULL, SILC_ID_CLIENT, &client_entry->id,
620 silc_buffer_datalen(&buffer), NULL, NULL);
621 silc_buffer_purge(&buffer);
626 /* Removes the private message from the library. The key won't be used
627 after this to protect the private messages with the remote `client_entry'
628 client. Returns FALSE on error, TRUE otherwise. */
630 SilcBool silc_client_del_private_message_key(SilcClient client,
631 SilcClientConnection conn,
632 SilcClientEntry client_entry)
634 if (!client || !client_entry)
637 if (!client_entry->internal.send_key && !client_entry->internal.receive_key)
640 silc_cipher_free(client_entry->internal.send_key);
641 silc_cipher_free(client_entry->internal.receive_key);
643 if (client_entry->internal.key) {
644 memset(client_entry->internal.key, 0, client_entry->internal.key_len);
645 silc_free(client_entry->internal.key);
648 client_entry->internal.send_key = NULL;
649 client_entry->internal.receive_key = NULL;
650 client_entry->internal.key = NULL;
655 /* Returns array of set private message keys associated to the connection
656 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
657 count to the `key_count' argument. The array must be freed by the caller
658 by calling the silc_client_free_private_message_keys function. Note:
659 the keys returned in the array is in raw format. It might not be desired
660 to show the keys as is. The application might choose not to show the keys
661 at all or to show the fingerprints of the keys. */
663 SilcPrivateMessageKeys
664 silc_client_list_private_message_keys(SilcClient client,
665 SilcClientConnection conn,
666 SilcUInt32 *key_count)
668 SilcPrivateMessageKeys keys;
669 SilcUInt32 count = 0;
671 SilcIDCacheEntry id_cache;
672 SilcClientEntry entry;
674 if (!client || !conn)
677 if (!silc_idcache_get_all(conn->internal->client_cache, &list))
680 keys = silc_calloc(silc_list_count(list), sizeof(*keys));
684 silc_list_start(list);
685 while ((id_cache = silc_list_get(list))) {
686 entry = id_cache->context;
687 if (entry->internal.send_key) {
688 keys[count].client_entry = entry;
689 keys[count].cipher = (char *)silc_cipher_get_name(entry->internal.
691 keys[count].key = (entry->internal.generated == FALSE ?
692 entry->internal.key : NULL);
693 keys[count].key_len = (entry->internal.generated == FALSE ?
694 entry->internal.key_len : 0);
705 /* Frees the SilcPrivateMessageKeys array returned by the function
706 silc_client_list_private_message_keys. */
708 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
709 SilcUInt32 key_count)
714 /* Sets away `message'. The away message may be set when the client's
715 mode is changed to SILC_UMODE_GONE and the client whishes to reply
716 to anyone who sends private message. The `message' will be sent
717 automatically back to the the client who send private message. If
718 away message is already set this replaces the old message with the
719 new one. If `message' is NULL the old away message is removed.
720 The sender may freely free the memory of the `message'. */
722 void silc_client_set_away_message(SilcClient client,
723 SilcClientConnection conn,
726 assert(client && conn);
728 if (!message && conn->internal->away) {
729 silc_free(conn->internal->away->away);
730 silc_free(conn->internal->away);
731 conn->internal->away = NULL;
735 if (!conn->internal->away)
736 conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
737 if (conn->internal->away->away)
738 silc_free(conn->internal->away->away);
739 conn->internal->away->away = strdup(message);