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,
40 SILC_LOG_DEBUG(("Sending private message"));
42 if (!client || !conn || !client_entry)
44 if (flags & SILC_MESSAGE_FLAG_SIGNED && !hash)
47 /* Encode private message payload */
49 silc_message_payload_encode(flags, data, data_len,
50 (!client_entry->internal.send_key ? FALSE :
51 !client_entry->internal.generated),
52 TRUE, client_entry->internal.send_key,
53 client_entry->internal.hmac_send,
54 client->rng, NULL, conn->private_key,
57 SILC_LOG_ERROR(("Error encoding private message"));
61 /* Send the private message packet */
62 ret = silc_packet_send_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE,
63 client_entry->internal.send_key ?
64 SILC_PACKET_FLAG_PRIVMSG_KEY : 0,
65 0, NULL, SILC_ID_CLIENT, &client_entry->id,
66 silc_buffer_datalen(buffer), NULL, NULL);
68 silc_buffer_free(buffer);
72 /************************* Private Message Receive **************************/
74 /* Private message waiting context */
78 SilcDList message_queue;
79 unsigned int stopped : 1;
80 } *SilcClientPrivateMessageWait;
82 /* Client resolving callback. Continues with the private message processing */
84 static void silc_client_private_message_resolved(SilcClient client,
85 SilcClientConnection conn,
90 /* If no client found, ignore the private message, a silent error */
92 silc_fsm_next(context, silc_client_private_message_error);
94 /* Continue processing the private message packet */
95 SILC_FSM_CALL_CONTINUE(context);
98 /* Private message received. */
100 SILC_FSM_STATE(silc_client_private_message)
102 SilcClientConnection conn = fsm_context;
103 SilcClient client = conn->client;
104 SilcPacket packet = state_context;
105 SilcMessagePayload payload = NULL;
106 SilcClientID remote_id;
107 SilcClientEntry remote_client = NULL;
108 SilcMessageFlags flags;
109 unsigned char *message;
110 SilcUInt32 message_len;
111 SilcClientPrivateMessageWait pmw;
113 SILC_LOG_DEBUG(("Received private message"));
115 if (packet->src_id_type != SILC_ID_CLIENT) {
116 /** Invalid packet */
117 silc_fsm_next(fsm, silc_client_private_message_error);
118 return SILC_FSM_CONTINUE;
121 if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
122 &remote_id, sizeof(remote_id))) {
123 /** Invalid source ID */
124 silc_fsm_next(fsm, silc_client_private_message_error);
125 return SILC_FSM_CONTINUE;
128 /* Check whether we know this client already */
129 remote_client = silc_client_get_client_by_id(client, conn, &remote_id);
130 if (!remote_client || !remote_client->nickname[0]) {
131 /** Resolve client info */
132 silc_client_unref_client(client, conn, remote_client);
133 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
134 client, conn, &remote_id, NULL,
135 silc_client_private_message_resolved,
140 if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY &&
141 !remote_client->internal.receive_key &&
142 !remote_client->internal.hmac_receive)
145 /* Parse the payload and decrypt it also if private message key is set */
147 silc_message_payload_parse(silc_buffer_datalen(&packet->buffer),
148 TRUE, !remote_client->internal.generated,
149 remote_client->internal.receive_key,
150 remote_client->internal.hmac_receive,
155 #if 0 /* We need to rethink this. This doesn't work with multiple
156 waiters, and performance is suboptimal. */
157 /* Check if some thread is waiting for this private message */
158 silc_mutex_lock(conn->internal->lock);
159 if (conn->internal->privmsg_wait &&
160 silc_hash_table_find_ext(conn->internal->privmsg_wait,
161 &remote_client->id, NULL, (void **)&pmw,
162 NULL, NULL, silc_hash_id_compare_full,
163 SILC_32_TO_PTR(SILC_ID_CLIENT))) {
164 /* Signal that message was received */
165 silc_mutex_unlock(conn->internal->lock);
166 silc_mutex_lock(pmw->wait_lock);
168 silc_dlist_add(pmw->message_queue, payload);
169 silc_cond_broadcast(pmw->wait_cond);
170 silc_mutex_unlock(pmw->wait_lock);
171 silc_packet_free(packet);
174 silc_mutex_unlock(pmw->wait_lock);
176 silc_mutex_unlock(conn->internal->lock);
179 /* Pass the private message to application */
180 flags = silc_message_get_flags(payload);
181 message = silc_message_get_data(payload, &message_len);
182 client->internal->ops->private_message(client, conn, remote_client, payload,
183 flags, message, message_len);
185 /* See if we are away (gone). If we are away we will reply to the
186 sender with the set away message. */
187 if (conn->internal->away && conn->internal->away->away &&
188 !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
189 /* If it's me, ignore */
190 if (SILC_ID_CLIENT_COMPARE(&remote_id, conn->local_id))
193 /* Send the away message */
194 silc_client_send_private_message(client, conn, remote_client,
195 SILC_MESSAGE_FLAG_AUTOREPLY |
196 SILC_MESSAGE_FLAG_NOREPLY, NULL,
197 conn->internal->away->away,
198 strlen(conn->internal->away->away));
202 /** Packet processed */
203 silc_packet_free(packet);
204 silc_client_unref_client(client, conn, remote_client);
206 silc_message_payload_free(payload);
207 return SILC_FSM_FINISH;
210 /* Private message error. */
212 SILC_FSM_STATE(silc_client_private_message_error)
214 SilcPacket packet = state_context;
215 silc_packet_free(packet);
216 return SILC_FSM_FINISH;
219 #if 0 /* XXX we need to rethink this */
220 /* Initialize private message waiting in a thread. */
222 void *silc_client_private_message_wait_init(SilcClientConnection conn,
223 SilcClientEntry client_entry)
225 SilcClientPrivateMessageWait pmw;
227 pmw = silc_calloc(1, sizeof(*pmw));
231 pmw->message_queue = silc_dlist_init();
232 if (!pmw->message_queue) {
237 /* Allocate mutex and conditional variable */
238 if (!silc_mutex_alloc(&pmw->wait_lock)) {
239 silc_dlist_uninit(pmw->message_queue);
243 if (!silc_cond_alloc(&pmw->wait_cond)) {
244 silc_dlist_uninit(pmw->message_queue);
245 silc_mutex_free(pmw->wait_lock);
250 silc_mutex_lock(conn->internal->lock);
252 /* Allocate waiting hash table */
253 if (!conn->internal->privmsg_wait) {
254 conn->internal->privmsg_wait =
255 silc_hash_table_alloc(0, silc_hash_id,
256 SILC_32_TO_PTR(SILC_ID_CLIENT),
257 silc_hash_id_compare,
258 SILC_32_TO_PTR(SILC_ID_CLIENT), NULL, NULL, TRUE);
259 if (!conn->internal->privmsg_wait) {
260 silc_mutex_unlock(conn->internal->lock);
261 silc_dlist_uninit(pmw->message_queue);
262 silc_mutex_free(pmw->wait_lock);
263 silc_cond_free(pmw->wait_cond);
269 /* Add to waiting hash table */
270 silc_hash_table_add(conn->internal->privmsg_wait, client_entry->id, pmw);
272 silc_mutex_unlock(conn->internal->lock);
277 /* Uninitialize private message waiting. */
279 void silc_client_private_message_wait_uninit(SilcClientConnection conn,
280 SilcClientEntry client_entry,
283 SilcClientPrivateMessageWait pmw = waiter;
284 SilcMessagePayload payload;
286 /* Signal any threads to stop waiting */
287 silc_mutex_lock(pmw->wait_lock);
289 silc_cond_broadcast(pmw->wait_cond);
290 silc_mutex_unlock(pmw->wait_lock);
292 /* Re-acquire lock and free resources */
293 silc_mutex_lock(pmw->wait_lock);
295 /* Free any remaining message */
296 silc_dlist_start(pmw->message_queue);
297 while ((payload = silc_dlist_get(pmw->message_queue)))
298 silc_message_payload_free(payload);
300 silc_dlist_uninit(pmw->message_queue);
301 silc_cond_free(pmw->wait_cond);
302 silc_mutex_unlock(pmw->wait_lock);
303 silc_mutex_free(pmw->wait_lock);
305 silc_mutex_lock(conn->internal->lock);
306 silc_hash_table_del_by_context(conn->internal->privmsg_wait,
307 client_entry->id, pmw);
308 silc_mutex_unlock(conn->internal->lock);
313 /* Blocks the calling process or thread until a private message has been
314 received from the specified client. */
316 SilcBool silc_client_private_message_wait(SilcClientConnection conn,
317 SilcClientEntry client_entry,
319 SilcMessagePayload *payload)
321 SilcClientPrivateMessageWait pmw = waiter;
324 silc_mutex_lock(pmw->wait_lock);
326 /* Wait here until private message has been received */
327 while (silc_dlist_count(pmw->message_queue) == 0) {
329 silc_mutex_unlock(pmw->wait_lock);
332 silc_cond_wait(pmw->wait_cond, pmw->wait_lock);
336 silc_dlist_start(pmw->message_queue);
337 *payload = silc_dlist_get(pmw->message_queue);
338 silc_dlist_del(pmw->message_queue, *payload);
340 silc_mutex_unlock(pmw->wait_lock);
346 /*************************** Private Message Key ****************************/
348 /* Client resolving callback. Here we simply mark that we are the responder
349 side of this private message key request. */
351 static void silc_client_private_message_key_cb(SilcClient client,
352 SilcClientConnection conn,
357 SilcPacket packet = context;
358 unsigned char *cipher = NULL, *hmac = NULL;
359 SilcClientEntry client_entry;
363 silc_packet_free(packet);
367 /* Parse the private message key payload */
368 ret = silc_buffer_unformat(&packet->buffer,
369 SILC_STR_UI16_STRING_ALLOC(&cipher),
370 SILC_STR_UI16_STRING_ALLOC(&hmac),
375 /* Mark that we are responder */
376 client_entry = silc_dlist_get(clients);
377 client_entry->internal.prv_resp = TRUE;
379 /* XXX we should notify application that remote wants to set up the
385 silc_packet_free(packet);
388 /* Processes incoming Private Message Key payload to indicate that the
389 sender whishes to set up a static private message key. */
391 SILC_FSM_STATE(silc_client_private_message_key)
393 SilcClientConnection conn = fsm_context;
394 SilcClient client = conn->client;
395 SilcPacket packet = state_context;
396 SilcClientID remote_id;
398 if (packet->src_id_type != SILC_ID_CLIENT) {
399 silc_packet_free(packet);
400 return SILC_FSM_FINISH;
403 if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
404 &remote_id, sizeof(remote_id))) {
405 silc_packet_free(packet);
406 return SILC_FSM_FINISH;
409 /* Always resolve the remote client. The actual packet is processed
410 in the resolving callback. */
411 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
412 client, conn, &remote_id, NULL,
413 silc_client_private_message_key_cb,
417 /* Adds private message key to the client library. The key will be used to
418 encrypt all private message between the client and the remote client
419 indicated by the `client_entry'. If the `key' is NULL and the boolean
420 value `generate_key' is TRUE the library will generate random key.
421 The `key' maybe for example pre-shared-key, passphrase or similar.
422 The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure
423 that the requirements of the SILC protocol are met. The API, however,
424 allows to allocate any cipher and HMAC.
426 If `responder' is TRUE then the sending and receiving keys will be
427 set according the client being the receiver of the private key. If
428 FALSE the client is being the sender (or negotiator) of the private
431 It is not necessary to set key for normal private message usage. If the
432 key is not set then the private messages are encrypted using normal
433 session keys. Setting the private key, however, increases the security.
435 Returns FALSE if the key is already set for the `client_entry', TRUE
438 SilcBool silc_client_add_private_message_key(SilcClient client,
439 SilcClientConnection conn,
440 SilcClientEntry client_entry,
445 SilcBool generate_key,
448 unsigned char private_key[32];
450 SilcSKEKeyMaterial keymat;
454 if (!client || !client_entry)
457 /* Return FALSE if key already set */
458 if (client_entry->internal.send_key && client_entry->internal.receive_key)
462 cipher = SILC_DEFAULT_CIPHER;
464 hmac = SILC_DEFAULT_HMAC;
466 /* Check the requested cipher and HMAC */
467 if (!silc_cipher_is_supported(cipher))
469 if (!silc_hmac_is_supported(hmac))
472 /* Generate key if not provided */
473 if (generate_key == TRUE) {
475 for (i = 0; i < len; i++)
476 private_key[i] = silc_rng_get_byte_fast(client->rng);
482 client_entry->internal.key = silc_memdup(key, key_len);
483 client_entry->internal.key_len = key_len;
485 /* Produce the key material as the protocol defines */
486 keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
487 conn->internal->sha1hash);
491 /* Set the key into use */
492 ret = silc_client_add_private_message_key_ske(client, conn, client_entry,
493 cipher, hmac, keymat,
497 client_entry->internal.generated = FALSE;
499 /* Free the key material */
500 silc_ske_free_key_material(keymat);
505 /* Same as above but takes the key material from the SKE key material
506 structure. This structure is received if the application uses the
507 silc_client_send_key_agreement to negotiate the key material. The
508 `cipher' and `hmac' SHOULD be provided as it is negotiated also in
511 SilcBool silc_client_add_private_message_key_ske(SilcClient client,
512 SilcClientConnection conn,
513 SilcClientEntry client_entry,
516 SilcSKEKeyMaterial keymat,
519 if (!client || !client_entry)
522 /* Return FALSE if key already set */
523 if (client_entry->internal.send_key && client_entry->internal.receive_key)
527 cipher = SILC_DEFAULT_CIPHER;
529 hmac = SILC_DEFAULT_HMAC;
531 /* Check the requested cipher and HMAC */
532 if (!silc_cipher_is_supported(cipher))
534 if (!silc_hmac_is_supported(hmac))
537 client_entry->internal.generated = TRUE;
539 /* Allocate the cipher and HMAC */
540 if (!silc_cipher_alloc(cipher, &client_entry->internal.send_key))
542 if (!silc_cipher_alloc(cipher, &client_entry->internal.receive_key))
544 if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_send))
546 if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_receive))
550 if (responder == TRUE) {
551 silc_cipher_set_key(client_entry->internal.send_key,
552 keymat->receive_enc_key,
553 keymat->enc_key_len);
554 silc_cipher_set_iv(client_entry->internal.send_key,
556 silc_cipher_set_key(client_entry->internal.receive_key,
557 keymat->send_enc_key,
558 keymat->enc_key_len);
559 silc_cipher_set_iv(client_entry->internal.receive_key, keymat->send_iv);
560 silc_hmac_set_key(client_entry->internal.hmac_send,
561 keymat->receive_hmac_key,
562 keymat->hmac_key_len);
563 silc_hmac_set_key(client_entry->internal.hmac_receive,
564 keymat->send_hmac_key,
565 keymat->hmac_key_len);
567 silc_cipher_set_key(client_entry->internal.send_key,
568 keymat->send_enc_key,
569 keymat->enc_key_len);
570 silc_cipher_set_iv(client_entry->internal.send_key,
572 silc_cipher_set_key(client_entry->internal.receive_key,
573 keymat->receive_enc_key,
574 keymat->enc_key_len);
575 silc_cipher_set_iv(client_entry->internal.receive_key, keymat->receive_iv);
576 silc_hmac_set_key(client_entry->internal.hmac_send,
577 keymat->send_hmac_key,
578 keymat->hmac_key_len);
579 silc_hmac_set_key(client_entry->internal.hmac_receive,
580 keymat->receive_hmac_key,
581 keymat->hmac_key_len);
587 /* Sends private message key indicator. The sender of this packet is
588 going to be the initiator, if and when, the users set up a static
589 private message key (not Key Agreement). */
592 silc_client_send_private_message_key_request(SilcClient client,
593 SilcClientConnection conn,
594 SilcClientEntry client_entry)
596 const char *cipher, *hmac;
598 if (!client || !conn || !client_entry)
601 if (!client_entry->internal.send_key && !client_entry->internal.receive_key)
604 SILC_LOG_DEBUG(("Sending private message key indicator"));
606 cipher = silc_cipher_get_name(client_entry->internal.send_key);
607 hmac = silc_hmac_get_name(client_entry->internal.hmac_send);
609 /* Send the packet */
610 return silc_packet_send_va_ext(conn->stream,
611 SILC_PACKET_PRIVATE_MESSAGE_KEY,
612 0, 0, NULL, SILC_ID_CLIENT,
613 &client_entry->id, NULL, NULL,
614 SILC_STR_UI_SHORT(strlen(cipher)),
615 SILC_STR_DATA(cipher, strlen(cipher)),
616 SILC_STR_UI_SHORT(strlen(hmac)),
617 SILC_STR_DATA(hmac, strlen(hmac)),
621 /* Removes the private message from the library. The key won't be used
622 after this to protect the private messages with the remote `client_entry'
623 client. Returns FALSE on error, TRUE otherwise. */
625 SilcBool silc_client_del_private_message_key(SilcClient client,
626 SilcClientConnection conn,
627 SilcClientEntry client_entry)
629 if (!client || !client_entry)
632 if (!client_entry->internal.send_key && !client_entry->internal.receive_key)
635 silc_cipher_free(client_entry->internal.send_key);
636 silc_cipher_free(client_entry->internal.receive_key);
638 if (client_entry->internal.key) {
639 memset(client_entry->internal.key, 0, client_entry->internal.key_len);
640 silc_free(client_entry->internal.key);
643 client_entry->internal.send_key = NULL;
644 client_entry->internal.receive_key = NULL;
645 client_entry->internal.key = NULL;
650 /* Returns array of set private message keys associated to the connection
651 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
652 count to the `key_count' argument. The array must be freed by the caller
653 by calling the silc_client_free_private_message_keys function. Note:
654 the keys returned in the array is in raw format. It might not be desired
655 to show the keys as is. The application might choose not to show the keys
656 at all or to show the fingerprints of the keys. */
658 SilcPrivateMessageKeys
659 silc_client_list_private_message_keys(SilcClient client,
660 SilcClientConnection conn,
661 SilcUInt32 *key_count)
663 SilcPrivateMessageKeys keys;
664 SilcUInt32 count = 0;
666 SilcIDCacheEntry id_cache;
667 SilcClientEntry entry;
669 if (!client || !conn)
672 silc_mutex_lock(conn->internal->lock);
673 if (!silc_idcache_get_all(conn->internal->client_cache, &list)) {
674 silc_mutex_unlock(conn->internal->lock);
678 keys = silc_calloc(silc_list_count(list), sizeof(*keys));
680 silc_mutex_unlock(conn->internal->lock);
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);
699 silc_mutex_unlock(conn->internal->lock);
707 /* Frees the SilcPrivateMessageKeys array returned by the function
708 silc_client_list_private_message_keys. */
710 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
711 SilcUInt32 key_count)
716 /* Sets away `message'. The away message may be set when the client's
717 mode is changed to SILC_UMODE_GONE and the client whishes to reply
718 to anyone who sends private message. The `message' will be sent
719 automatically back to the the client who send private message. If
720 away message is already set this replaces the old message with the
721 new one. If `message' is NULL the old away message is removed.
722 The sender may freely free the memory of the `message'. */
724 void silc_client_set_away_message(SilcClient client,
725 SilcClientConnection conn,
728 assert(client && conn);
730 if (!message && conn->internal->away) {
731 silc_free(conn->internal->away->away);
732 silc_free(conn->internal->away);
733 conn->internal->away = NULL;
737 if (!conn->internal->away)
738 conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
739 if (conn->internal->away->away)
740 silc_free(conn->internal->away->away);
741 conn->internal->away->away = strdup(message);