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 "clientlibincludes.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 = conn->sock;
45 SilcPacketContext packetdata;
49 SILC_LOG_DEBUG(("Sending private message"));
51 /* Encode private message payload */
52 buffer = silc_private_message_payload_encode(flags,
54 client_entry->send_key);
56 /* If we don't have private message specific key then private messages
57 are just as any normal packet thus call normal packet sending. If
58 the key exist then the encryption process is a bit different and
59 will be done in the rest of this function. */
60 if (!client_entry->send_key) {
61 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
62 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
63 buffer->data, buffer->len, force_send);
67 /* We have private message specific key */
69 /* Get data used in the encryption */
70 cipher = client_entry->send_key;
71 hmac = conn->hmac_send;
73 /* Set the packet context pointers. */
74 packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
75 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
76 packetdata.src_id = conn->local_id_data;
77 packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
78 packetdata.src_id_type = SILC_ID_CLIENT;
79 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
80 packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
81 packetdata.dst_id_type = SILC_ID_CLIENT;
82 packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
83 packetdata.src_id_len + packetdata.dst_id_len;
84 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
85 packetdata.src_id_len +
86 packetdata.dst_id_len));
88 /* Prepare outgoing data buffer for packet sending */
89 silc_packet_send_prepare(sock,
90 SILC_PACKET_HEADER_LEN +
91 packetdata.src_id_len +
92 packetdata.dst_id_len,
96 packetdata.buffer = sock->outbuf;
98 /* Put the actual encrypted message payload data into the buffer. */
99 silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
101 /* Create the outgoing packet */
102 silc_packet_assemble(&packetdata);
104 /* Encrypt the header and padding of the packet. */
105 cipher = conn->send_key;
106 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
107 packetdata.src_id_len + packetdata.dst_id_len +
110 SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
111 sock->outbuf->data, sock->outbuf->len);
113 /* Now actually send the packet */
114 silc_client_packet_send_real(client, sock, force_send, FALSE);
115 silc_free(packetdata.dst_id);
118 silc_buffer_free(buffer);
121 static void silc_client_private_message_cb(SilcClient client,
122 SilcClientConnection conn,
123 SilcClientEntry *clients,
124 uint32 clients_count,
127 SilcPacketContext *packet = (SilcPacketContext *)context;
129 silc_client_private_message(client, conn->sock, packet);
130 silc_packet_context_free(packet);
133 /* Private message received. This processes the private message and
134 finally displays it on the screen. */
136 void silc_client_private_message(SilcClient client,
137 SilcSocketConnection sock,
138 SilcPacketContext *packet)
140 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
141 SilcPrivateMessagePayload payload = NULL;
142 SilcIDCacheEntry id_cache;
143 SilcClientID *remote_id = NULL;
144 SilcClientEntry remote_client;
145 SilcMessageFlags flags;
147 if (packet->src_id_type != SILC_ID_CLIENT)
150 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
155 /* Check whether we know this client already */
156 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)remote_id,
158 silc_hash_client_id_compare, NULL,
160 /* Resolve the client info */
161 silc_client_get_client_by_id_resolve(client, conn, remote_id,
162 silc_client_private_message_cb,
163 silc_packet_context_dup(packet));
167 remote_client = (SilcClientEntry)id_cache->context;
169 /* Parse the payload and decrypt it also if private message key is set */
170 payload = silc_private_message_payload_parse(packet->buffer,
171 remote_client->send_key);
173 silc_free(remote_id);
177 flags = silc_private_message_get_flags(payload);
179 /* Pass the private message to application */
180 client->ops->private_message(client, conn, remote_client, flags,
181 silc_private_message_get_message(payload,
184 /* See if we are away (gone). If we are away we will reply to the
185 sender with the set away message. */
186 if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
187 /* If it's me, ignore */
188 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
191 /* Send the away message */
192 silc_client_send_private_message(client, conn, remote_client,
193 SILC_MESSAGE_FLAG_AUTOREPLY |
194 SILC_MESSAGE_FLAG_NOREPLY,
196 strlen(conn->away->away), TRUE);
201 silc_private_message_payload_free(payload);
203 silc_free(remote_id);
206 /* Function that actually employes the received private message key */
208 static void silc_client_private_message_key_cb(SilcClient client,
209 SilcClientConnection conn,
210 SilcClientEntry *clients,
211 uint32 clients_count,
214 SilcPacketContext *packet = (SilcPacketContext *)context;
217 unsigned char *cipher;
223 /* Parse the private message key payload */
224 ret = silc_buffer_unformat(packet->buffer,
225 SILC_STR_UI16_NSTRING(&key, &key_len),
226 SILC_STR_UI16_STRING(&cipher),
231 if (key_len > packet->buffer->len)
234 /* Now take the key in use */
235 if (!silc_client_add_private_message_key(client, conn, clients[0],
236 cipher, key, key_len, FALSE))
239 /* Print some info for application */
240 client->ops->say(client, conn,
241 "Received private message key from %s%s%s %s%s%s",
242 clients[0]->nickname,
243 clients[0]->server ? "@" : "",
244 clients[0]->server ? clients[0]->server : "",
245 clients[0]->username ? "(" : "",
246 clients[0]->username ? clients[0]->username : "",
247 clients[0]->username ? ")" : "");
250 silc_packet_context_free(packet);
253 /* Processes incoming Private Message Key payload. The libary always
254 accepts the key and takes it into use. */
256 void silc_client_private_message_key(SilcClient client,
257 SilcSocketConnection sock,
258 SilcPacketContext *packet)
260 SilcClientID *remote_id;
262 if (packet->src_id_type != SILC_ID_CLIENT)
265 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
270 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
271 silc_client_private_message_key_cb,
272 silc_packet_context_dup(packet));
273 silc_free(remote_id);
276 /* Adds private message key to the client library. The key will be used to
277 encrypt all private message between the client and the remote client
278 indicated by the `client_entry'. If the `key' is NULL and the boolean
279 value `generate_key' is TRUE the library will generate random key.
280 The `key' maybe for example pre-shared-key, passphrase or similar.
281 The `cipher' MAY be provided but SHOULD be NULL to assure that the
282 requirements of the SILC protocol are met. The API, however, allows
283 to allocate any cipher.
285 It is not necessary to set key for normal private message usage. If the
286 key is not set then the private messages are encrypted using normal
287 session keys. Setting the private key, however, increases the security.
289 Returns FALSE if the key is already set for the `client_entry', TRUE
292 int silc_client_add_private_message_key(SilcClient client,
293 SilcClientConnection conn,
294 SilcClientEntry client_entry,
300 unsigned char private_key[32];
303 SilcSKEKeyMaterial *keymat;
305 assert(client_entry);
307 /* Return FALSE if key already set */
308 if (client_entry->send_key && client_entry->receive_key)
312 cipher = "aes-256-cbc";
314 /* Check the requested cipher */
315 if (!silc_cipher_is_supported(cipher))
318 /* Generate key if not provided */
319 if (generate_key == TRUE) {
321 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
324 client_entry->generated = TRUE;
328 client_entry->key = silc_calloc(key_len, sizeof(*client_entry->key));
329 memcpy(client_entry->key, key, key_len);
330 client_entry->key_len = key_len;
332 /* Produce the key material as the protocol defines */
333 keymat = silc_calloc(1, sizeof(*keymat));
334 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
335 client->md5hash, keymat)
336 != SILC_SKE_STATUS_OK)
339 /* Allocate the ciphers */
340 silc_cipher_alloc(cipher, &client_entry->send_key);
341 silc_cipher_alloc(cipher, &client_entry->receive_key);
344 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
345 keymat->enc_key_len);
346 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
347 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
348 keymat->enc_key_len);
349 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
351 /* Free the key material */
352 silc_ske_free_key_material(keymat);
357 /* Same as above but takes the key material from the SKE key material
358 structure. This structure is received if the application uses the
359 silc_client_send_key_agreement to negotiate the key material. The
360 `cipher' SHOULD be provided as it is negotiated also in the SKE
363 int silc_client_add_private_message_key_ske(SilcClient client,
364 SilcClientConnection conn,
365 SilcClientEntry client_entry,
367 SilcSKEKeyMaterial *key)
369 assert(client_entry);
371 /* Return FALSE if key already set */
372 if (client_entry->send_key && client_entry->receive_key)
376 cipher = "aes-256-cbc";
378 /* Check the requested cipher */
379 if (!silc_cipher_is_supported(cipher))
382 /* Allocate the ciphers */
383 silc_cipher_alloc(cipher, &client_entry->send_key);
384 silc_cipher_alloc(cipher, &client_entry->receive_key);
387 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
389 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
390 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
392 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
397 /* Sends private message key payload to the remote client indicated by
398 the `client_entry'. If the `force_send' is TRUE the packet is sent
399 immediately. Returns FALSE if error occurs, TRUE otherwise. The
400 application should call this function after setting the key to the
403 Note that the key sent using this function is sent to the remote client
404 through the SILC network. The packet is protected using normal session
407 int silc_client_send_private_message_key(SilcClient client,
408 SilcClientConnection conn,
409 SilcClientEntry client_entry,
412 SilcSocketConnection sock = conn->sock;
416 if (!client_entry->send_key || !client_entry->key)
419 SILC_LOG_DEBUG(("Sending private message key"));
421 cipher_len = strlen(client_entry->send_key->cipher->name);
423 /* Create private message key payload */
424 buffer = silc_buffer_alloc(2 + client_entry->key_len);
425 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
426 silc_buffer_format(buffer,
427 SILC_STR_UI_SHORT(client_entry->key_len),
428 SILC_STR_UI_XNSTRING(client_entry->key,
429 client_entry->key_len),
430 SILC_STR_UI_SHORT(cipher_len),
431 SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
435 /* Send the packet */
436 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
437 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
438 buffer->data, buffer->len, force_send);
444 /* Removes the private message from the library. The key won't be used
445 after this to protect the private messages with the remote `client_entry'
446 client. Returns FALSE on error, TRUE otherwise. */
448 int silc_client_del_private_message_key(SilcClient client,
449 SilcClientConnection conn,
450 SilcClientEntry client_entry)
452 assert(client_entry);
454 if (!client_entry->send_key && !client_entry->receive_key)
457 silc_cipher_free(client_entry->send_key);
458 silc_cipher_free(client_entry->receive_key);
460 if (client_entry->key) {
461 memset(client_entry->key, 0, client_entry->key_len);
462 silc_free(client_entry->key);
465 client_entry->send_key = NULL;
466 client_entry->receive_key = NULL;
467 client_entry->key = NULL;
472 /* Returns array of set private message keys associated to the connection
473 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
474 count to the `key_count' argument. The array must be freed by the caller
475 by calling the silc_client_free_private_message_keys function. Note:
476 the keys returned in the array is in raw format. It might not be desired
477 to show the keys as is. The application might choose not to show the keys
478 at all or to show the fingerprints of the keys. */
480 SilcPrivateMessageKeys
481 silc_client_list_private_message_keys(SilcClient client,
482 SilcClientConnection conn,
485 SilcPrivateMessageKeys keys;
487 SilcIDCacheEntry id_cache;
488 SilcIDCacheList list;
489 SilcClientEntry entry;
491 if (!silc_idcache_get_all(conn->client_cache, &list))
494 if (!silc_idcache_list_count(list)) {
495 silc_idcache_list_free(list);
499 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
501 silc_idcache_list_first(list, &id_cache);
503 entry = (SilcClientEntry)id_cache->context;
505 if (entry->send_key) {
506 keys[count].client_entry = entry;
507 keys[count].cipher = entry->send_key->cipher->name;
508 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
509 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
513 if (!silc_idcache_list_next(list, &id_cache))
523 /* Frees the SilcPrivateMessageKeys array returned by the function
524 silc_client_list_private_message_keys. */
526 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
532 /* Sets away `message'. The away message may be set when the client's
533 mode is changed to SILC_UMODE_GONE and the client whishes to reply
534 to anyone who sends private message. The `message' will be sent
535 automatically back to the the client who send private message. If
536 away message is already set this replaces the old message with the
537 new one. If `message' is NULL the old away message is removed.
538 The sender may freely free the memory of the `message'. */
540 void silc_client_set_away_message(SilcClient client,
541 SilcClientConnection conn,
544 if (!message && conn->away) {
545 silc_free(conn->away->away);
546 silc_free(conn->away);
552 conn->away = silc_calloc(1, sizeof(*conn->away));
553 if (conn->away->away)
554 silc_free(conn->away->away);
555 conn->away->away = strdup(message);