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 bool 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);
80 /* We have private message specific key */
82 /* Get data used in the encryption */
83 cipher = conn->internal->send_key;
84 hmac = conn->internal->hmac_send;
85 block_len = silc_cipher_get_block_len(cipher);
87 /* Set the packet context pointers. */
89 data_len = buffer->len;
90 packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
91 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
92 packetdata.src_id = conn->local_id_data;
93 packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
94 packetdata.src_id_type = SILC_ID_CLIENT;
95 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
96 packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
97 packetdata.dst_id_type = SILC_ID_CLIENT;
98 data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
99 packetdata.src_id_len +
100 packetdata.dst_id_len);
101 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
102 packetdata.src_id_len + packetdata.dst_id_len;
103 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
104 packetdata.src_id_len +
105 packetdata.dst_id_len), block_len, packetdata.padlen);
107 /* Create the outgoing packet */
108 if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
109 data, data_len, (const SilcBuffer)&packet)) {
110 SILC_LOG_ERROR(("Error assembling packet"));
114 /* Encrypt the header and padding of the packet. */
115 silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
116 (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
117 packetdata.src_id_len + packetdata.dst_id_len +
120 SILC_LOG_HEXDUMP(("Private message packet, len %d", packet.len),
121 packet.data, packet.len);
123 /* Now actually send the packet */
124 silc_client_packet_send_real(client, sock, force_send);
126 /* Check for mandatory rekey */
127 if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD)
128 silc_schedule_task_add(client->schedule, sock->sock,
129 silc_client_rekey_callback, sock, 0, 1,
130 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
132 silc_free(packetdata.dst_id);
137 silc_buffer_free(buffer);
142 static void silc_client_private_message_cb(SilcClient client,
143 SilcClientConnection conn,
144 SilcClientEntry *clients,
145 SilcUInt32 clients_count,
148 SilcPacketContext *packet = (SilcPacketContext *)context;
151 silc_packet_context_free(packet);
155 silc_client_private_message(client, conn->sock, packet);
156 silc_packet_context_free(packet);
159 /* Private message received. This processes the private message and
160 finally displays it on the screen. */
162 void silc_client_private_message(SilcClient client,
163 SilcSocketConnection sock,
164 SilcPacketContext *packet)
166 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
167 SilcMessagePayload payload = NULL;
168 SilcClientID *remote_id = NULL;
169 SilcClientEntry remote_client;
170 SilcMessageFlags flags;
171 unsigned char *message;
172 SilcUInt32 message_len;
173 SilcCipher cipher = NULL;
174 SilcHmac hmac = NULL;
176 if (packet->src_id_type != SILC_ID_CLIENT)
179 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
184 /* Check whether we know this client already */
185 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
186 if (!remote_client || !remote_client->nickname) {
188 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
189 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
192 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
193 remote_client->resolve_cmd_ident = conn->cmd_ident + 1;
196 /* Resolve the client info */
197 silc_client_get_client_by_id_resolve(client, conn, remote_id, NULL,
198 silc_client_private_message_cb,
199 silc_packet_context_dup(packet));
203 cipher = remote_client->receive_key;
204 hmac = remote_client->hmac_receive;
205 if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher && !hmac) {
206 silc_free(remote_id);
210 /* Parse the payload and decrypt it also if private message key is set */
211 payload = silc_message_payload_parse(packet->buffer->data,
212 packet->buffer->len, TRUE,
213 !remote_client->generated,
216 silc_free(remote_id);
220 flags = silc_message_get_flags(payload);
222 /* Pass the private message to application */
223 message = silc_message_get_data(payload, &message_len);
224 client->internal->ops->private_message(client, conn, remote_client, payload,
225 flags, message, message_len);
227 /* See if we are away (gone). If we are away we will reply to the
228 sender with the set away message. */
229 if (conn->internal->away && conn->internal->away->away &&
230 !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
231 /* If it's me, ignore */
232 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
235 /* Send the away message */
236 silc_client_send_private_message(client, conn, remote_client,
237 SILC_MESSAGE_FLAG_AUTOREPLY |
238 SILC_MESSAGE_FLAG_NOREPLY,
239 conn->internal->away->away,
240 strlen(conn->internal->away->away), TRUE);
245 silc_message_payload_free(payload);
246 silc_free(remote_id);
249 /* Function that actually employes the received private message key */
251 static void silc_client_private_message_key_cb(SilcClient client,
252 SilcClientConnection conn,
253 SilcClientEntry *clients,
254 SilcUInt32 clients_count,
257 SilcPacketContext *packet = (SilcPacketContext *)context;
260 unsigned char *cipher = NULL, *hmac = NULL;
266 /* Parse the private message key payload */
267 ret = silc_buffer_unformat(packet->buffer,
268 SILC_STR_UI16_NSTRING(&key, &key_len),
269 SILC_STR_UI16_STRING_ALLOC(&cipher),
270 SILC_STR_UI16_STRING_ALLOC(&hmac),
275 if (key_len > packet->buffer->len)
278 /* Now take the key in use */
279 if (!silc_client_add_private_message_key(client, conn, clients[0],
280 cipher, hmac, key, key_len,
284 /* Print some info for application */
285 client->internal->ops->say(
286 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
287 "Received private message key from %s%s%s %s%s%s",
288 clients[0]->nickname,
289 clients[0]->server ? "@" : "",
290 clients[0]->server ? clients[0]->server : "",
291 clients[0]->username ? "(" : "",
292 clients[0]->username ? clients[0]->username : "",
293 clients[0]->username ? ")" : "");
298 silc_packet_context_free(packet);
301 /* Processes incoming Private Message Key payload. The libary always
302 accepts the key and takes it into use. */
304 void silc_client_private_message_key(SilcClient client,
305 SilcSocketConnection sock,
306 SilcPacketContext *packet)
308 SilcClientID *remote_id;
310 if (packet->src_id_type != SILC_ID_CLIENT)
313 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
318 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
320 silc_client_private_message_key_cb,
321 silc_packet_context_dup(packet));
322 silc_free(remote_id);
325 /* Adds private message key to the client library. The key will be used to
326 encrypt all private message between the client and the remote client
327 indicated by the `client_entry'. If the `key' is NULL and the boolean
328 value `generate_key' is TRUE the library will generate random key.
329 The `key' maybe for example pre-shared-key, passphrase or similar.
330 The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure
331 that the requirements of the SILC protocol are met. The API, however,
332 allows to allocate any cipher and HMAC.
334 If `responder' is TRUE then the sending and receiving keys will be
335 set according the client being the receiver of the private key. If
336 FALSE the client is being the sender (or negotiator) of the private
339 It is not necessary to set key for normal private message usage. If the
340 key is not set then the private messages are encrypted using normal
341 session keys. Setting the private key, however, increases the security.
343 Returns FALSE if the key is already set for the `client_entry', TRUE
346 bool silc_client_add_private_message_key(SilcClient client,
347 SilcClientConnection conn,
348 SilcClientEntry client_entry,
356 unsigned char private_key[32];
359 SilcSKEKeyMaterial *keymat;
361 assert(client && client_entry);
363 /* Return FALSE if key already set */
364 if (client_entry->send_key && client_entry->receive_key)
368 cipher = SILC_DEFAULT_CIPHER;
370 hmac = SILC_DEFAULT_HMAC;
372 /* Check the requested cipher and HMAC */
373 if (!silc_cipher_is_supported(cipher))
375 if (!silc_hmac_is_supported(hmac))
378 /* Generate key if not provided */
379 if (generate_key == TRUE) {
381 for (i = 0; i < len; i++)
382 private_key[i] = silc_rng_get_byte_fast(client->rng);
385 client_entry->generated = TRUE;
389 client_entry->key = silc_memdup(key, key_len);
390 client_entry->key_len = key_len;
392 /* Produce the key material as the protocol defines */
393 keymat = silc_calloc(1, sizeof(*keymat));
394 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
395 client->sha1hash, keymat)
396 != SILC_SKE_STATUS_OK)
399 /* Allocate the cipher and HMAC */
400 silc_cipher_alloc(cipher, &client_entry->send_key);
401 silc_cipher_alloc(cipher, &client_entry->receive_key);
402 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
403 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
406 if (responder == TRUE) {
407 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
408 keymat->enc_key_len);
409 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
410 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
411 keymat->enc_key_len);
412 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
413 silc_hmac_set_key(client_entry->hmac_send, keymat->receive_hmac_key,
414 keymat->hmac_key_len);
415 silc_hmac_set_key(client_entry->hmac_receive, keymat->send_hmac_key,
416 keymat->hmac_key_len);
418 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
419 keymat->enc_key_len);
420 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
421 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
422 keymat->enc_key_len);
423 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
424 silc_hmac_set_key(client_entry->hmac_send, keymat->send_hmac_key,
425 keymat->hmac_key_len);
426 silc_hmac_set_key(client_entry->hmac_receive, keymat->receive_hmac_key,
427 keymat->hmac_key_len);
430 /* Free the key material */
431 silc_ske_free_key_material(keymat);
436 /* Same as above but takes the key material from the SKE key material
437 structure. This structure is received if the application uses the
438 silc_client_send_key_agreement to negotiate the key material. The
439 `cipher' and `hmac' SHOULD be provided as it is negotiated also in
442 bool silc_client_add_private_message_key_ske(SilcClient client,
443 SilcClientConnection conn,
444 SilcClientEntry client_entry,
447 SilcSKEKeyMaterial *key,
450 assert(client && client_entry);
452 /* Return FALSE if key already set */
453 if (client_entry->send_key && client_entry->receive_key)
457 cipher = SILC_DEFAULT_CIPHER;
459 hmac = SILC_DEFAULT_HMAC;
461 /* Check the requested cipher and HMAC */
462 if (!silc_cipher_is_supported(cipher))
464 if (!silc_hmac_is_supported(hmac))
467 client_entry->generated = TRUE;
469 /* Allocate the cipher and HMAC */
470 silc_cipher_alloc(cipher, &client_entry->send_key);
471 silc_cipher_alloc(cipher, &client_entry->receive_key);
472 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
473 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
476 if (responder == TRUE) {
477 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
479 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
480 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
482 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
483 silc_hmac_set_key(client_entry->hmac_send, key->receive_hmac_key,
485 silc_hmac_set_key(client_entry->hmac_receive, key->send_hmac_key,
488 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
490 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
491 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
493 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
494 silc_hmac_set_key(client_entry->hmac_send, key->send_hmac_key,
496 silc_hmac_set_key(client_entry->hmac_receive, key->receive_hmac_key,
503 /* Sends private message key payload to the remote client indicated by
504 the `client_entry'. If the `force_send' is TRUE the packet is sent
505 immediately. Returns FALSE if error occurs, TRUE otherwise. The
506 application should call this function after setting the key to the
509 Note that the key sent using this function is sent to the remote client
510 through the SILC network. The packet is protected using normal session
513 bool silc_client_send_private_message_key(SilcClient client,
514 SilcClientConnection conn,
515 SilcClientEntry client_entry,
518 SilcSocketConnection sock;
520 int cipher_len, hmac_len;
521 const char *cipher, *hmac;
523 assert(client && conn && client_entry);
526 if (!client_entry->send_key || !client_entry->key)
529 SILC_LOG_DEBUG(("Sending private message key"));
531 cipher = silc_cipher_get_name(client_entry->send_key);
532 cipher_len = strlen(cipher);
533 hmac = silc_hmac_get_name(client_entry->hmac_send);
534 hmac_len = strlen(hmac);
536 /* Create private message key payload */
537 buffer = silc_buffer_alloc(2 + client_entry->key_len);
538 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
539 silc_buffer_format(buffer,
540 SILC_STR_UI_SHORT(client_entry->key_len),
541 SILC_STR_UI_XNSTRING(client_entry->key,
542 client_entry->key_len),
543 SILC_STR_UI_SHORT(cipher_len),
544 SILC_STR_UI_XNSTRING(cipher,
546 SILC_STR_UI_SHORT(hmac_len),
547 SILC_STR_UI_XNSTRING(hmac,
551 /* Send the packet */
552 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
553 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
554 buffer->data, buffer->len, force_send);
560 /* Removes the private message from the library. The key won't be used
561 after this to protect the private messages with the remote `client_entry'
562 client. Returns FALSE on error, TRUE otherwise. */
564 bool silc_client_del_private_message_key(SilcClient client,
565 SilcClientConnection conn,
566 SilcClientEntry client_entry)
568 assert(client && client_entry);
570 if (!client_entry->send_key && !client_entry->receive_key)
573 silc_cipher_free(client_entry->send_key);
574 silc_cipher_free(client_entry->receive_key);
576 if (client_entry->key) {
577 memset(client_entry->key, 0, client_entry->key_len);
578 silc_free(client_entry->key);
581 client_entry->send_key = NULL;
582 client_entry->receive_key = NULL;
583 client_entry->key = NULL;
588 /* Returns array of set private message keys associated to the connection
589 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
590 count to the `key_count' argument. The array must be freed by the caller
591 by calling the silc_client_free_private_message_keys function. Note:
592 the keys returned in the array is in raw format. It might not be desired
593 to show the keys as is. The application might choose not to show the keys
594 at all or to show the fingerprints of the keys. */
596 SilcPrivateMessageKeys
597 silc_client_list_private_message_keys(SilcClient client,
598 SilcClientConnection conn,
599 SilcUInt32 *key_count)
601 SilcPrivateMessageKeys keys;
602 SilcUInt32 count = 0;
603 SilcIDCacheEntry id_cache;
604 SilcIDCacheList list;
605 SilcClientEntry entry;
607 assert(client && conn);
609 if (!silc_idcache_get_all(conn->internal->client_cache, &list))
612 if (!silc_idcache_list_count(list)) {
613 silc_idcache_list_free(list);
617 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
619 silc_idcache_list_first(list, &id_cache);
621 entry = (SilcClientEntry)id_cache->context;
623 if (entry->send_key) {
624 keys[count].client_entry = entry;
625 keys[count].cipher = (char *)silc_cipher_get_name(entry->send_key);
626 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
627 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
631 if (!silc_idcache_list_next(list, &id_cache))
641 /* Frees the SilcPrivateMessageKeys array returned by the function
642 silc_client_list_private_message_keys. */
644 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
645 SilcUInt32 key_count)
650 /* Sets away `message'. The away message may be set when the client's
651 mode is changed to SILC_UMODE_GONE and the client whishes to reply
652 to anyone who sends private message. The `message' will be sent
653 automatically back to the the client who send private message. If
654 away message is already set this replaces the old message with the
655 new one. If `message' is NULL the old away message is removed.
656 The sender may freely free the memory of the `message'. */
658 void silc_client_set_away_message(SilcClient client,
659 SilcClientConnection conn,
662 assert(client && conn);
664 if (!message && conn->internal->away) {
665 silc_free(conn->internal->away->away);
666 silc_free(conn->internal->away);
667 conn->internal->away = NULL;
671 if (!conn->internal->away)
672 conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
673 if (conn->internal->away->away)
674 silc_free(conn->internal->away->away);
675 conn->internal->away->away = strdup(message);