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,
64 /* If we don't have private message specific key then private messages
65 are just as any normal packet thus call normal packet sending. If
66 the key exist then the encryption process is a bit different and
67 will be done in the rest of this function. */
68 if (!client_entry->send_key) {
69 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
70 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
71 buffer->data, buffer->len, force_send);
75 /* We have private message specific key */
77 /* Get data used in the encryption */
78 cipher = conn->internal->send_key;
79 hmac = conn->internal->hmac_send;
80 block_len = silc_cipher_get_block_len(cipher);
82 /* Set the packet context pointers. */
84 data_len = buffer->len;
85 packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
86 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
87 packetdata.src_id = conn->local_id_data;
88 packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
89 packetdata.src_id_type = SILC_ID_CLIENT;
90 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
91 packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
92 packetdata.dst_id_type = SILC_ID_CLIENT;
93 data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
94 packetdata.src_id_len +
95 packetdata.dst_id_len);
96 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
97 packetdata.src_id_len + packetdata.dst_id_len;
98 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
99 packetdata.src_id_len +
100 packetdata.dst_id_len), block_len, packetdata.padlen);
102 /* Create the outgoing packet */
103 if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
104 data, data_len, (const SilcBuffer)&packet)) {
105 SILC_LOG_ERROR(("Error assembling packet"));
109 /* Encrypt the header and padding of the packet. */
110 silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
111 (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
112 packetdata.src_id_len + packetdata.dst_id_len +
115 SILC_LOG_HEXDUMP(("Private message packet, len %d", packet.len),
116 packet.data, packet.len);
118 /* Now actually send the packet */
119 silc_client_packet_send_real(client, sock, force_send);
121 /* Check for mandatory rekey */
122 if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD)
123 silc_schedule_task_add(client->schedule, sock->sock,
124 silc_client_rekey_callback, sock, 0, 1,
125 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
127 silc_free(packetdata.dst_id);
130 silc_buffer_free(buffer);
133 static void silc_client_private_message_cb(SilcClient client,
134 SilcClientConnection conn,
135 SilcClientEntry *clients,
136 SilcUInt32 clients_count,
139 SilcPacketContext *packet = (SilcPacketContext *)context;
142 silc_packet_context_free(packet);
146 silc_client_private_message(client, conn->sock, packet);
147 silc_packet_context_free(packet);
150 /* Private message received. This processes the private message and
151 finally displays it on the screen. */
153 void silc_client_private_message(SilcClient client,
154 SilcSocketConnection sock,
155 SilcPacketContext *packet)
157 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
158 SilcMessagePayload payload = NULL;
159 SilcClientID *remote_id = NULL;
160 SilcClientEntry remote_client;
161 SilcMessageFlags flags;
162 unsigned char *message;
163 SilcUInt32 message_len;
164 SilcCipher cipher = NULL;
165 SilcHmac hmac = NULL;
167 if (packet->src_id_type != SILC_ID_CLIENT)
170 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
175 /* Check whether we know this client already */
176 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
177 if (!remote_client || !remote_client->nickname) {
179 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
180 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
183 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
184 remote_client->resolve_cmd_ident = conn->cmd_ident + 1;
187 /* Resolve the client info */
188 silc_client_get_client_by_id_resolve(client, conn, remote_id, NULL,
189 silc_client_private_message_cb,
190 silc_packet_context_dup(packet));
194 cipher = remote_client->receive_key;
195 hmac = remote_client->hmac_receive;
196 if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher && !hmac) {
197 silc_free(remote_id);
201 /* Parse the payload and decrypt it also if private message key is set */
202 payload = silc_message_payload_parse(packet->buffer->data,
203 packet->buffer->len, TRUE,
204 !remote_client->generated,
207 silc_free(remote_id);
211 flags = silc_message_get_flags(payload);
213 /* Pass the private message to application */
214 message = silc_message_get_data(payload, &message_len);
215 client->internal->ops->private_message(client, conn, remote_client, payload,
216 flags, message, message_len);
218 /* See if we are away (gone). If we are away we will reply to the
219 sender with the set away message. */
220 if (conn->internal->away && conn->internal->away->away &&
221 !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
222 /* If it's me, ignore */
223 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
226 /* Send the away message */
227 silc_client_send_private_message(client, conn, remote_client,
228 SILC_MESSAGE_FLAG_AUTOREPLY |
229 SILC_MESSAGE_FLAG_NOREPLY,
230 conn->internal->away->away,
231 strlen(conn->internal->away->away), TRUE);
236 silc_message_payload_free(payload);
237 silc_free(remote_id);
240 /* Function that actually employes the received private message key */
242 static void silc_client_private_message_key_cb(SilcClient client,
243 SilcClientConnection conn,
244 SilcClientEntry *clients,
245 SilcUInt32 clients_count,
248 SilcPacketContext *packet = (SilcPacketContext *)context;
251 unsigned char *cipher = NULL, *hmac = NULL;
257 /* Parse the private message key payload */
258 ret = silc_buffer_unformat(packet->buffer,
259 SILC_STR_UI16_NSTRING(&key, &key_len),
260 SILC_STR_UI16_STRING_ALLOC(&cipher),
261 SILC_STR_UI16_STRING_ALLOC(&hmac),
266 if (key_len > packet->buffer->len)
269 /* Now take the key in use */
270 if (!silc_client_add_private_message_key(client, conn, clients[0],
271 cipher, hmac, key, key_len,
275 /* Print some info for application */
276 client->internal->ops->say(
277 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
278 "Received private message key from %s%s%s %s%s%s",
279 clients[0]->nickname,
280 clients[0]->server ? "@" : "",
281 clients[0]->server ? clients[0]->server : "",
282 clients[0]->username ? "(" : "",
283 clients[0]->username ? clients[0]->username : "",
284 clients[0]->username ? ")" : "");
289 silc_packet_context_free(packet);
292 /* Processes incoming Private Message Key payload. The libary always
293 accepts the key and takes it into use. */
295 void silc_client_private_message_key(SilcClient client,
296 SilcSocketConnection sock,
297 SilcPacketContext *packet)
299 SilcClientID *remote_id;
301 if (packet->src_id_type != SILC_ID_CLIENT)
304 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
309 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
311 silc_client_private_message_key_cb,
312 silc_packet_context_dup(packet));
313 silc_free(remote_id);
316 /* Adds private message key to the client library. The key will be used to
317 encrypt all private message between the client and the remote client
318 indicated by the `client_entry'. If the `key' is NULL and the boolean
319 value `generate_key' is TRUE the library will generate random key.
320 The `key' maybe for example pre-shared-key, passphrase or similar.
321 The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure
322 that the requirements of the SILC protocol are met. The API, however,
323 allows to allocate any cipher and HMAC.
325 If `responder' is TRUE then the sending and receiving keys will be
326 set according the client being the receiver of the private key. If
327 FALSE the client is being the sender (or negotiator) of the private
330 It is not necessary to set key for normal private message usage. If the
331 key is not set then the private messages are encrypted using normal
332 session keys. Setting the private key, however, increases the security.
334 Returns FALSE if the key is already set for the `client_entry', TRUE
337 bool silc_client_add_private_message_key(SilcClient client,
338 SilcClientConnection conn,
339 SilcClientEntry client_entry,
347 unsigned char private_key[32];
350 SilcSKEKeyMaterial *keymat;
352 assert(client && client_entry);
354 /* Return FALSE if key already set */
355 if (client_entry->send_key && client_entry->receive_key)
359 cipher = SILC_DEFAULT_CIPHER;
361 hmac = SILC_DEFAULT_HMAC;
363 /* Check the requested cipher and HMAC */
364 if (!silc_cipher_is_supported(cipher))
366 if (!silc_hmac_is_supported(hmac))
369 /* Generate key if not provided */
370 if (generate_key == TRUE) {
372 for (i = 0; i < len; i++)
373 private_key[i] = silc_rng_get_byte_fast(client->rng);
376 client_entry->generated = TRUE;
380 client_entry->key = silc_memdup(key, key_len);
381 client_entry->key_len = key_len;
383 /* Produce the key material as the protocol defines */
384 keymat = silc_calloc(1, sizeof(*keymat));
385 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
386 client->sha1hash, keymat)
387 != SILC_SKE_STATUS_OK)
390 /* Allocate the cipher and HMAC */
391 silc_cipher_alloc(cipher, &client_entry->send_key);
392 silc_cipher_alloc(cipher, &client_entry->receive_key);
393 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
394 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
397 if (responder == TRUE) {
398 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
399 keymat->enc_key_len);
400 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
401 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
402 keymat->enc_key_len);
403 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
404 silc_hmac_set_key(client_entry->hmac_send, keymat->receive_hmac_key,
405 keymat->hmac_key_len);
406 silc_hmac_set_key(client_entry->hmac_receive, keymat->send_hmac_key,
407 keymat->hmac_key_len);
409 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
410 keymat->enc_key_len);
411 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
412 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
413 keymat->enc_key_len);
414 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
415 silc_hmac_set_key(client_entry->hmac_send, keymat->send_hmac_key,
416 keymat->hmac_key_len);
417 silc_hmac_set_key(client_entry->hmac_receive, keymat->receive_hmac_key,
418 keymat->hmac_key_len);
421 /* Free the key material */
422 silc_ske_free_key_material(keymat);
427 /* Same as above but takes the key material from the SKE key material
428 structure. This structure is received if the application uses the
429 silc_client_send_key_agreement to negotiate the key material. The
430 `cipher' and `hmac' SHOULD be provided as it is negotiated also in
433 bool silc_client_add_private_message_key_ske(SilcClient client,
434 SilcClientConnection conn,
435 SilcClientEntry client_entry,
438 SilcSKEKeyMaterial *key,
441 assert(client && client_entry);
443 /* Return FALSE if key already set */
444 if (client_entry->send_key && client_entry->receive_key)
448 cipher = SILC_DEFAULT_CIPHER;
450 hmac = SILC_DEFAULT_HMAC;
452 /* Check the requested cipher and HMAC */
453 if (!silc_cipher_is_supported(cipher))
455 if (!silc_hmac_is_supported(hmac))
458 client_entry->generated = TRUE;
460 /* Allocate the cipher and HMAC */
461 silc_cipher_alloc(cipher, &client_entry->send_key);
462 silc_cipher_alloc(cipher, &client_entry->receive_key);
463 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
464 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
467 if (responder == TRUE) {
468 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
470 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
471 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
473 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
474 silc_hmac_set_key(client_entry->hmac_send, key->receive_hmac_key,
476 silc_hmac_set_key(client_entry->hmac_receive, key->send_hmac_key,
479 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
481 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
482 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
484 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
485 silc_hmac_set_key(client_entry->hmac_send, key->send_hmac_key,
487 silc_hmac_set_key(client_entry->hmac_receive, key->receive_hmac_key,
494 /* Sends private message key payload to the remote client indicated by
495 the `client_entry'. If the `force_send' is TRUE the packet is sent
496 immediately. Returns FALSE if error occurs, TRUE otherwise. The
497 application should call this function after setting the key to the
500 Note that the key sent using this function is sent to the remote client
501 through the SILC network. The packet is protected using normal session
504 bool silc_client_send_private_message_key(SilcClient client,
505 SilcClientConnection conn,
506 SilcClientEntry client_entry,
509 SilcSocketConnection sock;
511 int cipher_len, hmac_len;
512 const char *cipher, *hmac;
514 assert(client && conn && client_entry);
517 if (!client_entry->send_key || !client_entry->key)
520 SILC_LOG_DEBUG(("Sending private message key"));
522 cipher = silc_cipher_get_name(client_entry->send_key);
523 cipher_len = strlen(cipher);
524 hmac = silc_hmac_get_name(client_entry->hmac_send);
525 hmac_len = strlen(hmac);
527 /* Create private message key payload */
528 buffer = silc_buffer_alloc(2 + client_entry->key_len);
529 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
530 silc_buffer_format(buffer,
531 SILC_STR_UI_SHORT(client_entry->key_len),
532 SILC_STR_UI_XNSTRING(client_entry->key,
533 client_entry->key_len),
534 SILC_STR_UI_SHORT(cipher_len),
535 SILC_STR_UI_XNSTRING(cipher,
537 SILC_STR_UI_SHORT(hmac_len),
538 SILC_STR_UI_XNSTRING(hmac,
542 /* Send the packet */
543 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
544 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
545 buffer->data, buffer->len, force_send);
551 /* Removes the private message from the library. The key won't be used
552 after this to protect the private messages with the remote `client_entry'
553 client. Returns FALSE on error, TRUE otherwise. */
555 bool silc_client_del_private_message_key(SilcClient client,
556 SilcClientConnection conn,
557 SilcClientEntry client_entry)
559 assert(client && client_entry);
561 if (!client_entry->send_key && !client_entry->receive_key)
564 silc_cipher_free(client_entry->send_key);
565 silc_cipher_free(client_entry->receive_key);
567 if (client_entry->key) {
568 memset(client_entry->key, 0, client_entry->key_len);
569 silc_free(client_entry->key);
572 client_entry->send_key = NULL;
573 client_entry->receive_key = NULL;
574 client_entry->key = NULL;
579 /* Returns array of set private message keys associated to the connection
580 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
581 count to the `key_count' argument. The array must be freed by the caller
582 by calling the silc_client_free_private_message_keys function. Note:
583 the keys returned in the array is in raw format. It might not be desired
584 to show the keys as is. The application might choose not to show the keys
585 at all or to show the fingerprints of the keys. */
587 SilcPrivateMessageKeys
588 silc_client_list_private_message_keys(SilcClient client,
589 SilcClientConnection conn,
590 SilcUInt32 *key_count)
592 SilcPrivateMessageKeys keys;
593 SilcUInt32 count = 0;
594 SilcIDCacheEntry id_cache;
595 SilcIDCacheList list;
596 SilcClientEntry entry;
598 assert(client && conn);
600 if (!silc_idcache_get_all(conn->internal->client_cache, &list))
603 if (!silc_idcache_list_count(list)) {
604 silc_idcache_list_free(list);
608 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
610 silc_idcache_list_first(list, &id_cache);
612 entry = (SilcClientEntry)id_cache->context;
614 if (entry->send_key) {
615 keys[count].client_entry = entry;
616 keys[count].cipher = (char *)silc_cipher_get_name(entry->send_key);
617 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
618 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
622 if (!silc_idcache_list_next(list, &id_cache))
632 /* Frees the SilcPrivateMessageKeys array returned by the function
633 silc_client_list_private_message_keys. */
635 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
636 SilcUInt32 key_count)
641 /* Sets away `message'. The away message may be set when the client's
642 mode is changed to SILC_UMODE_GONE and the client whishes to reply
643 to anyone who sends private message. The `message' will be sent
644 automatically back to the the client who send private message. If
645 away message is already set this replaces the old message with the
646 new one. If `message' is NULL the old away message is removed.
647 The sender may freely free the memory of the `message'. */
649 void silc_client_set_away_message(SilcClient client,
650 SilcClientConnection conn,
653 assert(client && conn);
655 if (!message && conn->internal->away) {
656 silc_free(conn->internal->away->away);
657 silc_free(conn->internal->away);
658 conn->internal->away = NULL;
662 if (!conn->internal->away)
663 conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
664 if (conn->internal->away->away)
665 silc_free(conn->internal->away->away);
666 conn->internal->away->away = strdup(message);