5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2004 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.
20 /* This file includes the private message sending and receiving routines
21 and private message key handling routines. */
23 #include "silcincludes.h"
24 #include "silcclient.h"
25 #include "client_internal.h"
27 /* Sends private message to remote client. If private message key has
28 not been set with this client then the message will be encrypted using
29 normal session keys. Private messages are special packets in SILC
30 network hence we need this own function for them. This is similiar
31 to silc_client_packet_send_to_channel except that we send private
32 message. The `data' is the private message. If the `force_send' is
33 TRUE the packet is sent immediately. */
35 SilcBool silc_client_send_private_message(SilcClient client,
36 SilcClientConnection conn,
37 SilcClientEntry client_entry,
38 SilcMessageFlags flags,
43 SilcSocketConnection sock;
45 SilcPacketContext packetdata;
46 const SilcBufferStruct packet;
52 assert(client && conn && client_entry);
54 SILC_LOG_DEBUG(("Sending private message"));
56 /* Encode private message payload */
57 buffer = silc_message_payload_encode(flags, data, data_len,
58 !client_entry->send_key ? FALSE :
59 !client_entry->generated,
60 TRUE, client_entry->send_key,
61 client_entry->hmac_send,
62 client->rng, NULL, client->private_key,
65 SILC_LOG_ERROR(("Error encoding private message"));
69 /* If we don't have private message specific key then private messages
70 are just as any normal packet thus call normal packet sending. If
71 the key exist then the encryption process is a bit different and
72 will be done in the rest of this function. */
73 if (!client_entry->send_key) {
74 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
75 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
76 buffer->data, buffer->len, force_send);
81 /* We have private message specific key */
83 /* Get data used in the encryption */
84 cipher = conn->internal->send_key;
85 hmac = conn->internal->hmac_send;
86 block_len = silc_cipher_get_block_len(cipher);
88 /* Set the packet context pointers. */
90 data_len = buffer->len;
91 packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
92 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
93 packetdata.src_id = conn->local_id_data;
94 packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
95 packetdata.src_id_type = SILC_ID_CLIENT;
96 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
97 packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
98 packetdata.dst_id_type = SILC_ID_CLIENT;
99 data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
100 packetdata.src_id_len +
101 packetdata.dst_id_len);
102 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
103 packetdata.src_id_len + packetdata.dst_id_len;
104 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
105 packetdata.src_id_len +
106 packetdata.dst_id_len), block_len, packetdata.padlen);
108 /* Create the outgoing packet */
109 if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
110 data, data_len, (const SilcBuffer)&packet)) {
111 SILC_LOG_ERROR(("Error assembling packet"));
115 /* Encrypt the header and padding of the packet. */
116 silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
117 (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
118 packetdata.src_id_len + packetdata.dst_id_len +
121 SILC_LOG_HEXDUMP(("Private message packet, len %d", packet.len),
122 packet.data, packet.len);
124 /* Now actually send the packet */
125 silc_client_packet_send_real(client, sock, force_send);
127 /* Check for mandatory rekey */
128 if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD)
129 silc_schedule_task_add(client->schedule, sock->sock,
130 silc_client_rekey_callback, sock, 0, 1,
131 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
133 silc_free(packetdata.dst_id);
138 silc_buffer_free(buffer);
143 static void silc_client_private_message_cb(SilcClient client,
144 SilcClientConnection conn,
145 SilcClientEntry *clients,
146 SilcUInt32 clients_count,
149 SilcPacketContext *packet = (SilcPacketContext *)context;
152 silc_packet_context_free(packet);
156 silc_client_private_message(client, conn->sock, packet);
157 silc_packet_context_free(packet);
160 /* Private message received. This processes the private message and
161 finally displays it on the screen. */
163 void silc_client_private_message(SilcClient client,
164 SilcSocketConnection sock,
165 SilcPacketContext *packet)
167 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
168 SilcMessagePayload payload = NULL;
169 SilcClientID *remote_id = NULL;
170 SilcClientEntry remote_client;
171 SilcMessageFlags flags;
172 unsigned char *message;
173 SilcUInt32 message_len;
174 SilcCipher cipher = NULL;
175 SilcHmac hmac = NULL;
177 if (packet->src_id_type != SILC_ID_CLIENT)
180 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
185 /* Check whether we know this client already */
186 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
187 if (!remote_client || !remote_client->nickname) {
189 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
190 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
193 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
194 remote_client->resolve_cmd_ident = conn->cmd_ident + 1;
197 /* Resolve the client info */
198 silc_client_get_client_by_id_resolve(client, conn, remote_id, NULL,
199 silc_client_private_message_cb,
200 silc_packet_context_dup(packet));
204 cipher = remote_client->receive_key;
205 hmac = remote_client->hmac_receive;
206 if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher && !hmac) {
207 silc_free(remote_id);
211 /* Parse the payload and decrypt it also if private message key is set */
212 payload = silc_message_payload_parse(packet->buffer->data,
213 packet->buffer->len, TRUE,
214 !remote_client->generated,
217 silc_free(remote_id);
221 flags = silc_message_get_flags(payload);
223 /* Pass the private message to application */
224 message = silc_message_get_data(payload, &message_len);
225 client->internal->ops->private_message(client, conn, remote_client, payload,
226 flags, message, message_len);
228 /* See if we are away (gone). If we are away we will reply to the
229 sender with the set away message. */
230 if (conn->internal->away && conn->internal->away->away &&
231 !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
232 /* If it's me, ignore */
233 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
236 /* Send the away message */
237 silc_client_send_private_message(client, conn, remote_client,
238 SILC_MESSAGE_FLAG_AUTOREPLY |
239 SILC_MESSAGE_FLAG_NOREPLY,
240 conn->internal->away->away,
241 strlen(conn->internal->away->away), TRUE);
246 silc_message_payload_free(payload);
247 silc_free(remote_id);
250 /* Function that actually employes the received private message key */
252 static void silc_client_private_message_key_cb(SilcClient client,
253 SilcClientConnection conn,
254 SilcClientEntry *clients,
255 SilcUInt32 clients_count,
258 SilcPacketContext *packet = (SilcPacketContext *)context;
261 unsigned char *cipher = NULL, *hmac = NULL;
267 /* Parse the private message key payload */
268 ret = silc_buffer_unformat(packet->buffer,
269 SILC_STR_UI16_NSTRING(&key, &key_len),
270 SILC_STR_UI16_STRING_ALLOC(&cipher),
271 SILC_STR_UI16_STRING_ALLOC(&hmac),
276 if (key_len > packet->buffer->len)
279 /* Mark that we are responder */
280 clients[0]->prv_resp = TRUE;
285 silc_packet_context_free(packet);
288 /* Processes incoming Private Message Key payload to indicate that the
289 sender whishes to set up a static private message key. */
291 void silc_client_private_message_key(SilcClient client,
292 SilcSocketConnection sock,
293 SilcPacketContext *packet)
295 SilcClientID *remote_id;
297 if (packet->src_id_type != SILC_ID_CLIENT)
300 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
305 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
307 silc_client_private_message_key_cb,
308 silc_packet_context_dup(packet));
309 silc_free(remote_id);
312 /* Adds private message key to the client library. The key will be used to
313 encrypt all private message between the client and the remote client
314 indicated by the `client_entry'. If the `key' is NULL and the boolean
315 value `generate_key' is TRUE the library will generate random key.
316 The `key' maybe for example pre-shared-key, passphrase or similar.
317 The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure
318 that the requirements of the SILC protocol are met. The API, however,
319 allows to allocate any cipher and HMAC.
321 If `responder' is TRUE then the sending and receiving keys will be
322 set according the client being the receiver of the private key. If
323 FALSE the client is being the sender (or negotiator) of the private
326 It is not necessary to set key for normal private message usage. If the
327 key is not set then the private messages are encrypted using normal
328 session keys. Setting the private key, however, increases the security.
330 Returns FALSE if the key is already set for the `client_entry', TRUE
333 SilcBool silc_client_add_private_message_key(SilcClient client,
334 SilcClientConnection conn,
335 SilcClientEntry client_entry,
340 SilcBool generate_key,
343 unsigned char private_key[32];
346 SilcSKEKeyMaterial *keymat;
348 assert(client && client_entry);
350 /* Return FALSE if key already set */
351 if (client_entry->send_key && client_entry->receive_key)
355 cipher = SILC_DEFAULT_CIPHER;
357 hmac = SILC_DEFAULT_HMAC;
359 /* Check the requested cipher and HMAC */
360 if (!silc_cipher_is_supported(cipher))
362 if (!silc_hmac_is_supported(hmac))
365 /* Generate key if not provided */
366 if (generate_key == TRUE) {
368 for (i = 0; i < len; i++)
369 private_key[i] = silc_rng_get_byte_fast(client->rng);
372 client_entry->generated = TRUE;
376 client_entry->key = silc_memdup(key, key_len);
377 client_entry->key_len = key_len;
379 /* Produce the key material as the protocol defines */
380 keymat = silc_calloc(1, sizeof(*keymat));
381 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
382 client->sha1hash, keymat)
383 != SILC_SKE_STATUS_OK)
386 /* Allocate the cipher and HMAC */
387 silc_cipher_alloc(cipher, &client_entry->send_key);
388 silc_cipher_alloc(cipher, &client_entry->receive_key);
389 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
390 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
393 if (responder == TRUE) {
394 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
395 keymat->enc_key_len);
396 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
397 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
398 keymat->enc_key_len);
399 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
400 silc_hmac_set_key(client_entry->hmac_send, keymat->receive_hmac_key,
401 keymat->hmac_key_len);
402 silc_hmac_set_key(client_entry->hmac_receive, keymat->send_hmac_key,
403 keymat->hmac_key_len);
405 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
406 keymat->enc_key_len);
407 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
408 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
409 keymat->enc_key_len);
410 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
411 silc_hmac_set_key(client_entry->hmac_send, keymat->send_hmac_key,
412 keymat->hmac_key_len);
413 silc_hmac_set_key(client_entry->hmac_receive, keymat->receive_hmac_key,
414 keymat->hmac_key_len);
417 /* Free the key material */
418 silc_ske_free_key_material(keymat);
423 /* Same as above but takes the key material from the SKE key material
424 structure. This structure is received if the application uses the
425 silc_client_send_key_agreement to negotiate the key material. The
426 `cipher' and `hmac' SHOULD be provided as it is negotiated also in
429 SilcBool silc_client_add_private_message_key_ske(SilcClient client,
430 SilcClientConnection conn,
431 SilcClientEntry client_entry,
434 SilcSKEKeyMaterial *key,
437 assert(client && client_entry);
439 /* Return FALSE if key already set */
440 if (client_entry->send_key && client_entry->receive_key)
444 cipher = SILC_DEFAULT_CIPHER;
446 hmac = SILC_DEFAULT_HMAC;
448 /* Check the requested cipher and HMAC */
449 if (!silc_cipher_is_supported(cipher))
451 if (!silc_hmac_is_supported(hmac))
454 client_entry->generated = TRUE;
456 /* Allocate the cipher and HMAC */
457 silc_cipher_alloc(cipher, &client_entry->send_key);
458 silc_cipher_alloc(cipher, &client_entry->receive_key);
459 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
460 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
463 if (responder == TRUE) {
464 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
466 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
467 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
469 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
470 silc_hmac_set_key(client_entry->hmac_send, key->receive_hmac_key,
472 silc_hmac_set_key(client_entry->hmac_receive, key->send_hmac_key,
475 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
477 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
478 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
480 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
481 silc_hmac_set_key(client_entry->hmac_send, key->send_hmac_key,
483 silc_hmac_set_key(client_entry->hmac_receive, key->receive_hmac_key,
490 /* Sends private message key indicator. The sender of this packet is
491 going to be the initiator, if and when, the users set up a static
492 private message key (not Key Agreement). */
494 SilcBool silc_client_send_private_message_key_request(SilcClient client,
495 SilcClientConnection conn,
496 SilcClientEntry client_entry)
498 SilcSocketConnection sock;
500 int cipher_len, hmac_len;
501 const char *cipher, *hmac;
503 assert(client && conn && client_entry);
506 if (!client_entry->send_key || !client_entry->key)
509 SILC_LOG_DEBUG(("Sending private message key indicator"));
511 cipher = silc_cipher_get_name(client_entry->send_key);
512 cipher_len = strlen(cipher);
513 hmac = silc_hmac_get_name(client_entry->hmac_send);
514 hmac_len = strlen(hmac);
516 /* Create private message key payload */
517 buffer = silc_buffer_alloc_size(4 + cipher_len + hmac_len);
518 silc_buffer_format(buffer,
519 SILC_STR_UI_SHORT(cipher_len),
520 SILC_STR_UI_XNSTRING(cipher,
522 SILC_STR_UI_SHORT(hmac_len),
523 SILC_STR_UI_XNSTRING(hmac,
527 /* Send the packet */
528 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
529 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
530 buffer->data, buffer->len, TRUE);
536 /* Removes the private message from the library. The key won't be used
537 after this to protect the private messages with the remote `client_entry'
538 client. Returns FALSE on error, TRUE otherwise. */
540 SilcBool silc_client_del_private_message_key(SilcClient client,
541 SilcClientConnection conn,
542 SilcClientEntry client_entry)
544 assert(client && client_entry);
546 if (!client_entry->send_key && !client_entry->receive_key)
549 silc_cipher_free(client_entry->send_key);
550 silc_cipher_free(client_entry->receive_key);
552 if (client_entry->key) {
553 memset(client_entry->key, 0, client_entry->key_len);
554 silc_free(client_entry->key);
557 client_entry->send_key = NULL;
558 client_entry->receive_key = NULL;
559 client_entry->key = NULL;
564 /* Returns array of set private message keys associated to the connection
565 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
566 count to the `key_count' argument. The array must be freed by the caller
567 by calling the silc_client_free_private_message_keys function. Note:
568 the keys returned in the array is in raw format. It might not be desired
569 to show the keys as is. The application might choose not to show the keys
570 at all or to show the fingerprints of the keys. */
572 SilcPrivateMessageKeys
573 silc_client_list_private_message_keys(SilcClient client,
574 SilcClientConnection conn,
575 SilcUInt32 *key_count)
577 SilcPrivateMessageKeys keys;
578 SilcUInt32 count = 0;
579 SilcIDCacheEntry id_cache;
580 SilcIDCacheList list;
581 SilcClientEntry entry;
583 assert(client && conn);
585 if (!silc_idcache_get_all(conn->internal->client_cache, &list))
588 if (!silc_idcache_list_count(list)) {
589 silc_idcache_list_free(list);
593 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
595 silc_idcache_list_first(list, &id_cache);
597 entry = (SilcClientEntry)id_cache->context;
599 if (entry->send_key) {
600 keys[count].client_entry = entry;
601 keys[count].cipher = (char *)silc_cipher_get_name(entry->send_key);
602 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
603 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
607 if (!silc_idcache_list_next(list, &id_cache))
617 /* Frees the SilcPrivateMessageKeys array returned by the function
618 silc_client_list_private_message_keys. */
620 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
621 SilcUInt32 key_count)
626 /* Sets away `message'. The away message may be set when the client's
627 mode is changed to SILC_UMODE_GONE and the client whishes to reply
628 to anyone who sends private message. The `message' will be sent
629 automatically back to the the client who send private message. If
630 away message is already set this replaces the old message with the
631 new one. If `message' is NULL the old away message is removed.
632 The sender may freely free the memory of the `message'. */
634 void silc_client_set_away_message(SilcClient client,
635 SilcClientConnection conn,
638 assert(client && conn);
640 if (!message && conn->internal->away) {
641 silc_free(conn->internal->away->away);
642 silc_free(conn->internal->away);
643 conn->internal->away = NULL;
647 if (!conn->internal->away)
648 conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
649 if (conn->internal->away->away)
650 silc_free(conn->internal->away->away);
651 conn->internal->away->away = strdup(message);