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 ****************************/
29 SilcClientConnection conn;
30 SilcClientEntry client_entry;
31 } *SilcClientPrvmsgContext;
33 /* Message payload encoding callback */
35 static void silc_client_send_private_message_final(SilcBuffer message,
38 SilcClientPrvmsgContext p = context;
40 /* Send the private message packet */
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);
48 silc_client_unref_client(p->client, p->conn, p->client_entry);
52 /* Sends private message to remote client. */
54 SilcBool silc_client_send_private_message(SilcClient client,
55 SilcClientConnection conn,
56 SilcClientEntry client_entry,
57 SilcMessageFlags flags,
62 SilcClientPrvmsgContext p;
65 if (silc_unlikely(!client || !conn || !client_entry))
67 if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash)) {
68 SILC_LOG_ERROR(("Cannot send signed message without hash, missing "
72 if (silc_unlikely(conn->internal->disconnected))
75 SILC_LOG_DEBUG(("Sending private message"));
77 sid.type = SILC_ID_CLIENT;
78 sid.u.client_id = conn->local_entry->id;
79 rid.type = SILC_ID_CLIENT;
80 rid.u.client_id = client_entry->id;
82 p = silc_calloc(1, sizeof(*p));
88 p->client_entry = silc_client_ref_client(client, conn, client_entry);
90 /* Encode private message payload */
91 silc_message_payload_encode(flags, data, data_len,
92 (!client_entry->internal.send_key ? FALSE :
93 !client_entry->internal.generated),
94 TRUE, client_entry->internal.send_key,
95 client_entry->internal.hmac_send,
96 client->rng, NULL, conn->private_key,
97 hash, &sid, &rid, NULL,
98 silc_client_send_private_message_final, p);
103 /************************* Private Message Receive **************************/
105 /* Client resolving callback. Continues with the private message processing */
107 static void silc_client_private_message_resolved(SilcClient client,
108 SilcClientConnection conn,
113 /* If no client found, ignore the private message, a silent error */
115 silc_fsm_next(context, silc_client_private_message_error);
117 /* Continue processing the private message packet */
118 SILC_FSM_CALL_CONTINUE(context);
121 /* Private message received. */
123 SILC_FSM_STATE(silc_client_private_message)
125 SilcClientConnection conn = fsm_context;
126 SilcClient client = conn->client;
127 SilcPacket packet = state_context;
128 SilcMessagePayload payload = NULL;
129 SilcClientID remote_id;
130 SilcClientEntry remote_client = NULL;
131 SilcMessageFlags flags;
132 unsigned char *message;
133 SilcUInt32 message_len;
135 SILC_LOG_DEBUG(("Received private message"));
137 if (silc_unlikely(packet->src_id_type != SILC_ID_CLIENT)) {
138 /** Invalid packet */
139 silc_fsm_next(fsm, silc_client_private_message_error);
140 return SILC_FSM_CONTINUE;
143 if (silc_unlikely(!silc_id_str2id(packet->src_id, packet->src_id_len,
144 SILC_ID_CLIENT, &remote_id,
145 sizeof(remote_id)))) {
146 /** Invalid source ID */
147 silc_fsm_next(fsm, silc_client_private_message_error);
148 return SILC_FSM_CONTINUE;
151 /* Check whether we know this client already */
152 remote_client = silc_client_get_client_by_id(client, conn, &remote_id);
153 if (!remote_client || !remote_client->nickname[0]) {
154 /** Resolve client info */
155 silc_client_unref_client(client, conn, remote_client);
156 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
157 client, conn, &remote_id, NULL,
158 silc_client_private_message_resolved,
163 if (silc_unlikely(packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY &&
164 !remote_client->internal.receive_key &&
165 !remote_client->internal.hmac_receive))
168 /* Parse the payload and decrypt it also if private message key is set */
170 silc_message_payload_parse(silc_buffer_datalen(&packet->buffer),
171 TRUE, !remote_client->internal.generated,
172 remote_client->internal.receive_key,
173 remote_client->internal.hmac_receive,
174 packet->src_id, packet->src_id_len,
175 packet->dst_id, packet->dst_id_len,
177 if (silc_unlikely(!payload))
180 /* Pass the private message to application */
181 flags = silc_message_get_flags(payload);
182 message = silc_message_get_data(payload, &message_len);
183 client->internal->ops->private_message(client, conn, remote_client, payload,
184 flags, message, message_len);
186 /* See if we are away (gone). If we are away we will reply to the
187 sender with the set away message. */
188 if (conn->internal->away_message &&
189 !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
190 /* If it's me, ignore */
191 if (SILC_ID_CLIENT_COMPARE(&remote_id, conn->local_id))
194 /* Send the away message */
195 silc_client_send_private_message(client, conn, remote_client,
196 SILC_MESSAGE_FLAG_AUTOREPLY |
197 SILC_MESSAGE_FLAG_NOREPLY, NULL,
198 conn->internal->away_message,
199 strlen(conn->internal->away_message));
203 /** Packet processed */
204 silc_packet_free(packet);
205 silc_client_unref_client(client, conn, remote_client);
207 silc_message_payload_free(payload);
208 return SILC_FSM_FINISH;
211 /* Private message error. */
213 SILC_FSM_STATE(silc_client_private_message_error)
215 SilcPacket packet = state_context;
216 silc_packet_free(packet);
217 return SILC_FSM_FINISH;
220 /* Initialize private message waiter for the `conn' connection. */
222 SilcBool silc_client_private_message_wait_init(SilcClient client,
223 SilcClientConnection conn,
224 SilcClientEntry client_entry)
228 if (client_entry->internal.prv_waiter)
231 /* We want SILC_PACKET_PRIVATE_MESSAGE packets from this source ID. */
232 id.type = SILC_ID_CLIENT;
233 id.u.client_id = client_entry->id;
235 client_entry->internal.prv_waiter =
236 silc_packet_wait_init(conn->stream, &id, SILC_PACKET_PRIVATE_MESSAGE, -1);
237 if (!client_entry->internal.prv_waiter)
243 /* Uninitializes private message waiter. */
245 void silc_client_private_message_wait_uninit(SilcClient client,
246 SilcClientConnection conn,
247 SilcClientEntry client_entry)
249 if (!client_entry->internal.prv_waiter)
251 silc_packet_wait_uninit(client_entry->internal.prv_waiter, conn->stream);
252 client_entry->internal.prv_waiter = NULL;
255 /* Blocks the calling process or thread until private message has been
256 received from the specified client. */
258 SilcBool silc_client_private_message_wait(SilcClient client,
259 SilcClientConnection conn,
260 SilcClientEntry client_entry,
261 SilcMessagePayload *payload)
265 if (!client_entry->internal.prv_waiter)
268 /* Block until private message arrives */
270 if ((silc_packet_wait(client_entry->internal.prv_waiter, 0, &packet)) < 0)
273 /* Parse the payload and decrypt it also if private message key is set */
275 silc_message_payload_parse(silc_buffer_data(&packet->buffer),
276 silc_buffer_len(&packet->buffer),
277 TRUE, !client_entry->internal.generated,
278 client_entry->internal.receive_key,
279 client_entry->internal.hmac_receive,
280 packet->src_id, packet->src_id_len,
281 packet->dst_id, packet->dst_id_len,
284 silc_packet_free(packet);
291 silc_packet_free(packet);
295 /*************************** Private Message Key ****************************/
297 /* Sends private message key request. Sender of this packet is initiator
298 when setting the private message key. */
301 silc_client_send_private_message_key_request(SilcClient client,
302 SilcClientConnection conn,
303 SilcClientEntry client_entry)
305 const char *cipher, *hmac;
307 SILC_LOG_DEBUG(("Sending private message key request"));
309 cipher = silc_cipher_get_name(client_entry->internal.send_key);
310 hmac = silc_hmac_get_name(client_entry->internal.hmac_send);
312 /* Send the packet */
313 return silc_packet_send_va_ext(conn->stream,
314 SILC_PACKET_PRIVATE_MESSAGE_KEY,
315 0, 0, NULL, SILC_ID_CLIENT,
316 &client_entry->id, NULL, NULL,
317 SILC_STR_UI_SHORT(strlen(cipher)),
318 SILC_STR_DATA(cipher, strlen(cipher)),
319 SILC_STR_UI_SHORT(strlen(hmac)),
320 SILC_STR_DATA(hmac, strlen(hmac)),
324 /* Client resolving callback. Here we simply mark that we are the responder
325 side of this private message key request. */
327 static void silc_client_private_message_key_cb(SilcClient client,
328 SilcClientConnection conn,
333 SilcFSMThread thread = context;
334 SilcPacket packet = silc_fsm_get_state_context(thread);
335 unsigned char *cipher = NULL, *hmac = NULL;
336 SilcClientEntry client_entry;
340 silc_packet_free(packet);
341 silc_fsm_finish(thread);
345 /* Parse the private message key payload */
346 ret = silc_buffer_unformat(&packet->buffer,
347 SILC_STR_UI16_STRING_ALLOC(&cipher),
348 SILC_STR_UI16_STRING_ALLOC(&hmac),
353 /* Mark that we are responder */
354 client_entry = silc_dlist_get(clients);
355 client_entry->internal.prv_resp = TRUE;
357 /* XXX we should notify application that remote wants to set up the
358 static key. And we should tell if we already have key with remote.
359 Application should return status telling whether to delete the key
365 silc_packet_free(packet);
366 silc_fsm_finish(thread);
369 /* Processes incoming Private Message Key payload to indicate that the
370 sender whishes to set up a static private message key. */
372 SILC_FSM_STATE(silc_client_private_message_key)
374 SilcClientConnection conn = fsm_context;
375 SilcClient client = conn->client;
376 SilcPacket packet = state_context;
377 SilcClientID remote_id;
379 if (packet->src_id_type != SILC_ID_CLIENT) {
380 silc_packet_free(packet);
381 return SILC_FSM_FINISH;
384 if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
385 &remote_id, sizeof(remote_id))) {
386 silc_packet_free(packet);
387 return SILC_FSM_FINISH;
390 /* Always resolve the remote client. The actual packet is processed
391 in the resolving callback. */
392 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
393 client, conn, &remote_id, NULL,
394 silc_client_private_message_key_cb,
398 /* Adds new private message key to `client_entry'. If we are setting this
399 before receiving request for it from `client_entry' we will send the
400 request to the client. Otherwise, we are responder side. */
402 SilcBool silc_client_add_private_message_key(SilcClient client,
403 SilcClientConnection conn,
404 SilcClientEntry client_entry,
410 SilcSKEKeyMaterial keymat;
413 if (!client || !client_entry)
416 /* Return FALSE if key already set */
417 if (client_entry->internal.send_key && client_entry->internal.receive_key)
421 cipher = SILC_DEFAULT_CIPHER;
423 hmac = SILC_DEFAULT_HMAC;
425 /* Check the requested cipher and HMAC */
426 if (!silc_cipher_is_supported(cipher))
428 if (!silc_hmac_is_supported(hmac))
432 client_entry->internal.key = silc_memdup(key, key_len);
433 client_entry->internal.key_len = key_len;
435 /* Produce the key material as the protocol defines */
436 keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
437 conn->internal->sha1hash);
441 /* Set the key into use */
442 ret = silc_client_add_private_message_key_ske(client, conn, client_entry,
443 cipher, hmac, keymat);
444 client_entry->internal.generated = FALSE;
446 /* Free the key material */
447 silc_ske_free_key_material(keymat);
449 /* If we are setting the key without a request from the remote client,
450 we will send request to remote. */
451 if (!client_entry->internal.prv_resp)
452 silc_client_send_private_message_key_request(client, conn, client_entry);
457 /* Same as above but takes the key material from the SKE key material
460 SilcBool silc_client_add_private_message_key_ske(SilcClient client,
461 SilcClientConnection conn,
462 SilcClientEntry client_entry,
465 SilcSKEKeyMaterial keymat)
467 if (!client || !client_entry)
470 /* Return FALSE if key already set */
471 if (client_entry->internal.send_key && client_entry->internal.receive_key)
475 cipher = SILC_DEFAULT_CIPHER;
477 hmac = SILC_DEFAULT_HMAC;
479 /* Check the requested cipher and HMAC */
480 if (!silc_cipher_is_supported(cipher))
482 if (!silc_hmac_is_supported(hmac))
485 client_entry->internal.generated = TRUE;
487 /* Allocate the cipher and HMAC */
488 if (!silc_cipher_alloc(cipher, &client_entry->internal.send_key))
490 if (!silc_cipher_alloc(cipher, &client_entry->internal.receive_key))
492 if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_send))
494 if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_receive))
498 if (client_entry->internal.prv_resp) {
499 silc_cipher_set_key(client_entry->internal.send_key,
500 keymat->receive_enc_key,
501 keymat->enc_key_len, TRUE);
502 silc_cipher_set_iv(client_entry->internal.send_key,
504 silc_cipher_set_key(client_entry->internal.receive_key,
505 keymat->send_enc_key,
506 keymat->enc_key_len, FALSE);
507 silc_cipher_set_iv(client_entry->internal.receive_key, keymat->send_iv);
508 silc_hmac_set_key(client_entry->internal.hmac_send,
509 keymat->receive_hmac_key,
510 keymat->hmac_key_len);
511 silc_hmac_set_key(client_entry->internal.hmac_receive,
512 keymat->send_hmac_key,
513 keymat->hmac_key_len);
515 silc_cipher_set_key(client_entry->internal.send_key,
516 keymat->send_enc_key,
517 keymat->enc_key_len, TRUE);
518 silc_cipher_set_iv(client_entry->internal.send_key,
520 silc_cipher_set_key(client_entry->internal.receive_key,
521 keymat->receive_enc_key,
522 keymat->enc_key_len, FALSE);
523 silc_cipher_set_iv(client_entry->internal.receive_key, keymat->receive_iv);
524 silc_hmac_set_key(client_entry->internal.hmac_send,
525 keymat->send_hmac_key,
526 keymat->hmac_key_len);
527 silc_hmac_set_key(client_entry->internal.hmac_receive,
528 keymat->receive_hmac_key,
529 keymat->hmac_key_len);
535 /* Removes the private message from the library. The key won't be used
536 after this to protect the private messages with the remote `client_entry'
537 client. Returns FALSE on error, TRUE otherwise. */
539 SilcBool silc_client_del_private_message_key(SilcClient client,
540 SilcClientConnection conn,
541 SilcClientEntry client_entry)
543 if (!client || !client_entry)
546 if (!client_entry->internal.send_key && !client_entry->internal.receive_key)
549 silc_cipher_free(client_entry->internal.send_key);
550 silc_cipher_free(client_entry->internal.receive_key);
552 if (client_entry->internal.key) {
553 memset(client_entry->internal.key, 0, client_entry->internal.key_len);
554 silc_free(client_entry->internal.key);
557 client_entry->internal.send_key = NULL;
558 client_entry->internal.receive_key = NULL;
559 client_entry->internal.key = NULL;
560 client_entry->internal.prv_resp = FALSE;
565 /* Returns array of set private message keys associated to the connection
566 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
567 count to the `key_count' argument. The array must be freed by the caller
568 by calling the silc_client_free_private_message_keys function. Note:
569 the keys returned in the array is in raw format. It might not be desired
570 to show the keys as is. The application might choose not to show the keys
571 at all or to show the fingerprints of the keys. */
573 SilcPrivateMessageKeys
574 silc_client_list_private_message_keys(SilcClient client,
575 SilcClientConnection conn,
576 SilcUInt32 *key_count)
578 SilcPrivateMessageKeys keys;
579 SilcUInt32 count = 0;
581 SilcIDCacheEntry id_cache;
582 SilcClientEntry entry;
584 if (!client || !conn)
587 silc_mutex_lock(conn->internal->lock);
588 if (!silc_idcache_get_all(conn->internal->client_cache, &list)) {
589 silc_mutex_unlock(conn->internal->lock);
593 keys = silc_calloc(silc_list_count(list), sizeof(*keys));
595 silc_mutex_unlock(conn->internal->lock);
599 silc_list_start(list);
600 while ((id_cache = silc_list_get(list))) {
601 entry = id_cache->context;
602 if (entry->internal.send_key) {
603 keys[count].client_entry = entry;
604 keys[count].cipher = (char *)silc_cipher_get_name(entry->internal.
606 keys[count].key = (entry->internal.generated == FALSE ?
607 entry->internal.key : NULL);
608 keys[count].key_len = (entry->internal.generated == FALSE ?
609 entry->internal.key_len : 0);
614 silc_mutex_unlock(conn->internal->lock);
622 /* Frees the SilcPrivateMessageKeys array returned by the function
623 silc_client_list_private_message_keys. */
625 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
626 SilcUInt32 key_count)
631 /* Return private message key from the client entry. */
634 silc_client_private_message_key_is_set(SilcClient client,
635 SilcClientConnection conn,
636 SilcClientEntry client_entry)
638 return client_entry->internal.send_key != NULL;
641 /* Sets away `message'. The away message may be set when the client's
642 mode is changed to SILC_UMODE_GONE and the client whishes to reply
643 to anyone who sends private message. The `message' will be sent
644 automatically back to the the client who send private message. If
645 away message is already set this replaces the old message with the
646 new one. If `message' is NULL the old away message is removed.
647 The sender may freely free the memory of the `message'. */
649 SilcBool silc_client_set_away_message(SilcClient client,
650 SilcClientConnection conn,
653 if (!client || !conn)
657 silc_free(conn->internal->away_message);
658 conn->internal->away_message = NULL;
662 if (conn->internal->away_message)
663 silc_free(conn->internal->away_message);
665 conn->internal->away_message = strdup(message);
666 if (!conn->internal->away_message)