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,
63 /* If we don't have private message specific key then private messages
64 are just as any normal packet thus call normal packet sending. If
65 the key exist then the encryption process is a bit different and
66 will be done in the rest of this function. */
67 if (!client_entry->send_key) {
68 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
69 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
70 buffer->data, buffer->len, force_send);
74 /* We have private message specific key */
76 /* Get data used in the encryption */
77 cipher = conn->internal->send_key;
78 hmac = conn->internal->hmac_send;
79 block_len = silc_cipher_get_block_len(cipher);
81 /* Set the packet context pointers. */
83 data_len = buffer->len;
84 packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
85 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
86 packetdata.src_id = conn->local_id_data;
87 packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
88 packetdata.src_id_type = SILC_ID_CLIENT;
89 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
90 packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
91 packetdata.dst_id_type = SILC_ID_CLIENT;
92 data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
93 packetdata.src_id_len +
94 packetdata.dst_id_len);
95 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
96 packetdata.src_id_len + packetdata.dst_id_len;
97 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
98 packetdata.src_id_len +
99 packetdata.dst_id_len), block_len, packetdata.padlen);
101 /* Create the outgoing packet */
102 if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
103 data, data_len, (const SilcBuffer)&packet)) {
104 SILC_LOG_ERROR(("Error assembling packet"));
108 /* Encrypt the header and padding of the packet. */
109 silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
110 (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
111 packetdata.src_id_len + packetdata.dst_id_len +
114 SILC_LOG_HEXDUMP(("Private message packet, len %d", packet.len),
115 packet.data, packet.len);
117 /* Now actually send the packet */
118 silc_client_packet_send_real(client, sock, force_send);
120 /* Check for mandatory rekey */
121 if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD)
122 silc_schedule_task_add(client->schedule, sock->sock,
123 silc_client_rekey_callback, sock, 0, 1,
124 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
126 silc_free(packetdata.dst_id);
129 silc_buffer_free(buffer);
132 static void silc_client_private_message_cb(SilcClient client,
133 SilcClientConnection conn,
134 SilcClientEntry *clients,
135 SilcUInt32 clients_count,
138 SilcPacketContext *packet = (SilcPacketContext *)context;
141 silc_packet_context_free(packet);
145 silc_client_private_message(client, conn->sock, packet);
146 silc_packet_context_free(packet);
149 /* Private message received. This processes the private message and
150 finally displays it on the screen. */
152 void silc_client_private_message(SilcClient client,
153 SilcSocketConnection sock,
154 SilcPacketContext *packet)
156 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
157 SilcMessagePayload payload = NULL;
158 SilcClientID *remote_id = NULL;
159 SilcClientEntry remote_client;
160 SilcMessageFlags flags;
161 unsigned char *message;
162 SilcUInt32 message_len;
163 SilcCipher cipher = NULL;
164 SilcHmac hmac = NULL;
166 if (packet->src_id_type != SILC_ID_CLIENT)
169 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
174 /* Check whether we know this client already */
175 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
176 if (!remote_client || !remote_client->nickname) {
178 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
179 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
182 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
183 remote_client->resolve_cmd_ident = conn->cmd_ident + 1;
186 /* Resolve the client info */
187 silc_client_get_client_by_id_resolve(client, conn, remote_id, NULL,
188 silc_client_private_message_cb,
189 silc_packet_context_dup(packet));
193 cipher = remote_client->receive_key;
194 hmac = remote_client->hmac_receive;
195 if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher && !hmac) {
196 silc_free(remote_id);
200 /* Parse the payload and decrypt it also if private message key is set */
201 payload = silc_message_payload_parse(packet->buffer->data,
202 packet->buffer->len, TRUE,
203 !remote_client->generated,
206 silc_free(remote_id);
210 flags = silc_message_get_flags(payload);
212 /* Pass the private message to application */
213 message = silc_message_get_data(payload, &message_len);
214 client->internal->ops->private_message(client, conn, remote_client, flags,
215 message, message_len);
217 /* See if we are away (gone). If we are away we will reply to the
218 sender with the set away message. */
219 if (conn->internal->away && conn->internal->away->away &&
220 !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
221 /* If it's me, ignore */
222 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
225 /* Send the away message */
226 silc_client_send_private_message(client, conn, remote_client,
227 SILC_MESSAGE_FLAG_AUTOREPLY |
228 SILC_MESSAGE_FLAG_NOREPLY,
229 conn->internal->away->away,
230 strlen(conn->internal->away->away), TRUE);
235 silc_message_payload_free(payload);
236 silc_free(remote_id);
239 /* Function that actually employes the received private message key */
241 static void silc_client_private_message_key_cb(SilcClient client,
242 SilcClientConnection conn,
243 SilcClientEntry *clients,
244 SilcUInt32 clients_count,
247 SilcPacketContext *packet = (SilcPacketContext *)context;
250 unsigned char *cipher = NULL, *hmac = NULL;
256 /* Parse the private message key payload */
257 ret = silc_buffer_unformat(packet->buffer,
258 SILC_STR_UI16_NSTRING(&key, &key_len),
259 SILC_STR_UI16_STRING_ALLOC(&cipher),
260 SILC_STR_UI16_STRING_ALLOC(&hmac),
265 if (key_len > packet->buffer->len)
268 /* Now take the key in use */
269 if (!silc_client_add_private_message_key(client, conn, clients[0],
270 cipher, hmac, key, key_len,
274 /* Print some info for application */
275 client->internal->ops->say(
276 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
277 "Received private message key from %s%s%s %s%s%s",
278 clients[0]->nickname,
279 clients[0]->server ? "@" : "",
280 clients[0]->server ? clients[0]->server : "",
281 clients[0]->username ? "(" : "",
282 clients[0]->username ? clients[0]->username : "",
283 clients[0]->username ? ")" : "");
288 silc_packet_context_free(packet);
291 /* Processes incoming Private Message Key payload. The libary always
292 accepts the key and takes it into use. */
294 void silc_client_private_message_key(SilcClient client,
295 SilcSocketConnection sock,
296 SilcPacketContext *packet)
298 SilcClientID *remote_id;
300 if (packet->src_id_type != SILC_ID_CLIENT)
303 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
308 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
310 silc_client_private_message_key_cb,
311 silc_packet_context_dup(packet));
312 silc_free(remote_id);
315 /* Adds private message key to the client library. The key will be used to
316 encrypt all private message between the client and the remote client
317 indicated by the `client_entry'. If the `key' is NULL and the boolean
318 value `generate_key' is TRUE the library will generate random key.
319 The `key' maybe for example pre-shared-key, passphrase or similar.
320 The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure
321 that the requirements of the SILC protocol are met. The API, however,
322 allows to allocate any cipher and HMAC.
324 If `responder' is TRUE then the sending and receiving keys will be
325 set according the client being the receiver of the private key. If
326 FALSE the client is being the sender (or negotiator) of the private
329 It is not necessary to set key for normal private message usage. If the
330 key is not set then the private messages are encrypted using normal
331 session keys. Setting the private key, however, increases the security.
333 Returns FALSE if the key is already set for the `client_entry', TRUE
336 bool silc_client_add_private_message_key(SilcClient client,
337 SilcClientConnection conn,
338 SilcClientEntry client_entry,
346 unsigned char private_key[32];
349 SilcSKEKeyMaterial *keymat;
351 assert(client && client_entry);
353 /* Return FALSE if key already set */
354 if (client_entry->send_key && client_entry->receive_key)
358 cipher = SILC_DEFAULT_CIPHER;
360 hmac = SILC_DEFAULT_HMAC;
362 /* Check the requested cipher and HMAC */
363 if (!silc_cipher_is_supported(cipher))
365 if (!silc_hmac_is_supported(hmac))
368 /* Generate key if not provided */
369 if (generate_key == TRUE) {
371 for (i = 0; i < len; i++)
372 private_key[i] = silc_rng_get_byte_fast(client->rng);
375 client_entry->generated = TRUE;
379 client_entry->key = silc_memdup(key, key_len);
380 client_entry->key_len = key_len;
382 /* Produce the key material as the protocol defines */
383 keymat = silc_calloc(1, sizeof(*keymat));
384 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
385 client->md5hash, keymat)
386 != SILC_SKE_STATUS_OK)
389 /* Allocate the cipher and HMAC */
390 silc_cipher_alloc(cipher, &client_entry->send_key);
391 silc_cipher_alloc(cipher, &client_entry->receive_key);
392 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
393 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
396 if (responder == TRUE) {
397 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
398 keymat->enc_key_len);
399 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
400 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
401 keymat->enc_key_len);
402 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
403 silc_hmac_set_key(client_entry->hmac_send, keymat->receive_hmac_key,
404 keymat->hmac_key_len);
405 silc_hmac_set_key(client_entry->hmac_receive, keymat->send_hmac_key,
406 keymat->hmac_key_len);
408 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
409 keymat->enc_key_len);
410 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
411 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
412 keymat->enc_key_len);
413 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
414 silc_hmac_set_key(client_entry->hmac_send, keymat->send_hmac_key,
415 keymat->hmac_key_len);
416 silc_hmac_set_key(client_entry->hmac_receive, keymat->receive_hmac_key,
417 keymat->hmac_key_len);
420 /* Free the key material */
421 silc_ske_free_key_material(keymat);
426 /* Same as above but takes the key material from the SKE key material
427 structure. This structure is received if the application uses the
428 silc_client_send_key_agreement to negotiate the key material. The
429 `cipher' and `hmac' SHOULD be provided as it is negotiated also in
432 bool silc_client_add_private_message_key_ske(SilcClient client,
433 SilcClientConnection conn,
434 SilcClientEntry client_entry,
437 SilcSKEKeyMaterial *key,
440 assert(client && client_entry);
442 /* Return FALSE if key already set */
443 if (client_entry->send_key && client_entry->receive_key)
447 cipher = SILC_DEFAULT_CIPHER;
449 hmac = SILC_DEFAULT_HMAC;
451 /* Check the requested cipher and HMAC */
452 if (!silc_cipher_is_supported(cipher))
454 if (!silc_hmac_is_supported(hmac))
457 client_entry->generated = TRUE;
459 /* Allocate the cipher and HMAC */
460 silc_cipher_alloc(cipher, &client_entry->send_key);
461 silc_cipher_alloc(cipher, &client_entry->receive_key);
462 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
463 silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
466 if (responder == TRUE) {
467 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
469 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
470 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
472 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
473 silc_hmac_set_key(client_entry->hmac_send, key->receive_hmac_key,
475 silc_hmac_set_key(client_entry->hmac_receive, key->send_hmac_key,
478 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
480 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
481 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
483 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
484 silc_hmac_set_key(client_entry->hmac_send, key->send_hmac_key,
486 silc_hmac_set_key(client_entry->hmac_receive, key->receive_hmac_key,
493 /* Sends private message key payload to the remote client indicated by
494 the `client_entry'. If the `force_send' is TRUE the packet is sent
495 immediately. Returns FALSE if error occurs, TRUE otherwise. The
496 application should call this function after setting the key to the
499 Note that the key sent using this function is sent to the remote client
500 through the SILC network. The packet is protected using normal session
503 bool silc_client_send_private_message_key(SilcClient client,
504 SilcClientConnection conn,
505 SilcClientEntry client_entry,
508 SilcSocketConnection sock;
510 int cipher_len, hmac_len;
511 const char *cipher, *hmac;
513 assert(client && conn && client_entry);
516 if (!client_entry->send_key || !client_entry->key)
519 SILC_LOG_DEBUG(("Sending private message key"));
521 cipher = silc_cipher_get_name(client_entry->send_key);
522 cipher_len = strlen(cipher);
523 hmac = silc_hmac_get_name(client_entry->hmac_send);
524 hmac_len = strlen(hmac);
526 /* Create private message key payload */
527 buffer = silc_buffer_alloc(2 + client_entry->key_len);
528 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
529 silc_buffer_format(buffer,
530 SILC_STR_UI_SHORT(client_entry->key_len),
531 SILC_STR_UI_XNSTRING(client_entry->key,
532 client_entry->key_len),
533 SILC_STR_UI_SHORT(cipher_len),
534 SILC_STR_UI_XNSTRING(cipher,
536 SILC_STR_UI_SHORT(hmac_len),
537 SILC_STR_UI_XNSTRING(hmac,
541 /* Send the packet */
542 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
543 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
544 buffer->data, buffer->len, force_send);
550 /* Removes the private message from the library. The key won't be used
551 after this to protect the private messages with the remote `client_entry'
552 client. Returns FALSE on error, TRUE otherwise. */
554 bool silc_client_del_private_message_key(SilcClient client,
555 SilcClientConnection conn,
556 SilcClientEntry client_entry)
558 assert(client && client_entry);
560 if (!client_entry->send_key && !client_entry->receive_key)
563 silc_cipher_free(client_entry->send_key);
564 silc_cipher_free(client_entry->receive_key);
566 if (client_entry->key) {
567 memset(client_entry->key, 0, client_entry->key_len);
568 silc_free(client_entry->key);
571 client_entry->send_key = NULL;
572 client_entry->receive_key = NULL;
573 client_entry->key = NULL;
578 /* Returns array of set private message keys associated to the connection
579 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
580 count to the `key_count' argument. The array must be freed by the caller
581 by calling the silc_client_free_private_message_keys function. Note:
582 the keys returned in the array is in raw format. It might not be desired
583 to show the keys as is. The application might choose not to show the keys
584 at all or to show the fingerprints of the keys. */
586 SilcPrivateMessageKeys
587 silc_client_list_private_message_keys(SilcClient client,
588 SilcClientConnection conn,
589 SilcUInt32 *key_count)
591 SilcPrivateMessageKeys keys;
592 SilcUInt32 count = 0;
593 SilcIDCacheEntry id_cache;
594 SilcIDCacheList list;
595 SilcClientEntry entry;
597 assert(client && conn);
599 if (!silc_idcache_get_all(conn->internal->client_cache, &list))
602 if (!silc_idcache_list_count(list)) {
603 silc_idcache_list_free(list);
607 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
609 silc_idcache_list_first(list, &id_cache);
611 entry = (SilcClientEntry)id_cache->context;
613 if (entry->send_key) {
614 keys[count].client_entry = entry;
615 keys[count].cipher = (char *)silc_cipher_get_name(entry->send_key);
616 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
617 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
621 if (!silc_idcache_list_next(list, &id_cache))
631 /* Frees the SilcPrivateMessageKeys array returned by the function
632 silc_client_list_private_message_keys. */
634 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
635 SilcUInt32 key_count)
640 /* Sets away `message'. The away message may be set when the client's
641 mode is changed to SILC_UMODE_GONE and the client whishes to reply
642 to anyone who sends private message. The `message' will be sent
643 automatically back to the the client who send private message. If
644 away message is already set this replaces the old message with the
645 new one. If `message' is NULL the old away message is removed.
646 The sender may freely free the memory of the `message'. */
648 void silc_client_set_away_message(SilcClient client,
649 SilcClientConnection conn,
652 assert(client && conn);
654 if (!message && conn->internal->away) {
655 silc_free(conn->internal->away->away);
656 silc_free(conn->internal->away);
657 conn->internal->away = NULL;
661 if (!conn->internal->away)
662 conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
663 if (conn->internal->away->away)
664 silc_free(conn->internal->away->away);
665 conn->internal->away->away = strdup(message);