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. */
78 packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
79 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
80 packetdata.src_id = conn->local_id_data;
81 packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
82 packetdata.src_id_type = SILC_ID_CLIENT;
83 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
84 packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
85 packetdata.dst_id_type = SILC_ID_CLIENT;
86 packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
87 packetdata.src_id_len + packetdata.dst_id_len;
88 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
89 packetdata.src_id_len +
90 packetdata.dst_id_len), block_len);
92 /* Prepare outgoing data buffer for packet sending */
93 silc_packet_send_prepare(sock,
94 SILC_PACKET_HEADER_LEN +
95 packetdata.src_id_len +
96 packetdata.dst_id_len,
100 packetdata.buffer = sock->outbuf;
102 /* Put the actual encrypted message payload data into the buffer. */
103 silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
105 /* Create the outgoing packet */
106 silc_packet_assemble(&packetdata, cipher);
108 /* Encrypt the header and padding of the packet. */
109 cipher = conn->send_key;
110 silc_packet_encrypt(cipher, hmac, conn->psn_send++,
111 sock->outbuf, SILC_PACKET_HEADER_LEN +
112 packetdata.src_id_len + packetdata.dst_id_len +
115 SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
116 sock->outbuf->data, sock->outbuf->len);
118 /* Now actually send the packet */
119 silc_client_packet_send_real(client, sock, force_send);
120 silc_free(packetdata.dst_id);
123 silc_buffer_free(buffer);
126 static void silc_client_private_message_cb(SilcClient client,
127 SilcClientConnection conn,
128 SilcClientEntry *clients,
129 SilcUInt32 clients_count,
132 SilcPacketContext *packet = (SilcPacketContext *)context;
135 silc_packet_context_free(packet);
139 silc_client_private_message(client, conn->sock, packet);
140 silc_packet_context_free(packet);
143 /* Private message received. This processes the private message and
144 finally displays it on the screen. */
146 void silc_client_private_message(SilcClient client,
147 SilcSocketConnection sock,
148 SilcPacketContext *packet)
150 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
151 SilcPrivateMessagePayload payload = NULL;
152 SilcClientID *remote_id = NULL;
153 SilcClientEntry remote_client;
154 SilcMessageFlags flags;
156 if (packet->src_id_type != SILC_ID_CLIENT)
159 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
164 /* Check whether we know this client already */
165 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
166 if (!remote_client || !remote_client->nickname) {
168 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
169 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
172 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
175 /* Resolve the client info */
176 silc_client_get_client_by_id_resolve(client, conn, remote_id,
177 silc_client_private_message_cb,
178 silc_packet_context_dup(packet));
182 /* Parse the payload and decrypt it also if private message key is set */
183 payload = silc_private_message_payload_parse(packet->buffer->data,
185 remote_client->receive_key);
187 silc_free(remote_id);
191 flags = silc_private_message_get_flags(payload);
193 /* Pass the private message to application */
194 client->internal->ops->private_message(
195 client, conn, remote_client, flags,
196 silc_private_message_get_message(payload,
199 /* See if we are away (gone). If we are away we will reply to the
200 sender with the set away message. */
201 if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
202 /* If it's me, ignore */
203 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
206 /* Send the away message */
207 silc_client_send_private_message(client, conn, remote_client,
208 SILC_MESSAGE_FLAG_AUTOREPLY |
209 SILC_MESSAGE_FLAG_NOREPLY,
211 strlen(conn->away->away), TRUE);
216 silc_private_message_payload_free(payload);
217 silc_free(remote_id);
220 /* Function that actually employes the received private message key */
222 static void silc_client_private_message_key_cb(SilcClient client,
223 SilcClientConnection conn,
224 SilcClientEntry *clients,
225 SilcUInt32 clients_count,
228 SilcPacketContext *packet = (SilcPacketContext *)context;
231 unsigned char *cipher;
237 /* Parse the private message key payload */
238 ret = silc_buffer_unformat(packet->buffer,
239 SILC_STR_UI16_NSTRING(&key, &key_len),
240 SILC_STR_UI16_STRING(&cipher),
245 if (key_len > packet->buffer->len)
248 /* Now take the key in use */
249 if (!silc_client_add_private_message_key(client, conn, clients[0],
250 cipher, key, key_len, FALSE, TRUE))
253 /* Print some info for application */
254 client->internal->ops->say(
255 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
256 "Received private message key from %s%s%s %s%s%s",
257 clients[0]->nickname,
258 clients[0]->server ? "@" : "",
259 clients[0]->server ? clients[0]->server : "",
260 clients[0]->username ? "(" : "",
261 clients[0]->username ? clients[0]->username : "",
262 clients[0]->username ? ")" : "");
265 silc_packet_context_free(packet);
268 /* Processes incoming Private Message Key payload. The libary always
269 accepts the key and takes it into use. */
271 void silc_client_private_message_key(SilcClient client,
272 SilcSocketConnection sock,
273 SilcPacketContext *packet)
275 SilcClientID *remote_id;
277 if (packet->src_id_type != SILC_ID_CLIENT)
280 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
285 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
286 silc_client_private_message_key_cb,
287 silc_packet_context_dup(packet));
288 silc_free(remote_id);
291 /* Adds private message key to the client library. The key will be used to
292 encrypt all private message between the client and the remote client
293 indicated by the `client_entry'. If the `key' is NULL and the boolean
294 value `generate_key' is TRUE the library will generate random key.
295 The `key' maybe for example pre-shared-key, passphrase or similar.
296 The `cipher' MAY be provided but SHOULD be NULL to assure that the
297 requirements of the SILC protocol are met. The API, however, allows
298 to allocate any cipher.
300 If `responder' is TRUE then the sending and receiving keys will be
301 set according the client being the receiver of the private key. If
302 FALSE the client is being the sender (or negotiator) of the private
305 It is not necessary to set key for normal private message usage. If the
306 key is not set then the private messages are encrypted using normal
307 session keys. Setting the private key, however, increases the security.
309 Returns FALSE if the key is already set for the `client_entry', TRUE
312 int silc_client_add_private_message_key(SilcClient client,
313 SilcClientConnection conn,
314 SilcClientEntry client_entry,
321 unsigned char private_key[32];
324 SilcSKEKeyMaterial *keymat;
326 assert(client_entry);
328 /* Return FALSE if key already set */
329 if (client_entry->send_key && client_entry->receive_key)
333 cipher = SILC_DEFAULT_CIPHER;
335 /* Check the requested cipher */
336 if (!silc_cipher_is_supported(cipher))
339 /* Generate key if not provided */
340 if (generate_key == TRUE) {
342 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
345 client_entry->generated = TRUE;
349 client_entry->key = silc_memdup(key, key_len);
350 client_entry->key_len = key_len;
352 /* Produce the key material as the protocol defines */
353 keymat = silc_calloc(1, sizeof(*keymat));
354 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
355 client->internal->md5hash, keymat)
356 != SILC_SKE_STATUS_OK)
359 /* Allocate the ciphers */
360 silc_cipher_alloc(cipher, &client_entry->send_key);
361 silc_cipher_alloc(cipher, &client_entry->receive_key);
364 if (responder == TRUE) {
365 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
366 keymat->enc_key_len);
367 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
368 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
369 keymat->enc_key_len);
370 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
372 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
373 keymat->enc_key_len);
374 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
375 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
376 keymat->enc_key_len);
377 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
380 /* Free the key material */
381 silc_ske_free_key_material(keymat);
386 /* Same as above but takes the key material from the SKE key material
387 structure. This structure is received if the application uses the
388 silc_client_send_key_agreement to negotiate the key material. The
389 `cipher' SHOULD be provided as it is negotiated also in the SKE
392 int silc_client_add_private_message_key_ske(SilcClient client,
393 SilcClientConnection conn,
394 SilcClientEntry client_entry,
396 SilcSKEKeyMaterial *key,
399 assert(client_entry);
401 /* Return FALSE if key already set */
402 if (client_entry->send_key && client_entry->receive_key)
406 cipher = SILC_DEFAULT_CIPHER;
408 /* Check the requested cipher */
409 if (!silc_cipher_is_supported(cipher))
412 /* Allocate the ciphers */
413 silc_cipher_alloc(cipher, &client_entry->send_key);
414 silc_cipher_alloc(cipher, &client_entry->receive_key);
417 if (responder == TRUE) {
418 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
420 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
421 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
423 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
425 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
427 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
428 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
430 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
436 /* Sends private message key payload to the remote client indicated by
437 the `client_entry'. If the `force_send' is TRUE the packet is sent
438 immediately. Returns FALSE if error occurs, TRUE otherwise. The
439 application should call this function after setting the key to the
442 Note that the key sent using this function is sent to the remote client
443 through the SILC network. The packet is protected using normal session
446 int silc_client_send_private_message_key(SilcClient client,
447 SilcClientConnection conn,
448 SilcClientEntry client_entry,
451 SilcSocketConnection sock = conn->sock;
455 if (!client_entry->send_key || !client_entry->key)
458 SILC_LOG_DEBUG(("Sending private message key"));
460 cipher_len = strlen(client_entry->send_key->cipher->name);
462 /* Create private message key payload */
463 buffer = silc_buffer_alloc(2 + client_entry->key_len);
464 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
465 silc_buffer_format(buffer,
466 SILC_STR_UI_SHORT(client_entry->key_len),
467 SILC_STR_UI_XNSTRING(client_entry->key,
468 client_entry->key_len),
469 SILC_STR_UI_SHORT(cipher_len),
470 SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
474 /* Send the packet */
475 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
476 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
477 buffer->data, buffer->len, force_send);
483 /* Removes the private message from the library. The key won't be used
484 after this to protect the private messages with the remote `client_entry'
485 client. Returns FALSE on error, TRUE otherwise. */
487 int silc_client_del_private_message_key(SilcClient client,
488 SilcClientConnection conn,
489 SilcClientEntry client_entry)
491 assert(client_entry);
493 if (!client_entry->send_key && !client_entry->receive_key)
496 silc_cipher_free(client_entry->send_key);
497 silc_cipher_free(client_entry->receive_key);
499 if (client_entry->key) {
500 memset(client_entry->key, 0, client_entry->key_len);
501 silc_free(client_entry->key);
504 client_entry->send_key = NULL;
505 client_entry->receive_key = NULL;
506 client_entry->key = NULL;
511 /* Returns array of set private message keys associated to the connection
512 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
513 count to the `key_count' argument. The array must be freed by the caller
514 by calling the silc_client_free_private_message_keys function. Note:
515 the keys returned in the array is in raw format. It might not be desired
516 to show the keys as is. The application might choose not to show the keys
517 at all or to show the fingerprints of the keys. */
519 SilcPrivateMessageKeys
520 silc_client_list_private_message_keys(SilcClient client,
521 SilcClientConnection conn,
522 SilcUInt32 *key_count)
524 SilcPrivateMessageKeys keys;
525 SilcUInt32 count = 0;
526 SilcIDCacheEntry id_cache;
527 SilcIDCacheList list;
528 SilcClientEntry entry;
530 if (!silc_idcache_get_all(conn->client_cache, &list))
533 if (!silc_idcache_list_count(list)) {
534 silc_idcache_list_free(list);
538 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
540 silc_idcache_list_first(list, &id_cache);
542 entry = (SilcClientEntry)id_cache->context;
544 if (entry->send_key) {
545 keys[count].client_entry = entry;
546 keys[count].cipher = entry->send_key->cipher->name;
547 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
548 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
552 if (!silc_idcache_list_next(list, &id_cache))
562 /* Frees the SilcPrivateMessageKeys array returned by the function
563 silc_client_list_private_message_keys. */
565 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
566 SilcUInt32 key_count)
571 /* Sets away `message'. The away message may be set when the client's
572 mode is changed to SILC_UMODE_GONE and the client whishes to reply
573 to anyone who sends private message. The `message' will be sent
574 automatically back to the the client who send private message. If
575 away message is already set this replaces the old message with the
576 new one. If `message' is NULL the old away message is removed.
577 The sender may freely free the memory of the `message'. */
579 void silc_client_set_away_message(SilcClient client,
580 SilcClientConnection conn,
583 if (!message && conn->away) {
584 silc_free(conn->away->away);
585 silc_free(conn->away);
591 conn->away = silc_calloc(1, sizeof(*conn->away));
592 if (conn->away->away)
593 silc_free(conn->away->away);
594 conn->away->away = strdup(message);