5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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 void 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;
51 assert(client && conn && client_entry);
53 SILC_LOG_DEBUG(("Sending private message"));
55 /* Encode private message payload */
56 buffer = silc_private_message_payload_encode(flags,
58 client_entry->send_key,
59 client_entry->hmac_send,
62 /* If we don't have private message specific key then private messages
63 are just as any normal packet thus call normal packet sending. If
64 the key exist then the encryption process is a bit different and
65 will be done in the rest of this function. */
66 if (!client_entry->send_key) {
67 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
68 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
69 buffer->data, buffer->len, force_send);
73 /* We have private message specific key */
75 /* Get data used in the encryption */
76 cipher = conn->internal->send_key;
77 hmac = conn->internal->hmac_send;
78 block_len = silc_cipher_get_block_len(cipher);
80 /* Set the packet context pointers. */
82 data_len = buffer->len;
83 packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
84 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
85 packetdata.src_id = conn->local_id_data;
86 packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
87 packetdata.src_id_type = SILC_ID_CLIENT;
88 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
89 packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
90 packetdata.dst_id_type = SILC_ID_CLIENT;
91 data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
92 packetdata.src_id_len +
93 packetdata.dst_id_len);
94 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
95 packetdata.src_id_len + packetdata.dst_id_len;
96 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
97 packetdata.src_id_len +
98 packetdata.dst_id_len), block_len, packetdata.padlen);
100 /* Create the outgoing packet */
101 if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
102 data, data_len, (const SilcBuffer)&packet)) {
103 SILC_LOG_ERROR(("Error assembling packet"));
107 /* Encrypt the header and padding of the packet. */
108 silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
109 (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
110 packetdata.src_id_len + packetdata.dst_id_len +
113 SILC_LOG_HEXDUMP(("Private message packet, len %d", packet.len),
114 packet.data, packet.len);
116 /* Now actually send the packet */
117 silc_client_packet_send_real(client, sock, force_send);
119 /* Check for mandatory rekey */
120 if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD)
121 silc_schedule_task_add(client->schedule, sock->sock,
122 silc_client_rekey_callback, sock, 0, 1,
123 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
125 silc_free(packetdata.dst_id);
128 silc_buffer_free(buffer);
131 static void silc_client_private_message_cb(SilcClient client,
132 SilcClientConnection conn,
133 SilcClientEntry *clients,
134 SilcUInt32 clients_count,
137 SilcPacketContext *packet = (SilcPacketContext *)context;
140 silc_packet_context_free(packet);
144 silc_client_private_message(client, conn->sock, packet);
145 silc_packet_context_free(packet);
148 /* Private message received. This processes the private message and
149 finally displays it on the screen. */
151 void silc_client_private_message(SilcClient client,
152 SilcSocketConnection sock,
153 SilcPacketContext *packet)
155 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
156 SilcPrivateMessagePayload payload = NULL;
157 SilcClientID *remote_id = NULL;
158 SilcClientEntry remote_client;
159 SilcMessageFlags flags;
160 unsigned char *message;
161 SilcUInt32 message_len;
162 SilcCipher cipher = NULL;
163 SilcHmac hmac = NULL;
165 if (packet->src_id_type != SILC_ID_CLIENT)
168 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
173 /* Check whether we know this client already */
174 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
175 if (!remote_client || !remote_client->nickname) {
177 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
178 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
181 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
182 remote_client->resolve_cmd_ident = conn->cmd_ident + 1;
185 /* Resolve the client info */
186 silc_client_get_client_by_id_resolve(client, conn, remote_id, NULL,
187 silc_client_private_message_cb,
188 silc_packet_context_dup(packet));
192 cipher = remote_client->receive_key;
193 hmac = remote_client->hmac_receive;
194 if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher && !hmac) {
195 silc_free(remote_id);
199 /* Parse the payload and decrypt it also if private message key is set */
200 payload = silc_private_message_payload_parse(packet->buffer->data,
204 silc_free(remote_id);
208 flags = silc_private_message_get_flags(payload);
210 /* Pass the private message to application */
211 message = silc_private_message_get_message(payload, &message_len);
212 client->internal->ops->private_message(client, conn, remote_client, flags,
213 message, message_len);
215 /* See if we are away (gone). If we are away we will reply to the
216 sender with the set away message. */
217 if (conn->internal->away && conn->internal->away->away &&
218 !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
219 /* If it's me, ignore */
220 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
223 /* Send the away message */
224 silc_client_send_private_message(client, conn, remote_client,
225 SILC_MESSAGE_FLAG_AUTOREPLY |
226 SILC_MESSAGE_FLAG_NOREPLY,
227 conn->internal->away->away,
228 strlen(conn->internal->away->away), TRUE);
233 silc_private_message_payload_free(payload);
234 silc_free(remote_id);
237 /* Function that actually employes the received private message key */
239 static void silc_client_private_message_key_cb(SilcClient client,
240 SilcClientConnection conn,
241 SilcClientEntry *clients,
242 SilcUInt32 clients_count,
245 SilcPacketContext *packet = (SilcPacketContext *)context;
248 unsigned char *cipher = NULL, *hmac = NULL;
254 /* Parse the private message key payload */
255 ret = silc_buffer_unformat(packet->buffer,
256 SILC_STR_UI16_NSTRING(&key, &key_len),
257 SILC_STR_UI16_STRING_ALLOC(&cipher),
258 SILC_STR_UI16_STRING_ALLOC(&hmac),
263 if (key_len > packet->buffer->len)
266 /* Now take the key in use */
267 if (!silc_client_add_private_message_key(client, conn, clients[0],
268 cipher, hmac, key, key_len,
272 /* Print some info for application */
273 client->internal->ops->say(
274 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
275 "Received private message key from %s%s%s %s%s%s",
276 clients[0]->nickname,
277 clients[0]->server ? "@" : "",
278 clients[0]->server ? clients[0]->server : "",
279 clients[0]->username ? "(" : "",
280 clients[0]->username ? clients[0]->username : "",
281 clients[0]->username ? ")" : "");
286 silc_packet_context_free(packet);
289 /* Processes incoming Private Message Key payload. The libary always
290 accepts the key and takes it into use. */
292 void silc_client_private_message_key(SilcClient client,
293 SilcSocketConnection sock,
294 SilcPacketContext *packet)
296 SilcClientID *remote_id;
298 if (packet->src_id_type != SILC_ID_CLIENT)
301 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
306 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
308 silc_client_private_message_key_cb,
309 silc_packet_context_dup(packet));
310 silc_free(remote_id);
313 /* Adds private message key to the client library. The key will be used to
314 encrypt all private message between the client and the remote client
315 indicated by the `client_entry'. If the `key' is NULL and the boolean
316 value `generate_key' is TRUE the library will generate random key.
317 The `key' maybe for example pre-shared-key, passphrase or similar.
318 The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure
319 that the requirements of the SILC protocol are met. The API, however,
320 allows to allocate any cipher and HMAC.
322 If `responder' is TRUE then the sending and receiving keys will be
323 set according the client being the receiver of the private key. If
324 FALSE the client is being the sender (or negotiator) of the private
327 It is not necessary to set key for normal private message usage. If the
328 key is not set then the private messages are encrypted using normal
329 session keys. Setting the private key, however, increases the security.
331 Returns FALSE if the key is already set for the `client_entry', TRUE
334 bool silc_client_add_private_message_key(SilcClient client,
335 SilcClientConnection conn,
336 SilcClientEntry client_entry,
344 unsigned char private_key[32];
347 SilcSKEKeyMaterial *keymat;
349 assert(client && client_entry);
351 /* Return FALSE if key already set */
352 if (client_entry->send_key && client_entry->receive_key)
356 cipher = SILC_DEFAULT_CIPHER;
358 hmac = SILC_DEFAULT_HMAC;
360 /* Check the requested cipher and HMAC */
361 if (!silc_cipher_is_supported(cipher))
363 if (!silc_hmac_is_supported(hmac))
366 /* Generate key if not provided */
367 if (generate_key == TRUE) {
369 for (i = 0; i < len; i++)
370 private_key[i] = silc_rng_get_byte_fast(client->rng);
373 client_entry->generated = TRUE;
377 client_entry->key = silc_memdup(key, key_len);
378 client_entry->key_len = key_len;
380 /* Produce the key material as the protocol defines */
381 keymat = silc_calloc(1, sizeof(*keymat));
382 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
383 client->md5hash, keymat)
384 != SILC_SKE_STATUS_OK)
387 /* Allocate the cipher and HMAC */
388 silc_cipher_alloc(cipher, &client_entry->send_key);
389 silc_cipher_alloc(cipher, &client_entry->receive_key);
390 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
391 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
394 if (responder == TRUE) {
395 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
396 keymat->enc_key_len);
397 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
398 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
399 keymat->enc_key_len);
400 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
401 silc_hmac_set_key(client_entry->hmac_send, keymat->receive_hmac_key,
402 keymat->hmac_key_len);
403 silc_hmac_set_key(client_entry->hmac_receive, keymat->send_hmac_key,
404 keymat->hmac_key_len);
406 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
407 keymat->enc_key_len);
408 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
409 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
410 keymat->enc_key_len);
411 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
412 silc_hmac_set_key(client_entry->hmac_send, keymat->send_hmac_key,
413 keymat->hmac_key_len);
414 silc_hmac_set_key(client_entry->hmac_receive, keymat->receive_hmac_key,
415 keymat->hmac_key_len);
418 /* Free the key material */
419 silc_ske_free_key_material(keymat);
424 /* Same as above but takes the key material from the SKE key material
425 structure. This structure is received if the application uses the
426 silc_client_send_key_agreement to negotiate the key material. The
427 `cipher' and `hmac' SHOULD be provided as it is negotiated also in
430 bool silc_client_add_private_message_key_ske(SilcClient client,
431 SilcClientConnection conn,
432 SilcClientEntry client_entry,
435 SilcSKEKeyMaterial *key,
438 assert(client && client_entry);
440 /* Return FALSE if key already set */
441 if (client_entry->send_key && client_entry->receive_key)
445 cipher = SILC_DEFAULT_CIPHER;
447 hmac = SILC_DEFAULT_HMAC;
449 /* Check the requested cipher and HMAC */
450 if (!silc_cipher_is_supported(cipher))
452 if (!silc_hmac_is_supported(hmac))
455 /* Allocate the cipher and HMAC */
456 silc_cipher_alloc(cipher, &client_entry->send_key);
457 silc_cipher_alloc(cipher, &client_entry->receive_key);
458 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
459 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
462 if (responder == TRUE) {
463 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
465 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
466 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
468 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
469 silc_hmac_set_key(client_entry->hmac_send, key->receive_hmac_key,
471 silc_hmac_set_key(client_entry->hmac_receive, key->send_hmac_key,
474 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
476 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
477 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
479 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
480 silc_hmac_set_key(client_entry->hmac_send, key->send_hmac_key,
482 silc_hmac_set_key(client_entry->hmac_receive, key->receive_hmac_key,
489 /* Sends private message key payload to the remote client indicated by
490 the `client_entry'. If the `force_send' is TRUE the packet is sent
491 immediately. Returns FALSE if error occurs, TRUE otherwise. The
492 application should call this function after setting the key to the
495 Note that the key sent using this function is sent to the remote client
496 through the SILC network. The packet is protected using normal session
499 bool silc_client_send_private_message_key(SilcClient client,
500 SilcClientConnection conn,
501 SilcClientEntry client_entry,
504 SilcSocketConnection sock;
506 int cipher_len, hmac_len;
507 const char *cipher, *hmac;
509 assert(client && conn && client_entry);
512 if (!client_entry->send_key || !client_entry->key)
515 SILC_LOG_DEBUG(("Sending private message key"));
517 cipher = silc_cipher_get_name(client_entry->send_key);
518 cipher_len = strlen(cipher);
519 hmac = silc_hmac_get_name(client_entry->hmac_send);
520 hmac_len = strlen(hmac);
522 /* Create private message key payload */
523 buffer = silc_buffer_alloc(2 + client_entry->key_len);
524 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
525 silc_buffer_format(buffer,
526 SILC_STR_UI_SHORT(client_entry->key_len),
527 SILC_STR_UI_XNSTRING(client_entry->key,
528 client_entry->key_len),
529 SILC_STR_UI_SHORT(cipher_len),
530 SILC_STR_UI_XNSTRING(cipher,
532 SILC_STR_UI_SHORT(hmac_len),
533 SILC_STR_UI_XNSTRING(hmac,
537 /* Send the packet */
538 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
539 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
540 buffer->data, buffer->len, force_send);
546 /* Removes the private message from the library. The key won't be used
547 after this to protect the private messages with the remote `client_entry'
548 client. Returns FALSE on error, TRUE otherwise. */
550 bool silc_client_del_private_message_key(SilcClient client,
551 SilcClientConnection conn,
552 SilcClientEntry client_entry)
554 assert(client && client_entry);
556 if (!client_entry->send_key && !client_entry->receive_key)
559 silc_cipher_free(client_entry->send_key);
560 silc_cipher_free(client_entry->receive_key);
562 if (client_entry->key) {
563 memset(client_entry->key, 0, client_entry->key_len);
564 silc_free(client_entry->key);
567 client_entry->send_key = NULL;
568 client_entry->receive_key = NULL;
569 client_entry->key = NULL;
574 /* Returns array of set private message keys associated to the connection
575 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
576 count to the `key_count' argument. The array must be freed by the caller
577 by calling the silc_client_free_private_message_keys function. Note:
578 the keys returned in the array is in raw format. It might not be desired
579 to show the keys as is. The application might choose not to show the keys
580 at all or to show the fingerprints of the keys. */
582 SilcPrivateMessageKeys
583 silc_client_list_private_message_keys(SilcClient client,
584 SilcClientConnection conn,
585 SilcUInt32 *key_count)
587 SilcPrivateMessageKeys keys;
588 SilcUInt32 count = 0;
589 SilcIDCacheEntry id_cache;
590 SilcIDCacheList list;
591 SilcClientEntry entry;
593 assert(client && conn);
595 if (!silc_idcache_get_all(conn->internal->client_cache, &list))
598 if (!silc_idcache_list_count(list)) {
599 silc_idcache_list_free(list);
603 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
605 silc_idcache_list_first(list, &id_cache);
607 entry = (SilcClientEntry)id_cache->context;
609 if (entry->send_key) {
610 keys[count].client_entry = entry;
611 keys[count].cipher = (char *)silc_cipher_get_name(entry->send_key);
612 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
613 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
617 if (!silc_idcache_list_next(list, &id_cache))
627 /* Frees the SilcPrivateMessageKeys array returned by the function
628 silc_client_list_private_message_keys. */
630 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
631 SilcUInt32 key_count)
636 /* Sets away `message'. The away message may be set when the client's
637 mode is changed to SILC_UMODE_GONE and the client whishes to reply
638 to anyone who sends private message. The `message' will be sent
639 automatically back to the the client who send private message. If
640 away message is already set this replaces the old message with the
641 new one. If `message' is NULL the old away message is removed.
642 The sender may freely free the memory of the `message'. */
644 void silc_client_set_away_message(SilcClient client,
645 SilcClientConnection conn,
648 assert(client && conn);
650 if (!message && conn->internal->away) {
651 silc_free(conn->internal->away->away);
652 silc_free(conn->internal->away);
653 conn->internal->away = NULL;
657 if (!conn->internal->away)
658 conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
659 if (conn->internal->away->away)
660 silc_free(conn->internal->away->away);
661 conn->internal->away->away = strdup(message);