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;
146 if (packet->src_id_type != SILC_ID_CLIENT)
149 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
154 /* Check whether we know this client already */
155 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)remote_id,
157 silc_hash_client_id_compare, NULL,
159 /* Resolve the client info */
160 silc_client_get_client_by_id_resolve(client, conn, remote_id,
161 silc_client_private_message_cb,
162 silc_packet_context_dup(packet));
166 remote_client = (SilcClientEntry)id_cache->context;
168 /* Parse the payload and decrypt it also if private message key is set */
169 payload = silc_private_message_payload_parse(packet->buffer,
170 remote_client->send_key);
172 silc_free(remote_id);
176 /* Pass the private message to application */
177 client->ops->private_message(client, conn, remote_client,
178 silc_private_message_get_flags(payload),
179 silc_private_message_get_message(payload,
182 /* See if we are away (gone). If we are away we will reply to the
183 sender with the set away message. */
184 if (conn->away && conn->away->away) {
185 /* If it's me, ignore */
186 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
189 /* Send the away message */
190 silc_client_send_private_message(client, conn, remote_client,
191 SILC_MESSAGE_FLAG_AUTOREPLY,
193 strlen(conn->away->away), TRUE);
198 silc_private_message_payload_free(payload);
200 silc_free(remote_id);
203 /* Function that actually employes the received private message key */
205 static void silc_client_private_message_key_cb(SilcClient client,
206 SilcClientConnection conn,
207 SilcClientEntry *clients,
208 uint32 clients_count,
211 SilcPacketContext *packet = (SilcPacketContext *)context;
214 unsigned char *cipher;
220 /* Parse the private message key payload */
221 ret = silc_buffer_unformat(packet->buffer,
222 SILC_STR_UI16_NSTRING(&key, &key_len),
223 SILC_STR_UI16_STRING(&cipher),
228 if (key_len > packet->buffer->len)
231 /* Now take the key in use */
232 if (!silc_client_add_private_message_key(client, conn, clients[0],
233 cipher, key, key_len, FALSE))
236 /* Print some info for application */
237 client->ops->say(client, conn,
238 "Received private message key from %s%s%s %s%s%s",
239 clients[0]->nickname,
240 clients[0]->server ? "@" : "",
241 clients[0]->server ? clients[0]->server : "",
242 clients[0]->username ? "(" : "",
243 clients[0]->username ? clients[0]->username : "",
244 clients[0]->username ? ")" : "");
247 silc_packet_context_free(packet);
250 /* Processes incoming Private Message Key payload. The libary always
251 accepts the key and takes it into use. */
253 void silc_client_private_message_key(SilcClient client,
254 SilcSocketConnection sock,
255 SilcPacketContext *packet)
257 SilcClientID *remote_id;
259 if (packet->src_id_type != SILC_ID_CLIENT)
262 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
267 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
268 silc_client_private_message_key_cb,
269 silc_packet_context_dup(packet));
270 silc_free(remote_id);
273 /* Adds private message key to the client library. The key will be used to
274 encrypt all private message between the client and the remote client
275 indicated by the `client_entry'. If the `key' is NULL and the boolean
276 value `generate_key' is TRUE the library will generate random key.
277 The `key' maybe for example pre-shared-key, passphrase or similar.
278 The `cipher' MAY be provided but SHOULD be NULL to assure that the
279 requirements of the SILC protocol are met. The API, however, allows
280 to allocate any cipher.
282 It is not necessary to set key for normal private message usage. If the
283 key is not set then the private messages are encrypted using normal
284 session keys. Setting the private key, however, increases the security.
286 Returns FALSE if the key is already set for the `client_entry', TRUE
289 int silc_client_add_private_message_key(SilcClient client,
290 SilcClientConnection conn,
291 SilcClientEntry client_entry,
297 unsigned char private_key[32];
300 SilcSKEKeyMaterial *keymat;
302 assert(client_entry);
304 /* Return FALSE if key already set */
305 if (client_entry->send_key && client_entry->receive_key)
309 cipher = "aes-256-cbc";
311 /* Check the requested cipher */
312 if (!silc_cipher_is_supported(cipher))
315 /* Generate key if not provided */
316 if (generate_key == TRUE) {
318 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
321 client_entry->generated = TRUE;
325 client_entry->key = silc_calloc(key_len, sizeof(*client_entry->key));
326 memcpy(client_entry->key, key, key_len);
327 client_entry->key_len = key_len;
329 /* Produce the key material as the protocol defines */
330 keymat = silc_calloc(1, sizeof(*keymat));
331 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
332 client->md5hash, keymat)
333 != SILC_SKE_STATUS_OK)
336 /* Allocate the ciphers */
337 silc_cipher_alloc(cipher, &client_entry->send_key);
338 silc_cipher_alloc(cipher, &client_entry->receive_key);
341 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
342 keymat->enc_key_len);
343 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
344 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
345 keymat->enc_key_len);
346 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
348 /* Free the key material */
349 silc_ske_free_key_material(keymat);
354 /* Same as above but takes the key material from the SKE key material
355 structure. This structure is received if the application uses the
356 silc_client_send_key_agreement to negotiate the key material. The
357 `cipher' SHOULD be provided as it is negotiated also in the SKE
360 int silc_client_add_private_message_key_ske(SilcClient client,
361 SilcClientConnection conn,
362 SilcClientEntry client_entry,
364 SilcSKEKeyMaterial *key)
366 assert(client_entry);
368 /* Return FALSE if key already set */
369 if (client_entry->send_key && client_entry->receive_key)
373 cipher = "aes-256-cbc";
375 /* Check the requested cipher */
376 if (!silc_cipher_is_supported(cipher))
379 /* Allocate the ciphers */
380 silc_cipher_alloc(cipher, &client_entry->send_key);
381 silc_cipher_alloc(cipher, &client_entry->receive_key);
384 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
386 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
387 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
389 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
394 /* Sends private message key payload to the remote client indicated by
395 the `client_entry'. If the `force_send' is TRUE the packet is sent
396 immediately. Returns FALSE if error occurs, TRUE otherwise. The
397 application should call this function after setting the key to the
400 Note that the key sent using this function is sent to the remote client
401 through the SILC network. The packet is protected using normal session
404 int silc_client_send_private_message_key(SilcClient client,
405 SilcClientConnection conn,
406 SilcClientEntry client_entry,
409 SilcSocketConnection sock = conn->sock;
413 if (!client_entry->send_key || !client_entry->key)
416 SILC_LOG_DEBUG(("Sending private message key"));
418 cipher_len = strlen(client_entry->send_key->cipher->name);
420 /* Create private message key payload */
421 buffer = silc_buffer_alloc(2 + client_entry->key_len);
422 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
423 silc_buffer_format(buffer,
424 SILC_STR_UI_SHORT(client_entry->key_len),
425 SILC_STR_UI_XNSTRING(client_entry->key,
426 client_entry->key_len),
427 SILC_STR_UI_SHORT(cipher_len),
428 SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
432 /* Send the packet */
433 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
434 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
435 buffer->data, buffer->len, force_send);
441 /* Removes the private message from the library. The key won't be used
442 after this to protect the private messages with the remote `client_entry'
443 client. Returns FALSE on error, TRUE otherwise. */
445 int silc_client_del_private_message_key(SilcClient client,
446 SilcClientConnection conn,
447 SilcClientEntry client_entry)
449 assert(client_entry);
451 if (!client_entry->send_key && !client_entry->receive_key)
454 silc_cipher_free(client_entry->send_key);
455 silc_cipher_free(client_entry->receive_key);
457 if (client_entry->key) {
458 memset(client_entry->key, 0, client_entry->key_len);
459 silc_free(client_entry->key);
462 client_entry->send_key = NULL;
463 client_entry->receive_key = NULL;
464 client_entry->key = NULL;
469 /* Returns array of set private message keys associated to the connection
470 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
471 count to the `key_count' argument. The array must be freed by the caller
472 by calling the silc_client_free_private_message_keys function. Note:
473 the keys returned in the array is in raw format. It might not be desired
474 to show the keys as is. The application might choose not to show the keys
475 at all or to show the fingerprints of the keys. */
477 SilcPrivateMessageKeys
478 silc_client_list_private_message_keys(SilcClient client,
479 SilcClientConnection conn,
482 SilcPrivateMessageKeys keys;
484 SilcIDCacheEntry id_cache;
485 SilcIDCacheList list;
486 SilcClientEntry entry;
488 if (!silc_idcache_get_all(conn->client_cache, &list))
491 if (!silc_idcache_list_count(list)) {
492 silc_idcache_list_free(list);
496 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
498 silc_idcache_list_first(list, &id_cache);
500 entry = (SilcClientEntry)id_cache->context;
502 if (entry->send_key) {
503 keys[count].client_entry = entry;
504 keys[count].cipher = entry->send_key->cipher->name;
505 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
506 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
510 if (!silc_idcache_list_next(list, &id_cache))
520 /* Frees the SilcPrivateMessageKeys array returned by the function
521 silc_client_list_private_message_keys. */
523 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,