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,
201 SilcClientEntry client_entry)
205 if (client_entry->internal.prv_waiter)
208 /* We want SILC_PACKET_PRIVATE_MESSAGE packets from this source ID. */
209 id.type = SILC_ID_CLIENT;
210 id.u.client_id = client_entry->id;
212 client_entry->internal.prv_waiter =
213 silc_packet_wait_init(conn->stream, &id, SILC_PACKET_PRIVATE_MESSAGE, -1);
214 if (!client_entry->internal.prv_waiter)
220 /* Uninitializes private message waiter. */
222 void silc_client_private_message_wait_uninit(SilcClient client,
223 SilcClientConnection conn,
224 SilcClientEntry client_entry)
226 if (!client_entry->internal.prv_waiter)
228 silc_packet_wait_uninit(client_entry->internal.prv_waiter, conn->stream);
229 client_entry->internal.prv_waiter = NULL;
232 /* Blocks the calling process or thread until private message has been
233 received from the specified client. */
235 SilcBool silc_client_private_message_wait(SilcClient client,
236 SilcClientConnection conn,
237 SilcClientEntry client_entry,
238 SilcMessagePayload *payload)
242 if (!client_entry->internal.prv_waiter)
245 /* Block until private message arrives */
247 if ((silc_packet_wait(client_entry->internal.prv_waiter, 0, &packet)) < 0)
250 /* Parse the payload and decrypt it also if private message key is set */
252 silc_message_payload_parse(silc_buffer_data(&packet->buffer),
253 silc_buffer_len(&packet->buffer),
254 TRUE, !client_entry->internal.generated,
255 client_entry->internal.receive_key,
256 client_entry->internal.hmac_receive,
257 packet->src_id, packet->src_id_len,
258 packet->dst_id, packet->dst_id_len,
261 silc_packet_free(packet);
268 silc_packet_free(packet);
272 /*************************** Private Message Key ****************************/
274 /* Sends private message key request. Sender of this packet is initiator
275 when setting the private message key. */
278 silc_client_send_private_message_key_request(SilcClient client,
279 SilcClientConnection conn,
280 SilcClientEntry client_entry)
282 const char *cipher, *hmac;
284 SILC_LOG_DEBUG(("Sending private message key request"));
286 cipher = silc_cipher_get_name(client_entry->internal.send_key);
287 hmac = silc_hmac_get_name(client_entry->internal.hmac_send);
289 /* Send the packet */
290 return silc_packet_send_va_ext(conn->stream,
291 SILC_PACKET_PRIVATE_MESSAGE_KEY,
292 0, 0, NULL, SILC_ID_CLIENT,
293 &client_entry->id, NULL, NULL,
294 SILC_STR_UI_SHORT(strlen(cipher)),
295 SILC_STR_DATA(cipher, strlen(cipher)),
296 SILC_STR_UI_SHORT(strlen(hmac)),
297 SILC_STR_DATA(hmac, strlen(hmac)),
301 /* Client resolving callback. Here we simply mark that we are the responder
302 side of this private message key request. */
304 static void silc_client_private_message_key_cb(SilcClient client,
305 SilcClientConnection conn,
310 SilcFSMThread thread = context;
311 SilcPacket packet = silc_fsm_get_state_context(thread);
312 unsigned char *cipher = NULL, *hmac = NULL;
313 SilcClientEntry client_entry;
317 silc_packet_free(packet);
318 silc_fsm_finish(thread);
322 /* Parse the private message key payload */
323 ret = silc_buffer_unformat(&packet->buffer,
324 SILC_STR_UI16_STRING_ALLOC(&cipher),
325 SILC_STR_UI16_STRING_ALLOC(&hmac),
330 /* Mark that we are responder */
331 client_entry = silc_dlist_get(clients);
333 client_entry->internal.prv_resp = TRUE;
335 /* XXX we should notify application that remote wants to set up the
336 static key. And we should tell if we already have key with remote.
337 Application should return status telling whether to delete the key
343 silc_packet_free(packet);
344 silc_fsm_finish(thread);
347 /* Processes incoming Private Message Key payload to indicate that the
348 sender whishes to set up a static private message key. */
350 SILC_FSM_STATE(silc_client_private_message_key)
352 SilcClientConnection conn = fsm_context;
353 SilcClient client = conn->client;
354 SilcPacket packet = state_context;
355 SilcClientID remote_id;
357 if (packet->src_id_type != SILC_ID_CLIENT) {
358 silc_packet_free(packet);
359 return SILC_FSM_FINISH;
362 if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
363 &remote_id, sizeof(remote_id))) {
364 silc_packet_free(packet);
365 return SILC_FSM_FINISH;
368 /* Always resolve the remote client. The actual packet is processed
369 in the resolving callback. */
370 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
371 client, conn, &remote_id, NULL,
372 silc_client_private_message_key_cb,
376 /* Adds new private message key to `client_entry'. If we are setting this
377 before receiving request for it from `client_entry' we will send the
378 request to the client. Otherwise, we are responder side. */
380 SilcBool silc_client_add_private_message_key(SilcClient client,
381 SilcClientConnection conn,
382 SilcClientEntry client_entry,
388 SilcSKEKeyMaterial keymat;
391 if (!client || !client_entry)
394 /* Return FALSE if key already set */
395 if (client_entry->internal.send_key && client_entry->internal.receive_key)
399 cipher = SILC_DEFAULT_CIPHER;
401 hmac = SILC_DEFAULT_HMAC;
403 /* Check the requested cipher and HMAC */
404 if (!silc_cipher_is_supported(cipher))
406 if (!silc_hmac_is_supported(hmac))
410 client_entry->internal.key = silc_memdup(key, key_len);
411 client_entry->internal.key_len = key_len;
413 /* Produce the key material as the protocol defines */
414 keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
415 conn->internal->sha1hash);
419 /* Set the key into use */
420 ret = silc_client_add_private_message_key_ske(client, conn, client_entry,
421 cipher, hmac, keymat);
422 client_entry->internal.generated = FALSE;
424 /* Free the key material */
425 silc_ske_free_key_material(keymat);
427 /* If we are setting the key without a request from the remote client,
428 we will send request to remote. */
429 if (!client_entry->internal.prv_resp)
430 silc_client_send_private_message_key_request(client, conn, client_entry);
435 /* Same as above but takes the key material from the SKE key material
438 SilcBool silc_client_add_private_message_key_ske(SilcClient client,
439 SilcClientConnection conn,
440 SilcClientEntry client_entry,
443 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 client_entry->internal.generated = TRUE;
465 /* Allocate the cipher and HMAC */
466 if (!silc_cipher_alloc(cipher, &client_entry->internal.send_key))
468 if (!silc_cipher_alloc(cipher, &client_entry->internal.receive_key))
470 if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_send))
472 if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_receive))
476 if (client_entry->internal.prv_resp) {
477 silc_cipher_set_key(client_entry->internal.send_key,
478 keymat->receive_enc_key,
479 keymat->enc_key_len, TRUE);
480 silc_cipher_set_iv(client_entry->internal.send_key,
482 silc_cipher_set_key(client_entry->internal.receive_key,
483 keymat->send_enc_key,
484 keymat->enc_key_len, FALSE);
485 silc_cipher_set_iv(client_entry->internal.receive_key, keymat->send_iv);
486 silc_hmac_set_key(client_entry->internal.hmac_send,
487 keymat->receive_hmac_key,
488 keymat->hmac_key_len);
489 silc_hmac_set_key(client_entry->internal.hmac_receive,
490 keymat->send_hmac_key,
491 keymat->hmac_key_len);
493 silc_cipher_set_key(client_entry->internal.send_key,
494 keymat->send_enc_key,
495 keymat->enc_key_len, TRUE);
496 silc_cipher_set_iv(client_entry->internal.send_key,
498 silc_cipher_set_key(client_entry->internal.receive_key,
499 keymat->receive_enc_key,
500 keymat->enc_key_len, FALSE);
501 silc_cipher_set_iv(client_entry->internal.receive_key, keymat->receive_iv);
502 silc_hmac_set_key(client_entry->internal.hmac_send,
503 keymat->send_hmac_key,
504 keymat->hmac_key_len);
505 silc_hmac_set_key(client_entry->internal.hmac_receive,
506 keymat->receive_hmac_key,
507 keymat->hmac_key_len);
513 /* Removes the private message from the library. The key won't be used
514 after this to protect the private messages with the remote `client_entry'
515 client. Returns FALSE on error, TRUE otherwise. */
517 SilcBool silc_client_del_private_message_key(SilcClient client,
518 SilcClientConnection conn,
519 SilcClientEntry client_entry)
521 if (!client || !client_entry)
524 if (!client_entry->internal.send_key && !client_entry->internal.receive_key)
527 silc_cipher_free(client_entry->internal.send_key);
528 silc_cipher_free(client_entry->internal.receive_key);
530 if (client_entry->internal.key) {
531 memset(client_entry->internal.key, 0, client_entry->internal.key_len);
532 silc_free(client_entry->internal.key);
535 client_entry->internal.send_key = NULL;
536 client_entry->internal.receive_key = NULL;
537 client_entry->internal.key = NULL;
538 client_entry->internal.prv_resp = FALSE;
543 /* Returns array of set private message keys associated to the connection
544 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
545 count to the `key_count' argument. The array must be freed by the caller
546 by calling the silc_client_free_private_message_keys function. Note:
547 the keys returned in the array is in raw format. It might not be desired
548 to show the keys as is. The application might choose not to show the keys
549 at all or to show the fingerprints of the keys. */
551 SilcPrivateMessageKeys
552 silc_client_list_private_message_keys(SilcClient client,
553 SilcClientConnection conn,
554 SilcUInt32 *key_count)
556 SilcPrivateMessageKeys keys;
557 SilcUInt32 count = 0;
559 SilcIDCacheEntry id_cache;
560 SilcClientEntry entry;
562 if (!client || !conn)
565 silc_mutex_lock(conn->internal->lock);
566 if (!silc_idcache_get_all(conn->internal->client_cache, &list)) {
567 silc_mutex_unlock(conn->internal->lock);
571 keys = silc_calloc(silc_list_count(list), sizeof(*keys));
573 silc_mutex_unlock(conn->internal->lock);
577 silc_list_start(list);
578 while ((id_cache = silc_list_get(list))) {
579 entry = id_cache->context;
580 if (entry->internal.send_key) {
581 keys[count].client_entry = entry;
582 keys[count].cipher = (char *)silc_cipher_get_name(entry->internal.
584 keys[count].key = (entry->internal.generated == FALSE ?
585 entry->internal.key : NULL);
586 keys[count].key_len = (entry->internal.generated == FALSE ?
587 entry->internal.key_len : 0);
592 silc_mutex_unlock(conn->internal->lock);
600 /* Frees the SilcPrivateMessageKeys array returned by the function
601 silc_client_list_private_message_keys. */
603 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
604 SilcUInt32 key_count)
609 /* Return private message key from the client entry. */
612 silc_client_private_message_key_is_set(SilcClient client,
613 SilcClientConnection conn,
614 SilcClientEntry client_entry)
616 return client_entry->internal.send_key != NULL;
619 /* Sets away `message'. The away message may be set when the client's
620 mode is changed to SILC_UMODE_GONE and the client whishes to reply
621 to anyone who sends private message. The `message' will be sent
622 automatically back to the the client who send private message. If
623 away message is already set this replaces the old message with the
624 new one. If `message' is NULL the old away message is removed.
625 The sender may freely free the memory of the `message'. */
627 SilcBool silc_client_set_away_message(SilcClient client,
628 SilcClientConnection conn,
631 if (!client || !conn)
635 silc_free(conn->internal->away_message);
636 conn->internal->away_message = NULL;
640 if (conn->internal->away_message)
641 silc_free(conn->internal->away_message);
643 conn->internal->away_message = strdup(message);
644 if (!conn->internal->away_message)