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,
40 if (silc_unlikely(!client || !conn || !client_entry))
42 if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash))
44 if (silc_unlikely(conn->internal->disconnected))
47 SILC_LOG_DEBUG(("Sending private message"));
49 /* Encode private message payload */
51 silc_message_payload_encode(flags, data, data_len,
52 (!client_entry->internal.send_key ? FALSE :
53 !client_entry->internal.generated),
54 TRUE, client_entry->internal.send_key,
55 client_entry->internal.hmac_send,
56 client->rng, NULL, conn->private_key,
58 if (silc_unlikely(!buffer)) {
59 SILC_LOG_ERROR(("Error encoding private message"));
63 /* Send the private message packet */
64 ret = silc_packet_send_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE,
65 client_entry->internal.send_key ?
66 SILC_PACKET_FLAG_PRIVMSG_KEY : 0,
67 0, NULL, SILC_ID_CLIENT, &client_entry->id,
68 silc_buffer_datalen(buffer), NULL, NULL);
70 silc_buffer_free(buffer);
74 /************************* Private Message Receive **************************/
76 /* Client resolving callback. Continues with the private message processing */
78 static void silc_client_private_message_resolved(SilcClient client,
79 SilcClientConnection conn,
84 /* If no client found, ignore the private message, a silent error */
86 silc_fsm_next(context, silc_client_private_message_error);
88 /* Continue processing the private message packet */
89 SILC_FSM_CALL_CONTINUE(context);
92 /* Private message received. */
94 SILC_FSM_STATE(silc_client_private_message)
96 SilcClientConnection conn = fsm_context;
97 SilcClient client = conn->client;
98 SilcPacket packet = state_context;
99 SilcMessagePayload payload = NULL;
100 SilcClientID remote_id;
101 SilcClientEntry remote_client = NULL;
102 SilcMessageFlags flags;
103 unsigned char *message;
104 SilcUInt32 message_len;
106 SILC_LOG_DEBUG(("Received private message"));
108 if (silc_unlikely(packet->src_id_type != SILC_ID_CLIENT)) {
109 /** Invalid packet */
110 silc_fsm_next(fsm, silc_client_private_message_error);
111 return SILC_FSM_CONTINUE;
114 if (silc_unlikely(!silc_id_str2id(packet->src_id, packet->src_id_len,
115 SILC_ID_CLIENT, &remote_id,
116 sizeof(remote_id)))) {
117 /** Invalid source ID */
118 silc_fsm_next(fsm, silc_client_private_message_error);
119 return SILC_FSM_CONTINUE;
122 /* Check whether we know this client already */
123 remote_client = silc_client_get_client_by_id(client, conn, &remote_id);
124 if (!remote_client || !remote_client->nickname[0]) {
125 /** Resolve client info */
126 silc_client_unref_client(client, conn, remote_client);
127 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
128 client, conn, &remote_id, NULL,
129 silc_client_private_message_resolved,
134 if (silc_unlikely(packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY &&
135 !remote_client->internal.receive_key &&
136 !remote_client->internal.hmac_receive))
139 /* Parse the payload and decrypt it also if private message key is set */
141 silc_message_payload_parse(silc_buffer_datalen(&packet->buffer),
142 TRUE, !remote_client->internal.generated,
143 remote_client->internal.receive_key,
144 remote_client->internal.hmac_receive,
146 if (silc_unlikely(!payload))
149 /* Pass the private message to application */
150 flags = silc_message_get_flags(payload);
151 message = silc_message_get_data(payload, &message_len);
152 client->internal->ops->private_message(client, conn, remote_client, payload,
153 flags, message, message_len);
155 /* See if we are away (gone). If we are away we will reply to the
156 sender with the set away message. */
157 if (conn->internal->away_message &&
158 !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
159 /* If it's me, ignore */
160 if (SILC_ID_CLIENT_COMPARE(&remote_id, conn->local_id))
163 /* Send the away message */
164 silc_client_send_private_message(client, conn, remote_client,
165 SILC_MESSAGE_FLAG_AUTOREPLY |
166 SILC_MESSAGE_FLAG_NOREPLY, NULL,
167 conn->internal->away_message,
168 strlen(conn->internal->away_message));
172 /** Packet processed */
173 silc_packet_free(packet);
174 silc_client_unref_client(client, conn, remote_client);
176 silc_message_payload_free(payload);
177 return SILC_FSM_FINISH;
180 /* Private message error. */
182 SILC_FSM_STATE(silc_client_private_message_error)
184 SilcPacket packet = state_context;
185 silc_packet_free(packet);
186 return SILC_FSM_FINISH;
189 /* Initialize private message waiter for the `conn' connection. */
191 SilcBool silc_client_private_message_wait_init(SilcClient client,
192 SilcClientConnection conn)
194 if (conn->internal->prv_waiter)
197 conn->internal->prv_waiter =
198 silc_packet_wait_init(conn->stream, SILC_PACKET_PRIVATE_MESSAGE, -1);
199 if (!conn->internal->prv_waiter)
205 /* Uninitializes private message waiter. */
207 void silc_client_private_message_wait_uninit(SilcClient client,
208 SilcClientConnection conn)
210 if (!conn->internal->prv_waiter)
212 silc_packet_wait_uninit(conn->internal->prv_waiter, conn->stream);
213 conn->internal->prv_waiter = NULL;
216 /* Blocks the calling process or thread until private message has been
217 received from the specified client. */
219 SilcBool silc_client_private_message_wait(SilcClient client,
220 SilcClientConnection conn,
221 SilcClientEntry client_entry,
222 SilcMessagePayload *payload)
225 SilcClientID remote_id;
226 SilcFSMThread thread;
228 if (!conn->internal->prv_waiter)
231 /* Block until private message arrives */
233 if ((silc_packet_wait(conn->internal->prv_waiter, 0, &packet)) < 0)
236 /* Parse sender ID */
237 if (!silc_id_str2id(packet->src_id, packet->src_id_len,
238 SILC_ID_CLIENT, &remote_id,
239 sizeof(remote_id))) {
240 silc_packet_free(packet);
244 /* If the private message is not for the requested client, pass it to
245 normal private message processing. */
246 if (!SILC_ID_CLIENT_COMPARE(&remote_id, &client_entry->id)) {
247 thread = silc_fsm_thread_alloc(&conn->internal->fsm, conn,
248 silc_client_fsm_destructor, NULL, FALSE);
250 silc_packet_free(packet);
254 /* The packet will be processed in the connection thread, after this
255 FSM thread is started. */
256 silc_fsm_set_state_context(thread, packet);
257 silc_fsm_start(thread, silc_client_private_message);
261 /* Parse the payload and decrypt it also if private message key is set */
263 silc_message_payload_parse(silc_buffer_data(&packet->buffer),
264 silc_buffer_len(&packet->buffer),
265 TRUE, !client_entry->internal.generated,
266 client_entry->internal.receive_key,
267 client_entry->internal.hmac_receive,
270 silc_packet_free(packet);
277 silc_packet_free(packet);
281 /*************************** Private Message Key ****************************/
283 /* Sends private message key request. Sender of this packet is initiator
284 when setting the private message key. */
287 silc_client_send_private_message_key_request(SilcClient client,
288 SilcClientConnection conn,
289 SilcClientEntry client_entry)
291 const char *cipher, *hmac;
293 SILC_LOG_DEBUG(("Sending private message key request"));
295 cipher = silc_cipher_get_name(client_entry->internal.send_key);
296 hmac = silc_hmac_get_name(client_entry->internal.hmac_send);
298 /* Send the packet */
299 return silc_packet_send_va_ext(conn->stream,
300 SILC_PACKET_PRIVATE_MESSAGE_KEY,
301 0, 0, NULL, SILC_ID_CLIENT,
302 &client_entry->id, NULL, NULL,
303 SILC_STR_UI_SHORT(strlen(cipher)),
304 SILC_STR_DATA(cipher, strlen(cipher)),
305 SILC_STR_UI_SHORT(strlen(hmac)),
306 SILC_STR_DATA(hmac, strlen(hmac)),
310 /* Client resolving callback. Here we simply mark that we are the responder
311 side of this private message key request. */
313 static void silc_client_private_message_key_cb(SilcClient client,
314 SilcClientConnection conn,
319 SilcPacket packet = context;
320 unsigned char *cipher = NULL, *hmac = NULL;
321 SilcClientEntry client_entry;
325 silc_packet_free(packet);
329 /* Parse the private message key payload */
330 ret = silc_buffer_unformat(&packet->buffer,
331 SILC_STR_UI16_STRING_ALLOC(&cipher),
332 SILC_STR_UI16_STRING_ALLOC(&hmac),
337 /* Mark that we are responder */
338 client_entry = silc_dlist_get(clients);
339 client_entry->internal.prv_resp = TRUE;
341 /* XXX we should notify application that remote wants to set up the
342 static key. And we should tell if we already have key with remote.
343 Application should return status telling whether to delete the key
349 silc_packet_free(packet);
352 /* Processes incoming Private Message Key payload to indicate that the
353 sender whishes to set up a static private message key. */
355 SILC_FSM_STATE(silc_client_private_message_key)
357 SilcClientConnection conn = fsm_context;
358 SilcClient client = conn->client;
359 SilcPacket packet = state_context;
360 SilcClientID remote_id;
362 if (packet->src_id_type != SILC_ID_CLIENT) {
363 silc_packet_free(packet);
364 return SILC_FSM_FINISH;
367 if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
368 &remote_id, sizeof(remote_id))) {
369 silc_packet_free(packet);
370 return SILC_FSM_FINISH;
373 /* Always resolve the remote client. The actual packet is processed
374 in the resolving callback. */
375 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
376 client, conn, &remote_id, NULL,
377 silc_client_private_message_key_cb,
381 /* Adds new private message key to `client_entry'. If we are setting this
382 before receiving request for it from `client_entry' we will send the
383 request to the client. Otherwise, we are responder side. */
385 SilcBool silc_client_add_private_message_key(SilcClient client,
386 SilcClientConnection conn,
387 SilcClientEntry client_entry,
393 SilcSKEKeyMaterial keymat;
396 if (!client || !client_entry)
399 /* Return FALSE if key already set */
400 if (client_entry->internal.send_key && client_entry->internal.receive_key)
404 cipher = SILC_DEFAULT_CIPHER;
406 hmac = SILC_DEFAULT_HMAC;
408 /* Check the requested cipher and HMAC */
409 if (!silc_cipher_is_supported(cipher))
411 if (!silc_hmac_is_supported(hmac))
415 client_entry->internal.key = silc_memdup(key, key_len);
416 client_entry->internal.key_len = key_len;
418 /* Produce the key material as the protocol defines */
419 keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
420 conn->internal->sha1hash);
424 /* Set the key into use */
425 ret = silc_client_add_private_message_key_ske(client, conn, client_entry,
426 cipher, hmac, keymat);
427 client_entry->internal.generated = FALSE;
429 /* Free the key material */
430 silc_ske_free_key_material(keymat);
432 /* If we are setting the key without a request from the remote client,
433 we will send request to remote. */
434 if (!client_entry->internal.prv_resp)
435 silc_client_send_private_message_key_request(client, conn, client_entry);
440 /* Same as above but takes the key material from the SKE key material
443 SilcBool silc_client_add_private_message_key_ske(SilcClient client,
444 SilcClientConnection conn,
445 SilcClientEntry client_entry,
448 SilcSKEKeyMaterial keymat)
450 if (!client || !client_entry)
453 /* Return FALSE if key already set */
454 if (client_entry->internal.send_key && client_entry->internal.receive_key)
458 cipher = SILC_DEFAULT_CIPHER;
460 hmac = SILC_DEFAULT_HMAC;
462 /* Check the requested cipher and HMAC */
463 if (!silc_cipher_is_supported(cipher))
465 if (!silc_hmac_is_supported(hmac))
468 client_entry->internal.generated = TRUE;
470 /* Allocate the cipher and HMAC */
471 if (!silc_cipher_alloc(cipher, &client_entry->internal.send_key))
473 if (!silc_cipher_alloc(cipher, &client_entry->internal.receive_key))
475 if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_send))
477 if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_receive))
481 if (client_entry->internal.prv_resp) {
482 silc_cipher_set_key(client_entry->internal.send_key,
483 keymat->receive_enc_key,
484 keymat->enc_key_len, TRUE);
485 silc_cipher_set_iv(client_entry->internal.send_key,
487 silc_cipher_set_key(client_entry->internal.receive_key,
488 keymat->send_enc_key,
489 keymat->enc_key_len, FALSE);
490 silc_cipher_set_iv(client_entry->internal.receive_key, keymat->send_iv);
491 silc_hmac_set_key(client_entry->internal.hmac_send,
492 keymat->receive_hmac_key,
493 keymat->hmac_key_len);
494 silc_hmac_set_key(client_entry->internal.hmac_receive,
495 keymat->send_hmac_key,
496 keymat->hmac_key_len);
498 silc_cipher_set_key(client_entry->internal.send_key,
499 keymat->send_enc_key,
500 keymat->enc_key_len, TRUE);
501 silc_cipher_set_iv(client_entry->internal.send_key,
503 silc_cipher_set_key(client_entry->internal.receive_key,
504 keymat->receive_enc_key,
505 keymat->enc_key_len, FALSE);
506 silc_cipher_set_iv(client_entry->internal.receive_key, keymat->receive_iv);
507 silc_hmac_set_key(client_entry->internal.hmac_send,
508 keymat->send_hmac_key,
509 keymat->hmac_key_len);
510 silc_hmac_set_key(client_entry->internal.hmac_receive,
511 keymat->receive_hmac_key,
512 keymat->hmac_key_len);
518 /* Removes the private message from the library. The key won't be used
519 after this to protect the private messages with the remote `client_entry'
520 client. Returns FALSE on error, TRUE otherwise. */
522 SilcBool silc_client_del_private_message_key(SilcClient client,
523 SilcClientConnection conn,
524 SilcClientEntry client_entry)
526 if (!client || !client_entry)
529 if (!client_entry->internal.send_key && !client_entry->internal.receive_key)
532 silc_cipher_free(client_entry->internal.send_key);
533 silc_cipher_free(client_entry->internal.receive_key);
535 if (client_entry->internal.key) {
536 memset(client_entry->internal.key, 0, client_entry->internal.key_len);
537 silc_free(client_entry->internal.key);
540 client_entry->internal.send_key = NULL;
541 client_entry->internal.receive_key = NULL;
542 client_entry->internal.key = NULL;
543 client_entry->internal.prv_resp = FALSE;
548 /* Returns array of set private message keys associated to the connection
549 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
550 count to the `key_count' argument. The array must be freed by the caller
551 by calling the silc_client_free_private_message_keys function. Note:
552 the keys returned in the array is in raw format. It might not be desired
553 to show the keys as is. The application might choose not to show the keys
554 at all or to show the fingerprints of the keys. */
556 SilcPrivateMessageKeys
557 silc_client_list_private_message_keys(SilcClient client,
558 SilcClientConnection conn,
559 SilcUInt32 *key_count)
561 SilcPrivateMessageKeys keys;
562 SilcUInt32 count = 0;
564 SilcIDCacheEntry id_cache;
565 SilcClientEntry entry;
567 if (!client || !conn)
570 silc_mutex_lock(conn->internal->lock);
571 if (!silc_idcache_get_all(conn->internal->client_cache, &list)) {
572 silc_mutex_unlock(conn->internal->lock);
576 keys = silc_calloc(silc_list_count(list), sizeof(*keys));
578 silc_mutex_unlock(conn->internal->lock);
582 silc_list_start(list);
583 while ((id_cache = silc_list_get(list))) {
584 entry = id_cache->context;
585 if (entry->internal.send_key) {
586 keys[count].client_entry = entry;
587 keys[count].cipher = (char *)silc_cipher_get_name(entry->internal.
589 keys[count].key = (entry->internal.generated == FALSE ?
590 entry->internal.key : NULL);
591 keys[count].key_len = (entry->internal.generated == FALSE ?
592 entry->internal.key_len : 0);
597 silc_mutex_unlock(conn->internal->lock);
605 /* Frees the SilcPrivateMessageKeys array returned by the function
606 silc_client_list_private_message_keys. */
608 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
609 SilcUInt32 key_count)
614 /* Sets away `message'. The away message may be set when the client's
615 mode is changed to SILC_UMODE_GONE and the client whishes to reply
616 to anyone who sends private message. The `message' will be sent
617 automatically back to the the client who send private message. If
618 away message is already set this replaces the old message with the
619 new one. If `message' is NULL the old away message is removed.
620 The sender may freely free the memory of the `message'. */
622 SilcBool silc_client_set_away_message(SilcClient client,
623 SilcClientConnection conn,
626 if (!client || !conn)
630 silc_free(conn->internal->away_message);
631 conn->internal->away_message = NULL;
635 if (conn->internal->away_message)
636 silc_free(conn->internal->away_message);
638 conn->internal->away_message = strdup(message);
639 if (!conn->internal->away_message)