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);
58 /* If we don't have private message specific key then private messages
59 are just as any normal packet thus call normal packet sending. If
60 the key exist then the encryption process is a bit different and
61 will be done in the rest of this function. */
62 if (!client_entry->send_key) {
63 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
64 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
65 buffer->data, buffer->len, force_send);
69 /* We have private message specific key */
71 /* Get data used in the encryption */
72 cipher = client_entry->send_key;
73 hmac = conn->hmac_send;
74 block_len = silc_cipher_get_block_len(cipher);
76 /* Set the packet context pointers. */
77 packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
78 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
79 packetdata.src_id = conn->local_id_data;
80 packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
81 packetdata.src_id_type = SILC_ID_CLIENT;
82 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
83 packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
84 packetdata.dst_id_type = SILC_ID_CLIENT;
85 packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
86 packetdata.src_id_len + packetdata.dst_id_len;
87 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
88 packetdata.src_id_len +
89 packetdata.dst_id_len), block_len);
91 /* Prepare outgoing data buffer for packet sending */
92 silc_packet_send_prepare(sock,
93 SILC_PACKET_HEADER_LEN +
94 packetdata.src_id_len +
95 packetdata.dst_id_len,
99 packetdata.buffer = sock->outbuf;
101 /* Put the actual encrypted message payload data into the buffer. */
102 silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
104 /* Create the outgoing packet */
105 silc_packet_assemble(&packetdata, cipher);
107 /* Encrypt the header and padding of the packet. */
108 cipher = conn->send_key;
109 silc_packet_encrypt(cipher, hmac, conn->psn_send++,
110 sock->outbuf, SILC_PACKET_HEADER_LEN +
111 packetdata.src_id_len + packetdata.dst_id_len +
114 SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
115 sock->outbuf->data, sock->outbuf->len);
117 /* Now actually send the packet */
118 silc_client_packet_send_real(client, sock, force_send);
119 silc_free(packetdata.dst_id);
122 silc_buffer_free(buffer);
125 static void silc_client_private_message_cb(SilcClient client,
126 SilcClientConnection conn,
127 SilcClientEntry *clients,
128 SilcUInt32 clients_count,
131 SilcPacketContext *packet = (SilcPacketContext *)context;
134 silc_packet_context_free(packet);
138 silc_client_private_message(client, conn->sock, packet);
139 silc_packet_context_free(packet);
142 /* Private message received. This processes the private message and
143 finally displays it on the screen. */
145 void silc_client_private_message(SilcClient client,
146 SilcSocketConnection sock,
147 SilcPacketContext *packet)
149 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
150 SilcPrivateMessagePayload payload = NULL;
151 SilcClientID *remote_id = NULL;
152 SilcClientEntry remote_client;
153 SilcMessageFlags flags;
155 if (packet->src_id_type != SILC_ID_CLIENT)
158 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
163 /* Check whether we know this client already */
164 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
165 if (!remote_client || !remote_client->nickname) {
167 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
168 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
171 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
174 /* Resolve the client info */
175 silc_client_get_client_by_id_resolve(client, conn, remote_id,
176 silc_client_private_message_cb,
177 silc_packet_context_dup(packet));
181 /* Parse the payload and decrypt it also if private message key is set */
182 payload = silc_private_message_payload_parse(packet->buffer->data,
184 remote_client->receive_key);
186 silc_free(remote_id);
190 flags = silc_private_message_get_flags(payload);
192 /* Pass the private message to application */
193 client->internal->ops->private_message(
194 client, conn, remote_client, flags,
195 silc_private_message_get_message(payload,
198 /* See if we are away (gone). If we are away we will reply to the
199 sender with the set away message. */
200 if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
201 /* If it's me, ignore */
202 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
205 /* Send the away message */
206 silc_client_send_private_message(client, conn, remote_client,
207 SILC_MESSAGE_FLAG_AUTOREPLY |
208 SILC_MESSAGE_FLAG_NOREPLY,
210 strlen(conn->away->away), TRUE);
215 silc_private_message_payload_free(payload);
216 silc_free(remote_id);
219 /* Function that actually employes the received private message key */
221 static void silc_client_private_message_key_cb(SilcClient client,
222 SilcClientConnection conn,
223 SilcClientEntry *clients,
224 SilcUInt32 clients_count,
227 SilcPacketContext *packet = (SilcPacketContext *)context;
230 unsigned char *cipher;
236 /* Parse the private message key payload */
237 ret = silc_buffer_unformat(packet->buffer,
238 SILC_STR_UI16_NSTRING(&key, &key_len),
239 SILC_STR_UI16_STRING(&cipher),
244 if (key_len > packet->buffer->len)
247 /* Now take the key in use */
248 if (!silc_client_add_private_message_key(client, conn, clients[0],
249 cipher, key, key_len, FALSE, TRUE))
252 /* Print some info for application */
253 client->internal->ops->say(
254 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
255 "Received private message key from %s%s%s %s%s%s",
256 clients[0]->nickname,
257 clients[0]->server ? "@" : "",
258 clients[0]->server ? clients[0]->server : "",
259 clients[0]->username ? "(" : "",
260 clients[0]->username ? clients[0]->username : "",
261 clients[0]->username ? ")" : "");
264 silc_packet_context_free(packet);
267 /* Processes incoming Private Message Key payload. The libary always
268 accepts the key and takes it into use. */
270 void silc_client_private_message_key(SilcClient client,
271 SilcSocketConnection sock,
272 SilcPacketContext *packet)
274 SilcClientID *remote_id;
276 if (packet->src_id_type != SILC_ID_CLIENT)
279 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
284 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
285 silc_client_private_message_key_cb,
286 silc_packet_context_dup(packet));
287 silc_free(remote_id);
290 /* Adds private message key to the client library. The key will be used to
291 encrypt all private message between the client and the remote client
292 indicated by the `client_entry'. If the `key' is NULL and the boolean
293 value `generate_key' is TRUE the library will generate random key.
294 The `key' maybe for example pre-shared-key, passphrase or similar.
295 The `cipher' MAY be provided but SHOULD be NULL to assure that the
296 requirements of the SILC protocol are met. The API, however, allows
297 to allocate any cipher.
299 If `responder' is TRUE then the sending and receiving keys will be
300 set according the client being the receiver of the private key. If
301 FALSE the client is being the sender (or negotiator) of the private
304 It is not necessary to set key for normal private message usage. If the
305 key is not set then the private messages are encrypted using normal
306 session keys. Setting the private key, however, increases the security.
308 Returns FALSE if the key is already set for the `client_entry', TRUE
311 int silc_client_add_private_message_key(SilcClient client,
312 SilcClientConnection conn,
313 SilcClientEntry client_entry,
320 unsigned char private_key[32];
323 SilcSKEKeyMaterial *keymat;
325 assert(client_entry);
327 /* Return FALSE if key already set */
328 if (client_entry->send_key && client_entry->receive_key)
332 cipher = SILC_DEFAULT_CIPHER;
334 /* Check the requested cipher */
335 if (!silc_cipher_is_supported(cipher))
338 /* Generate key if not provided */
339 if (generate_key == TRUE) {
341 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
344 client_entry->generated = TRUE;
348 client_entry->key = silc_memdup(key, key_len);
349 client_entry->key_len = key_len;
351 /* Produce the key material as the protocol defines */
352 keymat = silc_calloc(1, sizeof(*keymat));
353 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
354 client->internal->md5hash, keymat)
355 != SILC_SKE_STATUS_OK)
358 /* Allocate the ciphers */
359 silc_cipher_alloc(cipher, &client_entry->send_key);
360 silc_cipher_alloc(cipher, &client_entry->receive_key);
363 if (responder == TRUE) {
364 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
365 keymat->enc_key_len);
366 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
367 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
368 keymat->enc_key_len);
369 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
371 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
372 keymat->enc_key_len);
373 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
374 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
375 keymat->enc_key_len);
376 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
379 /* Free the key material */
380 silc_ske_free_key_material(keymat);
385 /* Same as above but takes the key material from the SKE key material
386 structure. This structure is received if the application uses the
387 silc_client_send_key_agreement to negotiate the key material. The
388 `cipher' SHOULD be provided as it is negotiated also in the SKE
391 int silc_client_add_private_message_key_ske(SilcClient client,
392 SilcClientConnection conn,
393 SilcClientEntry client_entry,
395 SilcSKEKeyMaterial *key,
398 assert(client_entry);
400 /* Return FALSE if key already set */
401 if (client_entry->send_key && client_entry->receive_key)
405 cipher = SILC_DEFAULT_CIPHER;
407 /* Check the requested cipher */
408 if (!silc_cipher_is_supported(cipher))
411 /* Allocate the ciphers */
412 silc_cipher_alloc(cipher, &client_entry->send_key);
413 silc_cipher_alloc(cipher, &client_entry->receive_key);
416 if (responder == TRUE) {
417 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
419 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
420 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
422 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
424 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
426 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
427 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
429 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
435 /* Sends private message key payload to the remote client indicated by
436 the `client_entry'. If the `force_send' is TRUE the packet is sent
437 immediately. Returns FALSE if error occurs, TRUE otherwise. The
438 application should call this function after setting the key to the
441 Note that the key sent using this function is sent to the remote client
442 through the SILC network. The packet is protected using normal session
445 int silc_client_send_private_message_key(SilcClient client,
446 SilcClientConnection conn,
447 SilcClientEntry client_entry,
450 SilcSocketConnection sock = conn->sock;
454 if (!client_entry->send_key || !client_entry->key)
457 SILC_LOG_DEBUG(("Sending private message key"));
459 cipher_len = strlen(client_entry->send_key->cipher->name);
461 /* Create private message key payload */
462 buffer = silc_buffer_alloc(2 + client_entry->key_len);
463 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
464 silc_buffer_format(buffer,
465 SILC_STR_UI_SHORT(client_entry->key_len),
466 SILC_STR_UI_XNSTRING(client_entry->key,
467 client_entry->key_len),
468 SILC_STR_UI_SHORT(cipher_len),
469 SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
473 /* Send the packet */
474 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
475 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
476 buffer->data, buffer->len, force_send);
482 /* Removes the private message from the library. The key won't be used
483 after this to protect the private messages with the remote `client_entry'
484 client. Returns FALSE on error, TRUE otherwise. */
486 int silc_client_del_private_message_key(SilcClient client,
487 SilcClientConnection conn,
488 SilcClientEntry client_entry)
490 assert(client_entry);
492 if (!client_entry->send_key && !client_entry->receive_key)
495 silc_cipher_free(client_entry->send_key);
496 silc_cipher_free(client_entry->receive_key);
498 if (client_entry->key) {
499 memset(client_entry->key, 0, client_entry->key_len);
500 silc_free(client_entry->key);
503 client_entry->send_key = NULL;
504 client_entry->receive_key = NULL;
505 client_entry->key = NULL;
510 /* Returns array of set private message keys associated to the connection
511 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
512 count to the `key_count' argument. The array must be freed by the caller
513 by calling the silc_client_free_private_message_keys function. Note:
514 the keys returned in the array is in raw format. It might not be desired
515 to show the keys as is. The application might choose not to show the keys
516 at all or to show the fingerprints of the keys. */
518 SilcPrivateMessageKeys
519 silc_client_list_private_message_keys(SilcClient client,
520 SilcClientConnection conn,
521 SilcUInt32 *key_count)
523 SilcPrivateMessageKeys keys;
524 SilcUInt32 count = 0;
525 SilcIDCacheEntry id_cache;
526 SilcIDCacheList list;
527 SilcClientEntry entry;
529 if (!silc_idcache_get_all(conn->client_cache, &list))
532 if (!silc_idcache_list_count(list)) {
533 silc_idcache_list_free(list);
537 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
539 silc_idcache_list_first(list, &id_cache);
541 entry = (SilcClientEntry)id_cache->context;
543 if (entry->send_key) {
544 keys[count].client_entry = entry;
545 keys[count].cipher = entry->send_key->cipher->name;
546 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
547 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
551 if (!silc_idcache_list_next(list, &id_cache))
561 /* Frees the SilcPrivateMessageKeys array returned by the function
562 silc_client_list_private_message_keys. */
564 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
565 SilcUInt32 key_count)
570 /* Sets away `message'. The away message may be set when the client's
571 mode is changed to SILC_UMODE_GONE and the client whishes to reply
572 to anyone who sends private message. The `message' will be sent
573 automatically back to the the client who send private message. If
574 away message is already set this replaces the old message with the
575 new one. If `message' is NULL the old away message is removed.
576 The sender may freely free the memory of the `message'. */
578 void silc_client_set_away_message(SilcClient client,
579 SilcClientConnection conn,
582 if (!message && conn->away) {
583 silc_free(conn->away->away);
584 silc_free(conn->away);
590 conn->away = silc_calloc(1, sizeof(*conn->away));
591 if (conn->away->away)
592 silc_free(conn->away->away);
593 conn->away->away = strdup(message);