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,
39 unsigned int data_len,
42 SilcSocketConnection sock = conn->sock;
44 SilcPacketContext packetdata;
45 unsigned int nick_len;
49 SILC_LOG_DEBUG(("Sending private message"));
51 /* Create private message payload */
52 nick_len = strlen(conn->nickname);
53 buffer = silc_buffer_alloc(2 + nick_len + data_len);
54 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
55 silc_buffer_format(buffer,
56 SILC_STR_UI_SHORT(nick_len),
57 SILC_STR_UI_XNSTRING(conn->nickname,
59 SILC_STR_UI_XNSTRING(data, data_len),
62 /* If we don't have private message specific key then private messages
63 are just as any normal packet thus call normal packet sending. If
64 the key exist then the encryption process is a bit different and
65 will be done in the rest of this function. */
66 if (!client_entry->send_key) {
67 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
68 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
69 buffer->data, buffer->len, force_send);
73 /* We have private message specific key */
75 /* Get data used in the encryption */
76 cipher = client_entry->send_key;
79 /* Set the packet context pointers. */
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_CLIENT_LEN;
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_CLIENT_LEN;
87 packetdata.dst_id_type = SILC_ID_CLIENT;
88 packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
89 packetdata.src_id_len + packetdata.dst_id_len;
90 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
91 packetdata.src_id_len +
92 packetdata.dst_id_len));
94 /* Prepare outgoing data buffer for packet sending */
95 silc_packet_send_prepare(sock,
96 SILC_PACKET_HEADER_LEN +
97 packetdata.src_id_len +
98 packetdata.dst_id_len,
102 packetdata.buffer = sock->outbuf;
104 /* Encrypt payload of the packet. Encrypt with private message specific
106 cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data,
107 buffer->len, cipher->iv);
109 /* Put the actual encrypted payload data into the buffer. */
110 silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
112 /* Create the outgoing packet */
113 silc_packet_assemble(&packetdata);
115 /* Encrypt the header and padding of the packet. */
116 cipher = conn->send_key;
117 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
118 packetdata.src_id_len + packetdata.dst_id_len +
121 SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
122 sock->outbuf->data, sock->outbuf->len);
124 /* Now actually send the packet */
125 silc_client_packet_send_real(client, sock, force_send);
126 silc_free(packetdata.dst_id);
132 /* Private message received. This processes the private message and
133 finally displays it on the screen. */
135 void silc_client_private_message(SilcClient client,
136 SilcSocketConnection sock,
137 SilcPacketContext *packet)
139 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
140 SilcBuffer buffer = packet->buffer;
141 SilcIDCacheEntry id_cache;
142 SilcClientID *remote_id = NULL;
143 SilcClientEntry remote_client;
144 unsigned short nick_len;
145 unsigned char *nickname, *message = NULL;
148 if (packet->src_id_type != SILC_ID_CLIENT)
152 ret = silc_buffer_unformat(buffer,
153 SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
158 silc_buffer_pull(buffer, 2 + nick_len);
160 message = silc_calloc(buffer->len + 1, sizeof(char));
161 memcpy(message, buffer->data, buffer->len);
163 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
168 /* Check whether we know this client already */
169 if (!silc_idcache_find_by_id_one(conn->client_cache, remote_id,
170 SILC_ID_CLIENT, &id_cache))
172 /* Allocate client entry */
173 remote_client = silc_calloc(1, sizeof(*remote_client));
174 remote_client->id = remote_id;
175 silc_parse_nickname(nickname, &remote_client->nickname,
176 &remote_client->server, &remote_client->num);
178 /* Save the client to cache */
179 silc_idcache_add(conn->client_cache, remote_client->nickname,
180 SILC_ID_CLIENT, remote_client->id, remote_client,
183 remote_client = (SilcClientEntry)id_cache->context;
186 /* Pass the private message to application */
187 client->ops->private_message(client, conn, remote_client, message);
189 /* See if we are away (gone). If we are away we will reply to the
190 sender with the set away message. */
191 if (conn->away && conn->away->away) {
192 /* If it's me, ignore */
193 if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
196 /* Send the away message */
197 silc_client_send_private_message(client, conn, remote_client,
199 strlen(conn->away->away), TRUE);
204 silc_free(remote_id);
207 memset(message, 0, buffer->len);
213 /* Function that actually employes the received private message key */
215 static void silc_client_private_message_key_cb(SilcClient client,
216 SilcClientConnection conn,
217 SilcClientEntry *clients,
218 unsigned int clients_count,
221 SilcPacketContext *packet = (SilcPacketContext *)context;
223 unsigned short key_len;
224 unsigned char *cipher;
230 /* Parse the private message key payload */
231 ret = silc_buffer_unformat(packet->buffer,
232 SILC_STR_UI16_NSTRING(&key, &key_len),
233 SILC_STR_UI16_STRING(&cipher),
238 if (key_len > packet->buffer->len)
241 /* Now take the key in use */
242 if (!silc_client_add_private_message_key(client, conn, clients[0],
243 cipher, key, key_len, FALSE))
246 /* Print some info for application */
247 client->ops->say(client, conn,
248 "Received private message key from %s%s%s %s%s%s",
249 clients[0]->nickname,
250 clients[0]->server ? "@" : "",
251 clients[0]->server ? clients[0]->server : "",
252 clients[0]->username ? "(" : "",
253 clients[0]->username ? clients[0]->username : "",
254 clients[0]->username ? ")" : "");
257 silc_packet_context_free(packet);
260 /* Processes incoming Private Message Key payload. The libary always
261 accepts the key and takes it into use. */
263 void silc_client_private_message_key(SilcClient client,
264 SilcSocketConnection sock,
265 SilcPacketContext *packet)
267 SilcClientID *remote_id;
269 if (packet->src_id_type != SILC_ID_CLIENT)
272 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
277 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
278 silc_client_private_message_key_cb,
279 silc_packet_context_dup(packet));
280 silc_free(remote_id);
283 /* Adds private message key to the client library. The key will be used to
284 encrypt all private message between the client and the remote client
285 indicated by the `client_entry'. If the `key' is NULL and the boolean
286 value `generate_key' is TRUE the library will generate random key.
287 The `key' maybe for example pre-shared-key, passphrase or similar.
288 The `cipher' MAY be provided but SHOULD be NULL to assure that the
289 requirements of the SILC protocol are met. The API, however, allows
290 to allocate any cipher.
292 It is not necessary to set key for normal private message usage. If the
293 key is not set then the private messages are encrypted using normal
294 session keys. Setting the private key, however, increases the security.
296 Returns FALSE if the key is already set for the `client_entry', TRUE
299 int silc_client_add_private_message_key(SilcClient client,
300 SilcClientConnection conn,
301 SilcClientEntry client_entry,
304 unsigned int key_len,
307 unsigned char private_key[32];
310 SilcSKEKeyMaterial *keymat;
312 assert(client_entry);
314 /* Return FALSE if key already set */
315 if (client_entry->send_key && client_entry->receive_key)
319 cipher = "aes-256-cbc";
321 /* Check the requested cipher */
322 if (!silc_cipher_is_supported(cipher))
325 /* Generate key if not provided */
326 if (!key && generate_key == TRUE) {
328 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
331 client_entry->generated = TRUE;
335 client_entry->key = silc_calloc(key_len, sizeof(*client_entry->key));
336 memcpy(client_entry->key, key, key_len);
337 client_entry->key_len = key_len;
339 /* Produce the key material as the protocol defines */
340 keymat = silc_calloc(1, sizeof(*keymat));
341 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
342 client->md5hash, keymat)
343 != SILC_SKE_STATUS_OK)
346 /* Allocate the ciphers */
347 silc_cipher_alloc(cipher, &client_entry->send_key);
348 silc_cipher_alloc(cipher, &client_entry->receive_key);
351 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
352 keymat->enc_key_len);
353 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
354 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
355 keymat->enc_key_len);
356 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
358 /* Free the key material */
359 silc_ske_free_key_material(keymat);
364 /* Same as above but takes the key material from the SKE key material
365 structure. This structure is received if the application uses the
366 silc_client_send_key_agreement to negotiate the key material. The
367 `cipher' SHOULD be provided as it is negotiated also in the SKE
370 int silc_client_add_private_message_key_ske(SilcClient client,
371 SilcClientConnection conn,
372 SilcClientEntry client_entry,
374 SilcSKEKeyMaterial *key)
376 assert(client_entry);
378 /* Return FALSE if key already set */
379 if (client_entry->send_key && client_entry->receive_key)
383 cipher = "aes-256-cbc";
385 /* Check the requested cipher */
386 if (!silc_cipher_is_supported(cipher))
389 /* Allocate the ciphers */
390 silc_cipher_alloc(cipher, &client_entry->send_key);
391 silc_cipher_alloc(cipher, &client_entry->receive_key);
394 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
396 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
397 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
399 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
404 /* Sends private message key payload to the remote client indicated by
405 the `client_entry'. If the `force_send' is TRUE the packet is sent
406 immediately. Returns FALSE if error occurs, TRUE otherwise. The
407 application should call this function after setting the key to the
410 Note that the key sent using this function is sent to the remote client
411 through the SILC network. The packet is protected using normal session
414 int silc_client_send_private_message_key(SilcClient client,
415 SilcClientConnection conn,
416 SilcClientEntry client_entry,
419 SilcSocketConnection sock = conn->sock;
423 if (!client_entry->send_key || !client_entry->key)
426 SILC_LOG_DEBUG(("Sending private message key"));
428 cipher_len = strlen(client_entry->send_key->cipher->name);
430 /* Create private message key payload */
431 buffer = silc_buffer_alloc(2 + client_entry->key_len);
432 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
433 silc_buffer_format(buffer,
434 SILC_STR_UI_SHORT(client_entry->key_len),
435 SILC_STR_UI_XNSTRING(client_entry->key,
436 client_entry->key_len),
437 SILC_STR_UI_SHORT(cipher_len),
438 SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
442 /* Send the packet */
443 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
444 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
445 buffer->data, buffer->len, force_send);
451 /* Removes the private message from the library. The key won't be used
452 after this to protect the private messages with the remote `client_entry'
453 client. Returns FALSE on error, TRUE otherwise. */
455 int silc_client_del_private_message_key(SilcClient client,
456 SilcClientConnection conn,
457 SilcClientEntry client_entry)
459 assert(client_entry);
461 if (!client_entry->send_key && !client_entry->receive_key)
464 silc_cipher_free(client_entry->send_key);
465 silc_cipher_free(client_entry->receive_key);
467 if (client_entry->key) {
468 memset(client_entry->key, 0, client_entry->key_len);
469 silc_free(client_entry->key);
472 client_entry->send_key = NULL;
473 client_entry->receive_key = NULL;
474 client_entry->key = NULL;
479 /* Returns array of set private message keys associated to the connection
480 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
481 count to the `key_count' argument. The array must be freed by the caller
482 by calling the silc_client_free_private_message_keys function. Note:
483 the keys returned in the array is in raw format. It might not be desired
484 to show the keys as is. The application might choose not to show the keys
485 at all or to show the fingerprints of the keys. */
487 SilcPrivateMessageKeys
488 silc_client_list_private_message_keys(SilcClient client,
489 SilcClientConnection conn,
490 unsigned int *key_count)
492 SilcPrivateMessageKeys keys;
493 unsigned int count = 0;
494 SilcIDCacheEntry id_cache;
495 SilcIDCacheList list;
496 SilcClientEntry entry;
498 if (!silc_idcache_find_by_id(conn->client_cache, SILC_ID_CACHE_ANY,
499 SILC_ID_CLIENT, &list))
502 if (!silc_idcache_list_count(list)) {
503 silc_idcache_list_free(list);
507 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
509 silc_idcache_list_first(list, &id_cache);
511 entry = (SilcClientEntry)id_cache->context;
513 if (entry->send_key) {
514 keys[count].client_entry = entry;
515 keys[count].cipher = entry->send_key->cipher->name;
516 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
517 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
521 if (!silc_idcache_list_next(list, &id_cache))
531 /* Frees the SilcPrivateMessageKeys array returned by the function
532 silc_client_list_private_message_keys. */
534 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
535 unsigned int key_count)