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_message_payload_encode(flags, data, data_len,
57 !client_entry->send_key ? FALSE :
58 !client_entry->generated,
59 TRUE, client_entry->send_key,
60 client_entry->hmac_send,
61 client->rng, NULL, client->private_key,
66 /* If we don't have private message specific key then private messages
67 are just as any normal packet thus call normal packet sending. If
68 the key exist then the encryption process is a bit different and
69 will be done in the rest of this function. */
70 if (!client_entry->send_key) {
71 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
72 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
73 buffer->data, buffer->len, force_send);
77 /* We have private message specific key */
79 /* Get data used in the encryption */
80 cipher = conn->internal->send_key;
81 hmac = conn->internal->hmac_send;
82 block_len = silc_cipher_get_block_len(cipher);
84 /* Set the packet context pointers. */
86 data_len = buffer->len;
87 packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
88 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
89 packetdata.src_id = conn->local_id_data;
90 packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
91 packetdata.src_id_type = SILC_ID_CLIENT;
92 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
93 packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
94 packetdata.dst_id_type = SILC_ID_CLIENT;
95 data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
96 packetdata.src_id_len +
97 packetdata.dst_id_len);
98 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
99 packetdata.src_id_len + packetdata.dst_id_len;
100 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
101 packetdata.src_id_len +
102 packetdata.dst_id_len), block_len, packetdata.padlen);
104 /* Create the outgoing packet */
105 if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
106 data, data_len, (const SilcBuffer)&packet)) {
107 SILC_LOG_ERROR(("Error assembling packet"));
111 /* Encrypt the header and padding of the packet. */
112 silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
113 (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
114 packetdata.src_id_len + packetdata.dst_id_len +
117 SILC_LOG_HEXDUMP(("Private message packet, len %d", packet.len),
118 packet.data, packet.len);
120 /* Now actually send the packet */
121 silc_client_packet_send_real(client, sock, force_send);
123 /* Check for mandatory rekey */
124 if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD)
125 silc_schedule_task_add(client->schedule, sock->sock,
126 silc_client_rekey_callback, sock, 0, 1,
127 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
129 silc_free(packetdata.dst_id);
132 silc_buffer_free(buffer);
135 static void silc_client_private_message_cb(SilcClient client,
136 SilcClientConnection conn,
137 SilcClientEntry *clients,
138 SilcUInt32 clients_count,
141 SilcPacketContext *packet = (SilcPacketContext *)context;
144 silc_packet_context_free(packet);
148 silc_client_private_message(client, conn->sock, packet);
149 silc_packet_context_free(packet);
152 /* Private message received. This processes the private message and
153 finally displays it on the screen. */
155 void silc_client_private_message(SilcClient client,
156 SilcSocketConnection sock,
157 SilcPacketContext *packet)
159 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
160 SilcMessagePayload payload = NULL;
161 SilcClientID *remote_id = NULL;
162 SilcClientEntry remote_client;
163 SilcMessageFlags flags;
164 unsigned char *message;
165 SilcUInt32 message_len;
166 SilcCipher cipher = NULL;
167 SilcHmac hmac = NULL;
169 if (packet->src_id_type != SILC_ID_CLIENT)
172 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
177 /* Check whether we know this client already */
178 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
179 if (!remote_client || !remote_client->nickname) {
181 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
182 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
185 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
186 remote_client->resolve_cmd_ident = conn->cmd_ident + 1;
189 /* Resolve the client info */
190 silc_client_get_client_by_id_resolve(client, conn, remote_id, NULL,
191 silc_client_private_message_cb,
192 silc_packet_context_dup(packet));
196 cipher = remote_client->receive_key;
197 hmac = remote_client->hmac_receive;
198 if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher && !hmac) {
199 silc_free(remote_id);
203 /* Parse the payload and decrypt it also if private message key is set */
204 payload = silc_message_payload_parse(packet->buffer->data,
205 packet->buffer->len, TRUE,
206 !remote_client->generated,
209 silc_free(remote_id);
213 flags = silc_message_get_flags(payload);
215 /* Pass the private message to application */
216 message = silc_message_get_data(payload, &message_len);
217 client->internal->ops->private_message(client, conn, remote_client, payload,
218 flags, message, message_len);
220 /* See if we are away (gone). If we are away we will reply to the
221 sender with the set away message. */
222 if (conn->internal->away && conn->internal->away->away &&
223 !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
224 /* If it's me, ignore */
225 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
228 /* Send the away message */
229 silc_client_send_private_message(client, conn, remote_client,
230 SILC_MESSAGE_FLAG_AUTOREPLY |
231 SILC_MESSAGE_FLAG_NOREPLY,
232 conn->internal->away->away,
233 strlen(conn->internal->away->away), TRUE);
238 silc_message_payload_free(payload);
239 silc_free(remote_id);
242 /* Function that actually employes the received private message key */
244 static void silc_client_private_message_key_cb(SilcClient client,
245 SilcClientConnection conn,
246 SilcClientEntry *clients,
247 SilcUInt32 clients_count,
250 SilcPacketContext *packet = (SilcPacketContext *)context;
253 unsigned char *cipher = NULL, *hmac = NULL;
259 /* Parse the private message key payload */
260 ret = silc_buffer_unformat(packet->buffer,
261 SILC_STR_UI16_NSTRING(&key, &key_len),
262 SILC_STR_UI16_STRING_ALLOC(&cipher),
263 SILC_STR_UI16_STRING_ALLOC(&hmac),
268 if (key_len > packet->buffer->len)
271 /* Now take the key in use */
272 if (!silc_client_add_private_message_key(client, conn, clients[0],
273 cipher, hmac, key, key_len,
277 /* Print some info for application */
278 client->internal->ops->say(
279 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
280 "Received private message key from %s%s%s %s%s%s",
281 clients[0]->nickname,
282 clients[0]->server ? "@" : "",
283 clients[0]->server ? clients[0]->server : "",
284 clients[0]->username ? "(" : "",
285 clients[0]->username ? clients[0]->username : "",
286 clients[0]->username ? ")" : "");
291 silc_packet_context_free(packet);
294 /* Processes incoming Private Message Key payload. The libary always
295 accepts the key and takes it into use. */
297 void silc_client_private_message_key(SilcClient client,
298 SilcSocketConnection sock,
299 SilcPacketContext *packet)
301 SilcClientID *remote_id;
303 if (packet->src_id_type != SILC_ID_CLIENT)
306 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
311 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
313 silc_client_private_message_key_cb,
314 silc_packet_context_dup(packet));
315 silc_free(remote_id);
318 /* Adds private message key to the client library. The key will be used to
319 encrypt all private message between the client and the remote client
320 indicated by the `client_entry'. If the `key' is NULL and the boolean
321 value `generate_key' is TRUE the library will generate random key.
322 The `key' maybe for example pre-shared-key, passphrase or similar.
323 The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure
324 that the requirements of the SILC protocol are met. The API, however,
325 allows to allocate any cipher and HMAC.
327 If `responder' is TRUE then the sending and receiving keys will be
328 set according the client being the receiver of the private key. If
329 FALSE the client is being the sender (or negotiator) of the private
332 It is not necessary to set key for normal private message usage. If the
333 key is not set then the private messages are encrypted using normal
334 session keys. Setting the private key, however, increases the security.
336 Returns FALSE if the key is already set for the `client_entry', TRUE
339 bool silc_client_add_private_message_key(SilcClient client,
340 SilcClientConnection conn,
341 SilcClientEntry client_entry,
349 unsigned char private_key[32];
352 SilcSKEKeyMaterial *keymat;
354 assert(client && client_entry);
356 /* Return FALSE if key already set */
357 if (client_entry->send_key && client_entry->receive_key)
361 cipher = SILC_DEFAULT_CIPHER;
363 hmac = SILC_DEFAULT_HMAC;
365 /* Check the requested cipher and HMAC */
366 if (!silc_cipher_is_supported(cipher))
368 if (!silc_hmac_is_supported(hmac))
371 /* Generate key if not provided */
372 if (generate_key == TRUE) {
374 for (i = 0; i < len; i++)
375 private_key[i] = silc_rng_get_byte_fast(client->rng);
378 client_entry->generated = TRUE;
382 client_entry->key = silc_memdup(key, key_len);
383 client_entry->key_len = key_len;
385 /* Produce the key material as the protocol defines */
386 keymat = silc_calloc(1, sizeof(*keymat));
387 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
388 client->sha1hash, keymat)
389 != SILC_SKE_STATUS_OK)
392 /* Allocate the cipher and HMAC */
393 silc_cipher_alloc(cipher, &client_entry->send_key);
394 silc_cipher_alloc(cipher, &client_entry->receive_key);
395 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
396 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
399 if (responder == TRUE) {
400 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
401 keymat->enc_key_len);
402 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
403 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
404 keymat->enc_key_len);
405 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
406 silc_hmac_set_key(client_entry->hmac_send, keymat->receive_hmac_key,
407 keymat->hmac_key_len);
408 silc_hmac_set_key(client_entry->hmac_receive, keymat->send_hmac_key,
409 keymat->hmac_key_len);
411 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
412 keymat->enc_key_len);
413 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
414 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
415 keymat->enc_key_len);
416 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
417 silc_hmac_set_key(client_entry->hmac_send, keymat->send_hmac_key,
418 keymat->hmac_key_len);
419 silc_hmac_set_key(client_entry->hmac_receive, keymat->receive_hmac_key,
420 keymat->hmac_key_len);
423 /* Free the key material */
424 silc_ske_free_key_material(keymat);
429 /* Same as above but takes the key material from the SKE key material
430 structure. This structure is received if the application uses the
431 silc_client_send_key_agreement to negotiate the key material. The
432 `cipher' and `hmac' SHOULD be provided as it is negotiated also in
435 bool silc_client_add_private_message_key_ske(SilcClient client,
436 SilcClientConnection conn,
437 SilcClientEntry client_entry,
440 SilcSKEKeyMaterial *key,
443 assert(client && client_entry);
445 /* Return FALSE if key already set */
446 if (client_entry->send_key && client_entry->receive_key)
450 cipher = SILC_DEFAULT_CIPHER;
452 hmac = SILC_DEFAULT_HMAC;
454 /* Check the requested cipher and HMAC */
455 if (!silc_cipher_is_supported(cipher))
457 if (!silc_hmac_is_supported(hmac))
460 client_entry->generated = TRUE;
462 /* Allocate the cipher and HMAC */
463 silc_cipher_alloc(cipher, &client_entry->send_key);
464 silc_cipher_alloc(cipher, &client_entry->receive_key);
465 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
466 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
469 if (responder == TRUE) {
470 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
472 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
473 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
475 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
476 silc_hmac_set_key(client_entry->hmac_send, key->receive_hmac_key,
478 silc_hmac_set_key(client_entry->hmac_receive, key->send_hmac_key,
481 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
483 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
484 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
486 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
487 silc_hmac_set_key(client_entry->hmac_send, key->send_hmac_key,
489 silc_hmac_set_key(client_entry->hmac_receive, key->receive_hmac_key,
496 /* Sends private message key payload to the remote client indicated by
497 the `client_entry'. If the `force_send' is TRUE the packet is sent
498 immediately. Returns FALSE if error occurs, TRUE otherwise. The
499 application should call this function after setting the key to the
502 Note that the key sent using this function is sent to the remote client
503 through the SILC network. The packet is protected using normal session
506 bool silc_client_send_private_message_key(SilcClient client,
507 SilcClientConnection conn,
508 SilcClientEntry client_entry,
511 SilcSocketConnection sock;
513 int cipher_len, hmac_len;
514 const char *cipher, *hmac;
516 assert(client && conn && client_entry);
519 if (!client_entry->send_key || !client_entry->key)
522 SILC_LOG_DEBUG(("Sending private message key"));
524 cipher = silc_cipher_get_name(client_entry->send_key);
525 cipher_len = strlen(cipher);
526 hmac = silc_hmac_get_name(client_entry->hmac_send);
527 hmac_len = strlen(hmac);
529 /* Create private message key payload */
530 buffer = silc_buffer_alloc(2 + client_entry->key_len);
531 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
532 silc_buffer_format(buffer,
533 SILC_STR_UI_SHORT(client_entry->key_len),
534 SILC_STR_UI_XNSTRING(client_entry->key,
535 client_entry->key_len),
536 SILC_STR_UI_SHORT(cipher_len),
537 SILC_STR_UI_XNSTRING(cipher,
539 SILC_STR_UI_SHORT(hmac_len),
540 SILC_STR_UI_XNSTRING(hmac,
544 /* Send the packet */
545 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
546 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
547 buffer->data, buffer->len, force_send);
553 /* Removes the private message from the library. The key won't be used
554 after this to protect the private messages with the remote `client_entry'
555 client. Returns FALSE on error, TRUE otherwise. */
557 bool silc_client_del_private_message_key(SilcClient client,
558 SilcClientConnection conn,
559 SilcClientEntry client_entry)
561 assert(client && client_entry);
563 if (!client_entry->send_key && !client_entry->receive_key)
566 silc_cipher_free(client_entry->send_key);
567 silc_cipher_free(client_entry->receive_key);
569 if (client_entry->key) {
570 memset(client_entry->key, 0, client_entry->key_len);
571 silc_free(client_entry->key);
574 client_entry->send_key = NULL;
575 client_entry->receive_key = NULL;
576 client_entry->key = NULL;
581 /* Returns array of set private message keys associated to the connection
582 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
583 count to the `key_count' argument. The array must be freed by the caller
584 by calling the silc_client_free_private_message_keys function. Note:
585 the keys returned in the array is in raw format. It might not be desired
586 to show the keys as is. The application might choose not to show the keys
587 at all or to show the fingerprints of the keys. */
589 SilcPrivateMessageKeys
590 silc_client_list_private_message_keys(SilcClient client,
591 SilcClientConnection conn,
592 SilcUInt32 *key_count)
594 SilcPrivateMessageKeys keys;
595 SilcUInt32 count = 0;
596 SilcIDCacheEntry id_cache;
597 SilcIDCacheList list;
598 SilcClientEntry entry;
600 assert(client && conn);
602 if (!silc_idcache_get_all(conn->internal->client_cache, &list))
605 if (!silc_idcache_list_count(list)) {
606 silc_idcache_list_free(list);
610 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
612 silc_idcache_list_first(list, &id_cache);
614 entry = (SilcClientEntry)id_cache->context;
616 if (entry->send_key) {
617 keys[count].client_entry = entry;
618 keys[count].cipher = (char *)silc_cipher_get_name(entry->send_key);
619 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
620 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
624 if (!silc_idcache_list_next(list, &id_cache))
634 /* Frees the SilcPrivateMessageKeys array returned by the function
635 silc_client_list_private_message_keys. */
637 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
638 SilcUInt32 key_count)
643 /* Sets away `message'. The away message may be set when the client's
644 mode is changed to SILC_UMODE_GONE and the client whishes to reply
645 to anyone who sends private message. The `message' will be sent
646 automatically back to the the client who send private message. If
647 away message is already set this replaces the old message with the
648 new one. If `message' is NULL the old away message is removed.
649 The sender may freely free the memory of the `message'. */
651 void silc_client_set_away_message(SilcClient client,
652 SilcClientConnection conn,
655 assert(client && conn);
657 if (!message && conn->internal->away) {
658 silc_free(conn->internal->away->away);
659 silc_free(conn->internal->away);
660 conn->internal->away = NULL;
664 if (!conn->internal->away)
665 conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
666 if (conn->internal->away->away)
667 silc_free(conn->internal->away->away);
668 conn->internal->away->away = strdup(message);