5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 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,
41 if (silc_unlikely(!client || !conn || !client_entry))
43 if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash))
45 if (silc_unlikely(conn->internal->disconnected))
48 SILC_LOG_DEBUG(("Sending private message"));
50 sid.type = SILC_ID_CLIENT;
51 sid.u.client_id = conn->local_entry->id;
52 rid.type = SILC_ID_CLIENT;
53 rid.u.client_id = client_entry->id;
55 /* Encode private message payload */
57 silc_message_payload_encode(flags, data, data_len,
58 (!client_entry->internal.send_key ? FALSE :
59 !client_entry->internal.generated),
60 TRUE, client_entry->internal.send_key,
61 client_entry->internal.hmac_send,
62 client->rng, NULL, conn->private_key,
63 hash, &sid, &rid, NULL);
64 if (silc_unlikely(!buffer)) {
65 SILC_LOG_ERROR(("Error encoding private message"));
69 /* Send the private message packet */
70 ret = silc_packet_send_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE,
71 client_entry->internal.send_key ?
72 SILC_PACKET_FLAG_PRIVMSG_KEY : 0,
73 0, NULL, SILC_ID_CLIENT, &client_entry->id,
74 silc_buffer_datalen(buffer), NULL, NULL);
76 silc_buffer_free(buffer);
80 /************************* Private Message Receive **************************/
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;
112 SILC_LOG_DEBUG(("Received private message"));
114 if (silc_unlikely(packet->src_id_type != SILC_ID_CLIENT)) {
115 /** Invalid packet */
116 silc_fsm_next(fsm, silc_client_private_message_error);
117 return SILC_FSM_CONTINUE;
120 if (silc_unlikely(!silc_id_str2id(packet->src_id, packet->src_id_len,
121 SILC_ID_CLIENT, &remote_id,
122 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 (silc_unlikely(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,
151 packet->src_id, packet->src_id_len,
152 packet->dst_id, packet->dst_id_len,
154 if (silc_unlikely(!payload))
157 /* Pass the private message to application */
158 flags = silc_message_get_flags(payload);
159 message = silc_message_get_data(payload, &message_len);
160 client->internal->ops->private_message(client, conn, remote_client, payload,
161 flags, message, message_len);
163 /* See if we are away (gone). If we are away we will reply to the
164 sender with the set away message. */
165 if (conn->internal->away_message &&
166 !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
167 /* If it's me, ignore */
168 if (SILC_ID_CLIENT_COMPARE(&remote_id, conn->local_id))
171 /* Send the away message */
172 silc_client_send_private_message(client, conn, remote_client,
173 SILC_MESSAGE_FLAG_AUTOREPLY |
174 SILC_MESSAGE_FLAG_NOREPLY, NULL,
175 conn->internal->away_message,
176 strlen(conn->internal->away_message));
180 /** Packet processed */
181 silc_packet_free(packet);
182 silc_client_unref_client(client, conn, remote_client);
184 silc_message_payload_free(payload);
185 return SILC_FSM_FINISH;
188 /* Private message error. */
190 SILC_FSM_STATE(silc_client_private_message_error)
192 SilcPacket packet = state_context;
193 silc_packet_free(packet);
194 return SILC_FSM_FINISH;
197 /* Initialize private message waiter for the `conn' connection. */
199 SilcBool silc_client_private_message_wait_init(SilcClient client,
200 SilcClientConnection conn)
202 if (conn->internal->prv_waiter)
205 conn->internal->prv_waiter =
206 silc_packet_wait_init(conn->stream, SILC_PACKET_PRIVATE_MESSAGE, -1);
207 if (!conn->internal->prv_waiter)
213 /* Uninitializes private message waiter. */
215 void silc_client_private_message_wait_uninit(SilcClient client,
216 SilcClientConnection conn)
218 if (!conn->internal->prv_waiter)
220 silc_packet_wait_uninit(conn->internal->prv_waiter, conn->stream);
221 conn->internal->prv_waiter = NULL;
224 /* Blocks the calling process or thread until private message has been
225 received from the specified client. */
227 SilcBool silc_client_private_message_wait(SilcClient client,
228 SilcClientConnection conn,
229 SilcClientEntry client_entry,
230 SilcMessagePayload *payload)
233 SilcClientID remote_id;
234 SilcFSMThread thread;
236 if (!conn->internal->prv_waiter)
239 /* Block until private message arrives */
241 if ((silc_packet_wait(conn->internal->prv_waiter, 0, &packet)) < 0)
244 /* Parse sender ID */
245 if (!silc_id_str2id(packet->src_id, packet->src_id_len,
246 SILC_ID_CLIENT, &remote_id,
247 sizeof(remote_id))) {
248 silc_packet_free(packet);
252 /* If the private message is not for the requested client, pass it to
253 normal private message processing. */
254 if (!SILC_ID_CLIENT_COMPARE(&remote_id, &client_entry->id)) {
255 thread = silc_fsm_thread_alloc(&conn->internal->fsm, conn,
256 silc_client_fsm_destructor, NULL, FALSE);
258 silc_packet_free(packet);
262 /* The packet will be processed in the connection thread, after this
263 FSM thread is started. */
264 silc_fsm_set_state_context(thread, packet);
265 silc_fsm_start(thread, silc_client_private_message);
269 /* Parse the payload and decrypt it also if private message key is set */
271 silc_message_payload_parse(silc_buffer_data(&packet->buffer),
272 silc_buffer_len(&packet->buffer),
273 TRUE, !client_entry->internal.generated,
274 client_entry->internal.receive_key,
275 client_entry->internal.hmac_receive,
276 packet->src_id, packet->src_id_len,
277 packet->dst_id, packet->dst_id_len,
280 silc_packet_free(packet);
287 silc_packet_free(packet);
291 /*************************** Private Message Key ****************************/
293 /* Sends private message key request. Sender of this packet is initiator
294 when setting the private message key. */
297 silc_client_send_private_message_key_request(SilcClient client,
298 SilcClientConnection conn,
299 SilcClientEntry client_entry)
301 const char *cipher, *hmac;
303 SILC_LOG_DEBUG(("Sending private message key request"));
305 cipher = silc_cipher_get_name(client_entry->internal.send_key);
306 hmac = silc_hmac_get_name(client_entry->internal.hmac_send);
308 /* Send the packet */
309 return silc_packet_send_va_ext(conn->stream,
310 SILC_PACKET_PRIVATE_MESSAGE_KEY,
311 0, 0, NULL, SILC_ID_CLIENT,
312 &client_entry->id, NULL, NULL,
313 SILC_STR_UI_SHORT(strlen(cipher)),
314 SILC_STR_DATA(cipher, strlen(cipher)),
315 SILC_STR_UI_SHORT(strlen(hmac)),
316 SILC_STR_DATA(hmac, strlen(hmac)),
320 /* Client resolving callback. Here we simply mark that we are the responder
321 side of this private message key request. */
323 static void silc_client_private_message_key_cb(SilcClient client,
324 SilcClientConnection conn,
329 SilcFSMThread thread = context;
330 SilcPacket packet = silc_fsm_get_state_context(thread);
331 unsigned char *cipher = NULL, *hmac = NULL;
332 SilcClientEntry client_entry;
336 silc_packet_free(packet);
337 silc_fsm_finish(thread);
341 /* Parse the private message key payload */
342 ret = silc_buffer_unformat(&packet->buffer,
343 SILC_STR_UI16_STRING_ALLOC(&cipher),
344 SILC_STR_UI16_STRING_ALLOC(&hmac),
349 /* Mark that we are responder */
350 client_entry = silc_dlist_get(clients);
351 client_entry->internal.prv_resp = TRUE;
353 /* XXX we should notify application that remote wants to set up the
354 static key. And we should tell if we already have key with remote.
355 Application should return status telling whether to delete the key
361 silc_packet_free(packet);
362 silc_fsm_finish(thread);
365 /* Processes incoming Private Message Key payload to indicate that the
366 sender whishes to set up a static private message key. */
368 SILC_FSM_STATE(silc_client_private_message_key)
370 SilcClientConnection conn = fsm_context;
371 SilcClient client = conn->client;
372 SilcPacket packet = state_context;
373 SilcClientID remote_id;
375 if (packet->src_id_type != SILC_ID_CLIENT) {
376 silc_packet_free(packet);
377 return SILC_FSM_FINISH;
380 if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
381 &remote_id, sizeof(remote_id))) {
382 silc_packet_free(packet);
383 return SILC_FSM_FINISH;
386 /* Always resolve the remote client. The actual packet is processed
387 in the resolving callback. */
388 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
389 client, conn, &remote_id, NULL,
390 silc_client_private_message_key_cb,
394 /* Adds new private message key to `client_entry'. If we are setting this
395 before receiving request for it from `client_entry' we will send the
396 request to the client. Otherwise, we are responder side. */
398 SilcBool silc_client_add_private_message_key(SilcClient client,
399 SilcClientConnection conn,
400 SilcClientEntry client_entry,
406 SilcSKEKeyMaterial keymat;
409 if (!client || !client_entry)
412 /* Return FALSE if key already set */
413 if (client_entry->internal.send_key && client_entry->internal.receive_key)
417 cipher = SILC_DEFAULT_CIPHER;
419 hmac = SILC_DEFAULT_HMAC;
421 /* Check the requested cipher and HMAC */
422 if (!silc_cipher_is_supported(cipher))
424 if (!silc_hmac_is_supported(hmac))
428 client_entry->internal.key = silc_memdup(key, key_len);
429 client_entry->internal.key_len = key_len;
431 /* Produce the key material as the protocol defines */
432 keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
433 conn->internal->sha1hash);
437 /* Set the key into use */
438 ret = silc_client_add_private_message_key_ske(client, conn, client_entry,
439 cipher, hmac, keymat);
440 client_entry->internal.generated = FALSE;
442 /* Free the key material */
443 silc_ske_free_key_material(keymat);
445 /* If we are setting the key without a request from the remote client,
446 we will send request to remote. */
447 if (!client_entry->internal.prv_resp)
448 silc_client_send_private_message_key_request(client, conn, client_entry);
453 /* Same as above but takes the key material from the SKE key material
456 SilcBool silc_client_add_private_message_key_ske(SilcClient client,
457 SilcClientConnection conn,
458 SilcClientEntry client_entry,
461 SilcSKEKeyMaterial keymat)
463 if (!client || !client_entry)
466 /* Return FALSE if key already set */
467 if (client_entry->internal.send_key && client_entry->internal.receive_key)
471 cipher = SILC_DEFAULT_CIPHER;
473 hmac = SILC_DEFAULT_HMAC;
475 /* Check the requested cipher and HMAC */
476 if (!silc_cipher_is_supported(cipher))
478 if (!silc_hmac_is_supported(hmac))
481 client_entry->internal.generated = TRUE;
483 /* Allocate the cipher and HMAC */
484 if (!silc_cipher_alloc(cipher, &client_entry->internal.send_key))
486 if (!silc_cipher_alloc(cipher, &client_entry->internal.receive_key))
488 if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_send))
490 if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_receive))
494 if (client_entry->internal.prv_resp) {
495 silc_cipher_set_key(client_entry->internal.send_key,
496 keymat->receive_enc_key,
497 keymat->enc_key_len, TRUE);
498 silc_cipher_set_iv(client_entry->internal.send_key,
500 silc_cipher_set_key(client_entry->internal.receive_key,
501 keymat->send_enc_key,
502 keymat->enc_key_len, FALSE);
503 silc_cipher_set_iv(client_entry->internal.receive_key, keymat->send_iv);
504 silc_hmac_set_key(client_entry->internal.hmac_send,
505 keymat->receive_hmac_key,
506 keymat->hmac_key_len);
507 silc_hmac_set_key(client_entry->internal.hmac_receive,
508 keymat->send_hmac_key,
509 keymat->hmac_key_len);
511 silc_cipher_set_key(client_entry->internal.send_key,
512 keymat->send_enc_key,
513 keymat->enc_key_len, TRUE);
514 silc_cipher_set_iv(client_entry->internal.send_key,
516 silc_cipher_set_key(client_entry->internal.receive_key,
517 keymat->receive_enc_key,
518 keymat->enc_key_len, FALSE);
519 silc_cipher_set_iv(client_entry->internal.receive_key, keymat->receive_iv);
520 silc_hmac_set_key(client_entry->internal.hmac_send,
521 keymat->send_hmac_key,
522 keymat->hmac_key_len);
523 silc_hmac_set_key(client_entry->internal.hmac_receive,
524 keymat->receive_hmac_key,
525 keymat->hmac_key_len);
531 /* Removes the private message from the library. The key won't be used
532 after this to protect the private messages with the remote `client_entry'
533 client. Returns FALSE on error, TRUE otherwise. */
535 SilcBool silc_client_del_private_message_key(SilcClient client,
536 SilcClientConnection conn,
537 SilcClientEntry client_entry)
539 if (!client || !client_entry)
542 if (!client_entry->internal.send_key && !client_entry->internal.receive_key)
545 silc_cipher_free(client_entry->internal.send_key);
546 silc_cipher_free(client_entry->internal.receive_key);
548 if (client_entry->internal.key) {
549 memset(client_entry->internal.key, 0, client_entry->internal.key_len);
550 silc_free(client_entry->internal.key);
553 client_entry->internal.send_key = NULL;
554 client_entry->internal.receive_key = NULL;
555 client_entry->internal.key = NULL;
556 client_entry->internal.prv_resp = FALSE;
561 /* Returns array of set private message keys associated to the connection
562 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
563 count to the `key_count' argument. The array must be freed by the caller
564 by calling the silc_client_free_private_message_keys function. Note:
565 the keys returned in the array is in raw format. It might not be desired
566 to show the keys as is. The application might choose not to show the keys
567 at all or to show the fingerprints of the keys. */
569 SilcPrivateMessageKeys
570 silc_client_list_private_message_keys(SilcClient client,
571 SilcClientConnection conn,
572 SilcUInt32 *key_count)
574 SilcPrivateMessageKeys keys;
575 SilcUInt32 count = 0;
577 SilcIDCacheEntry id_cache;
578 SilcClientEntry entry;
580 if (!client || !conn)
583 silc_mutex_lock(conn->internal->lock);
584 if (!silc_idcache_get_all(conn->internal->client_cache, &list)) {
585 silc_mutex_unlock(conn->internal->lock);
589 keys = silc_calloc(silc_list_count(list), sizeof(*keys));
591 silc_mutex_unlock(conn->internal->lock);
595 silc_list_start(list);
596 while ((id_cache = silc_list_get(list))) {
597 entry = id_cache->context;
598 if (entry->internal.send_key) {
599 keys[count].client_entry = entry;
600 keys[count].cipher = (char *)silc_cipher_get_name(entry->internal.
602 keys[count].key = (entry->internal.generated == FALSE ?
603 entry->internal.key : NULL);
604 keys[count].key_len = (entry->internal.generated == FALSE ?
605 entry->internal.key_len : 0);
610 silc_mutex_unlock(conn->internal->lock);
618 /* Frees the SilcPrivateMessageKeys array returned by the function
619 silc_client_list_private_message_keys. */
621 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
622 SilcUInt32 key_count)
627 /* Return private message key from the client entry. */
630 silc_client_private_message_key_is_set(SilcClient client,
631 SilcClientConnection conn,
632 SilcClientEntry client_entry)
634 return client_entry->internal.send_key != NULL;
637 /* Sets away `message'. The away message may be set when the client's
638 mode is changed to SILC_UMODE_GONE and the client whishes to reply
639 to anyone who sends private message. The `message' will be sent
640 automatically back to the the client who send private message. If
641 away message is already set this replaces the old message with the
642 new one. If `message' is NULL the old away message is removed.
643 The sender may freely free the memory of the `message'. */
645 SilcBool silc_client_set_away_message(SilcClient client,
646 SilcClientConnection conn,
649 if (!client || !conn)
653 silc_free(conn->internal->away_message);
654 conn->internal->away_message = NULL;
658 if (conn->internal->away_message)
659 silc_free(conn->internal->away_message);
661 conn->internal->away_message = strdup(message);
662 if (!conn->internal->away_message)