5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 /* This file includes the private message sending and receiving routines
22 and private message key handling routines. */
24 #include "silcincludes.h"
25 #include "silcclient.h"
26 #include "client_internal.h"
28 /* Sends private message to remote client. If private message key has
29 not been set with this client then the message will be encrypted using
30 normal session keys. Private messages are special packets in SILC
31 network hence we need this own function for them. This is similiar
32 to silc_client_packet_send_to_channel except that we send private
33 message. The `data' is the private message. If the `force_send' is
34 TRUE the packet is sent immediately. */
36 void silc_client_send_private_message(SilcClient client,
37 SilcClientConnection conn,
38 SilcClientEntry client_entry,
39 SilcMessageFlags flags,
44 SilcSocketConnection sock = conn->sock;
46 SilcPacketContext packetdata;
51 SILC_LOG_DEBUG(("Sending private message"));
53 /* Encode private message payload */
54 buffer = silc_private_message_payload_encode(flags,
56 client_entry->send_key,
59 /* If we don't have private message specific key then private messages
60 are just as any normal packet thus call normal packet sending. If
61 the key exist then the encryption process is a bit different and
62 will be done in the rest of this function. */
63 if (!client_entry->send_key) {
64 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
65 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
66 buffer->data, buffer->len, force_send);
70 /* We have private message specific key */
72 /* Get data used in the encryption */
73 cipher = client_entry->send_key;
74 hmac = conn->hmac_send;
75 block_len = silc_cipher_get_block_len(cipher);
77 /* Set the packet context pointers. */
79 data_len = buffer->len;
80 packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
81 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
82 packetdata.src_id = conn->local_id_data;
83 packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
84 packetdata.src_id_type = SILC_ID_CLIENT;
85 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
86 packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
87 packetdata.dst_id_type = SILC_ID_CLIENT;
88 data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
89 packetdata.src_id_len +
90 packetdata.dst_id_len);
91 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
92 packetdata.src_id_len + packetdata.dst_id_len;
93 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
94 packetdata.src_id_len +
95 packetdata.dst_id_len), block_len);
97 /* Prepare outgoing data buffer for packet sending */
98 silc_packet_send_prepare(sock,
99 SILC_PACKET_HEADER_LEN +
100 packetdata.src_id_len +
101 packetdata.dst_id_len,
105 packetdata.buffer = sock->outbuf;
107 /* Put the actual encrypted message payload data into the buffer. */
108 silc_buffer_put(sock->outbuf, data, data_len);
110 /* Create the outgoing packet */
111 silc_packet_assemble(&packetdata, cipher);
113 /* Encrypt the header and padding of the packet. */
114 cipher = conn->send_key;
115 silc_packet_encrypt(cipher, hmac, conn->psn_send++,
116 sock->outbuf, SILC_PACKET_HEADER_LEN +
117 packetdata.src_id_len + packetdata.dst_id_len +
120 SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
121 sock->outbuf->data, sock->outbuf->len);
123 /* Now actually send the packet */
124 silc_client_packet_send_real(client, sock, force_send);
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;
161 if (packet->src_id_type != SILC_ID_CLIENT)
164 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
169 /* Check whether we know this client already */
170 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
171 if (!remote_client || !remote_client->nickname) {
173 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
174 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
177 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
180 /* Resolve the client info */
181 silc_client_get_client_by_id_resolve(client, conn, remote_id,
182 silc_client_private_message_cb,
183 silc_packet_context_dup(packet));
187 /* Parse the payload and decrypt it also if private message key is set */
188 payload = silc_private_message_payload_parse(packet->buffer->data,
190 remote_client->receive_key);
192 silc_free(remote_id);
196 flags = silc_private_message_get_flags(payload);
198 /* Pass the private message to application */
199 client->internal->ops->private_message(
200 client, conn, remote_client, flags,
201 silc_private_message_get_message(payload,
204 /* See if we are away (gone). If we are away we will reply to the
205 sender with the set away message. */
206 if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
207 /* If it's me, ignore */
208 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
211 /* Send the away message */
212 silc_client_send_private_message(client, conn, remote_client,
213 SILC_MESSAGE_FLAG_AUTOREPLY |
214 SILC_MESSAGE_FLAG_NOREPLY,
216 strlen(conn->away->away), TRUE);
221 silc_private_message_payload_free(payload);
222 silc_free(remote_id);
225 /* Function that actually employes the received private message key */
227 static void silc_client_private_message_key_cb(SilcClient client,
228 SilcClientConnection conn,
229 SilcClientEntry *clients,
230 SilcUInt32 clients_count,
233 SilcPacketContext *packet = (SilcPacketContext *)context;
236 unsigned char *cipher;
242 /* Parse the private message key payload */
243 ret = silc_buffer_unformat(packet->buffer,
244 SILC_STR_UI16_NSTRING(&key, &key_len),
245 SILC_STR_UI16_STRING(&cipher),
250 if (key_len > packet->buffer->len)
253 /* Now take the key in use */
254 if (!silc_client_add_private_message_key(client, conn, clients[0],
255 cipher, key, key_len, FALSE, TRUE))
258 /* Print some info for application */
259 client->internal->ops->say(
260 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
261 "Received private message key from %s%s%s %s%s%s",
262 clients[0]->nickname,
263 clients[0]->server ? "@" : "",
264 clients[0]->server ? clients[0]->server : "",
265 clients[0]->username ? "(" : "",
266 clients[0]->username ? clients[0]->username : "",
267 clients[0]->username ? ")" : "");
270 silc_packet_context_free(packet);
273 /* Processes incoming Private Message Key payload. The libary always
274 accepts the key and takes it into use. */
276 void silc_client_private_message_key(SilcClient client,
277 SilcSocketConnection sock,
278 SilcPacketContext *packet)
280 SilcClientID *remote_id;
282 if (packet->src_id_type != SILC_ID_CLIENT)
285 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
290 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
291 silc_client_private_message_key_cb,
292 silc_packet_context_dup(packet));
293 silc_free(remote_id);
296 /* Adds private message key to the client library. The key will be used to
297 encrypt all private message between the client and the remote client
298 indicated by the `client_entry'. If the `key' is NULL and the boolean
299 value `generate_key' is TRUE the library will generate random key.
300 The `key' maybe for example pre-shared-key, passphrase or similar.
301 The `cipher' MAY be provided but SHOULD be NULL to assure that the
302 requirements of the SILC protocol are met. The API, however, allows
303 to allocate any cipher.
305 If `responder' is TRUE then the sending and receiving keys will be
306 set according the client being the receiver of the private key. If
307 FALSE the client is being the sender (or negotiator) of the private
310 It is not necessary to set key for normal private message usage. If the
311 key is not set then the private messages are encrypted using normal
312 session keys. Setting the private key, however, increases the security.
314 Returns FALSE if the key is already set for the `client_entry', TRUE
317 int silc_client_add_private_message_key(SilcClient client,
318 SilcClientConnection conn,
319 SilcClientEntry client_entry,
326 unsigned char private_key[32];
329 SilcSKEKeyMaterial *keymat;
331 assert(client_entry);
333 /* Return FALSE if key already set */
334 if (client_entry->send_key && client_entry->receive_key)
338 cipher = SILC_DEFAULT_CIPHER;
340 /* Check the requested cipher */
341 if (!silc_cipher_is_supported(cipher))
344 /* Generate key if not provided */
345 if (generate_key == TRUE) {
347 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
350 client_entry->generated = TRUE;
354 client_entry->key = silc_memdup(key, key_len);
355 client_entry->key_len = key_len;
357 /* Produce the key material as the protocol defines */
358 keymat = silc_calloc(1, sizeof(*keymat));
359 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
360 client->internal->md5hash, keymat)
361 != SILC_SKE_STATUS_OK)
364 /* Allocate the ciphers */
365 silc_cipher_alloc(cipher, &client_entry->send_key);
366 silc_cipher_alloc(cipher, &client_entry->receive_key);
369 if (responder == TRUE) {
370 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
371 keymat->enc_key_len);
372 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
373 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
374 keymat->enc_key_len);
375 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
377 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
378 keymat->enc_key_len);
379 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
380 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
381 keymat->enc_key_len);
382 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
385 /* Free the key material */
386 silc_ske_free_key_material(keymat);
391 /* Same as above but takes the key material from the SKE key material
392 structure. This structure is received if the application uses the
393 silc_client_send_key_agreement to negotiate the key material. The
394 `cipher' SHOULD be provided as it is negotiated also in the SKE
397 int silc_client_add_private_message_key_ske(SilcClient client,
398 SilcClientConnection conn,
399 SilcClientEntry client_entry,
401 SilcSKEKeyMaterial *key,
404 assert(client_entry);
406 /* Return FALSE if key already set */
407 if (client_entry->send_key && client_entry->receive_key)
411 cipher = SILC_DEFAULT_CIPHER;
413 /* Check the requested cipher */
414 if (!silc_cipher_is_supported(cipher))
417 /* Allocate the ciphers */
418 silc_cipher_alloc(cipher, &client_entry->send_key);
419 silc_cipher_alloc(cipher, &client_entry->receive_key);
422 if (responder == TRUE) {
423 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
425 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
426 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
428 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
430 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
432 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
433 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
435 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
441 /* Sends private message key payload to the remote client indicated by
442 the `client_entry'. If the `force_send' is TRUE the packet is sent
443 immediately. Returns FALSE if error occurs, TRUE otherwise. The
444 application should call this function after setting the key to the
447 Note that the key sent using this function is sent to the remote client
448 through the SILC network. The packet is protected using normal session
451 int silc_client_send_private_message_key(SilcClient client,
452 SilcClientConnection conn,
453 SilcClientEntry client_entry,
456 SilcSocketConnection sock = conn->sock;
460 if (!client_entry->send_key || !client_entry->key)
463 SILC_LOG_DEBUG(("Sending private message key"));
465 cipher_len = strlen(client_entry->send_key->cipher->name);
467 /* Create private message key payload */
468 buffer = silc_buffer_alloc(2 + client_entry->key_len);
469 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
470 silc_buffer_format(buffer,
471 SILC_STR_UI_SHORT(client_entry->key_len),
472 SILC_STR_UI_XNSTRING(client_entry->key,
473 client_entry->key_len),
474 SILC_STR_UI_SHORT(cipher_len),
475 SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
479 /* Send the packet */
480 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
481 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
482 buffer->data, buffer->len, force_send);
488 /* Removes the private message from the library. The key won't be used
489 after this to protect the private messages with the remote `client_entry'
490 client. Returns FALSE on error, TRUE otherwise. */
492 int silc_client_del_private_message_key(SilcClient client,
493 SilcClientConnection conn,
494 SilcClientEntry client_entry)
496 assert(client_entry);
498 if (!client_entry->send_key && !client_entry->receive_key)
501 silc_cipher_free(client_entry->send_key);
502 silc_cipher_free(client_entry->receive_key);
504 if (client_entry->key) {
505 memset(client_entry->key, 0, client_entry->key_len);
506 silc_free(client_entry->key);
509 client_entry->send_key = NULL;
510 client_entry->receive_key = NULL;
511 client_entry->key = NULL;
516 /* Returns array of set private message keys associated to the connection
517 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
518 count to the `key_count' argument. The array must be freed by the caller
519 by calling the silc_client_free_private_message_keys function. Note:
520 the keys returned in the array is in raw format. It might not be desired
521 to show the keys as is. The application might choose not to show the keys
522 at all or to show the fingerprints of the keys. */
524 SilcPrivateMessageKeys
525 silc_client_list_private_message_keys(SilcClient client,
526 SilcClientConnection conn,
527 SilcUInt32 *key_count)
529 SilcPrivateMessageKeys keys;
530 SilcUInt32 count = 0;
531 SilcIDCacheEntry id_cache;
532 SilcIDCacheList list;
533 SilcClientEntry entry;
535 if (!silc_idcache_get_all(conn->client_cache, &list))
538 if (!silc_idcache_list_count(list)) {
539 silc_idcache_list_free(list);
543 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
545 silc_idcache_list_first(list, &id_cache);
547 entry = (SilcClientEntry)id_cache->context;
549 if (entry->send_key) {
550 keys[count].client_entry = entry;
551 keys[count].cipher = entry->send_key->cipher->name;
552 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
553 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
557 if (!silc_idcache_list_next(list, &id_cache))
567 /* Frees the SilcPrivateMessageKeys array returned by the function
568 silc_client_list_private_message_keys. */
570 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
571 SilcUInt32 key_count)
576 /* Sets away `message'. The away message may be set when the client's
577 mode is changed to SILC_UMODE_GONE and the client whishes to reply
578 to anyone who sends private message. The `message' will be sent
579 automatically back to the the client who send private message. If
580 away message is already set this replaces the old message with the
581 new one. If `message' is NULL the old away message is removed.
582 The sender may freely free the memory of the `message'. */
584 void silc_client_set_away_message(SilcClient client,
585 SilcClientConnection conn,
588 if (!message && conn->away) {
589 silc_free(conn->away->away);
590 silc_free(conn->away);
596 conn->away = silc_calloc(1, sizeof(*conn->away));
597 if (conn->away->away)
598 silc_free(conn->away->away);
599 conn->away->away = strdup(message);