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;
48 SILC_LOG_DEBUG(("Sending private message"));
50 /* Encode private message payload */
51 buffer = silc_private_message_payload_encode(0, strlen(conn->nickname),
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;
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_CLIENT_LEN;
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_CLIENT_LEN;
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);
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 unsigned int 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(conn->client_cache, remote_id,
156 SILC_ID_CLIENT, &id_cache)) {
157 /* Resolve the client info */
158 silc_client_get_client_by_id_resolve(client, conn, remote_id,
159 silc_client_private_message_cb,
160 silc_packet_context_dup(packet));
164 remote_client = (SilcClientEntry)id_cache->context;
166 /* Parse the payload and decrypt it also if private message key is set */
167 payload = silc_private_message_payload_parse(packet->buffer,
168 remote_client->send_key);
170 silc_free(remote_id);
174 /* Pass the private message to application */
175 client->ops->private_message(client, conn, remote_client,
176 silc_private_message_get_message(payload,
179 /* See if we are away (gone). If we are away we will reply to the
180 sender with the set away message. */
181 if (conn->away && conn->away->away) {
182 /* If it's me, ignore */
183 if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
186 /* Send the away message */
187 silc_client_send_private_message(client, conn, remote_client,
189 strlen(conn->away->away), TRUE);
194 silc_private_message_payload_free(payload);
196 silc_free(remote_id);
199 /* Function that actually employes the received private message key */
201 static void silc_client_private_message_key_cb(SilcClient client,
202 SilcClientConnection conn,
203 SilcClientEntry *clients,
204 unsigned int clients_count,
207 SilcPacketContext *packet = (SilcPacketContext *)context;
209 unsigned short key_len;
210 unsigned char *cipher;
216 /* Parse the private message key payload */
217 ret = silc_buffer_unformat(packet->buffer,
218 SILC_STR_UI16_NSTRING(&key, &key_len),
219 SILC_STR_UI16_STRING(&cipher),
224 if (key_len > packet->buffer->len)
227 /* Now take the key in use */
228 if (!silc_client_add_private_message_key(client, conn, clients[0],
229 cipher, key, key_len, FALSE))
232 /* Print some info for application */
233 client->ops->say(client, conn,
234 "Received private message key from %s%s%s %s%s%s",
235 clients[0]->nickname,
236 clients[0]->server ? "@" : "",
237 clients[0]->server ? clients[0]->server : "",
238 clients[0]->username ? "(" : "",
239 clients[0]->username ? clients[0]->username : "",
240 clients[0]->username ? ")" : "");
243 silc_packet_context_free(packet);
246 /* Processes incoming Private Message Key payload. The libary always
247 accepts the key and takes it into use. */
249 void silc_client_private_message_key(SilcClient client,
250 SilcSocketConnection sock,
251 SilcPacketContext *packet)
253 SilcClientID *remote_id;
255 if (packet->src_id_type != SILC_ID_CLIENT)
258 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
263 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
264 silc_client_private_message_key_cb,
265 silc_packet_context_dup(packet));
266 silc_free(remote_id);
269 /* Adds private message key to the client library. The key will be used to
270 encrypt all private message between the client and the remote client
271 indicated by the `client_entry'. If the `key' is NULL and the boolean
272 value `generate_key' is TRUE the library will generate random key.
273 The `key' maybe for example pre-shared-key, passphrase or similar.
274 The `cipher' MAY be provided but SHOULD be NULL to assure that the
275 requirements of the SILC protocol are met. The API, however, allows
276 to allocate any cipher.
278 It is not necessary to set key for normal private message usage. If the
279 key is not set then the private messages are encrypted using normal
280 session keys. Setting the private key, however, increases the security.
282 Returns FALSE if the key is already set for the `client_entry', TRUE
285 int silc_client_add_private_message_key(SilcClient client,
286 SilcClientConnection conn,
287 SilcClientEntry client_entry,
290 unsigned int key_len,
293 unsigned char private_key[32];
296 SilcSKEKeyMaterial *keymat;
298 assert(client_entry);
300 /* Return FALSE if key already set */
301 if (client_entry->send_key && client_entry->receive_key)
305 cipher = "aes-256-cbc";
307 /* Check the requested cipher */
308 if (!silc_cipher_is_supported(cipher))
311 /* Generate key if not provided */
312 if (generate_key == TRUE) {
314 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
317 client_entry->generated = TRUE;
321 client_entry->key = silc_calloc(key_len, sizeof(*client_entry->key));
322 memcpy(client_entry->key, key, key_len);
323 client_entry->key_len = key_len;
325 /* Produce the key material as the protocol defines */
326 keymat = silc_calloc(1, sizeof(*keymat));
327 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
328 client->md5hash, keymat)
329 != SILC_SKE_STATUS_OK)
332 /* Allocate the ciphers */
333 silc_cipher_alloc(cipher, &client_entry->send_key);
334 silc_cipher_alloc(cipher, &client_entry->receive_key);
337 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
338 keymat->enc_key_len);
339 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
340 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
341 keymat->enc_key_len);
342 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
344 /* Free the key material */
345 silc_ske_free_key_material(keymat);
350 /* Same as above but takes the key material from the SKE key material
351 structure. This structure is received if the application uses the
352 silc_client_send_key_agreement to negotiate the key material. The
353 `cipher' SHOULD be provided as it is negotiated also in the SKE
356 int silc_client_add_private_message_key_ske(SilcClient client,
357 SilcClientConnection conn,
358 SilcClientEntry client_entry,
360 SilcSKEKeyMaterial *key)
362 assert(client_entry);
364 /* Return FALSE if key already set */
365 if (client_entry->send_key && client_entry->receive_key)
369 cipher = "aes-256-cbc";
371 /* Check the requested cipher */
372 if (!silc_cipher_is_supported(cipher))
375 /* Allocate the ciphers */
376 silc_cipher_alloc(cipher, &client_entry->send_key);
377 silc_cipher_alloc(cipher, &client_entry->receive_key);
380 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
382 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
383 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
385 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
390 /* Sends private message key payload to the remote client indicated by
391 the `client_entry'. If the `force_send' is TRUE the packet is sent
392 immediately. Returns FALSE if error occurs, TRUE otherwise. The
393 application should call this function after setting the key to the
396 Note that the key sent using this function is sent to the remote client
397 through the SILC network. The packet is protected using normal session
400 int silc_client_send_private_message_key(SilcClient client,
401 SilcClientConnection conn,
402 SilcClientEntry client_entry,
405 SilcSocketConnection sock = conn->sock;
409 if (!client_entry->send_key || !client_entry->key)
412 SILC_LOG_DEBUG(("Sending private message key"));
414 cipher_len = strlen(client_entry->send_key->cipher->name);
416 /* Create private message key payload */
417 buffer = silc_buffer_alloc(2 + client_entry->key_len);
418 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
419 silc_buffer_format(buffer,
420 SILC_STR_UI_SHORT(client_entry->key_len),
421 SILC_STR_UI_XNSTRING(client_entry->key,
422 client_entry->key_len),
423 SILC_STR_UI_SHORT(cipher_len),
424 SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
428 /* Send the packet */
429 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
430 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
431 buffer->data, buffer->len, force_send);
437 /* Removes the private message from the library. The key won't be used
438 after this to protect the private messages with the remote `client_entry'
439 client. Returns FALSE on error, TRUE otherwise. */
441 int silc_client_del_private_message_key(SilcClient client,
442 SilcClientConnection conn,
443 SilcClientEntry client_entry)
445 assert(client_entry);
447 if (!client_entry->send_key && !client_entry->receive_key)
450 silc_cipher_free(client_entry->send_key);
451 silc_cipher_free(client_entry->receive_key);
453 if (client_entry->key) {
454 memset(client_entry->key, 0, client_entry->key_len);
455 silc_free(client_entry->key);
458 client_entry->send_key = NULL;
459 client_entry->receive_key = NULL;
460 client_entry->key = NULL;
465 /* Returns array of set private message keys associated to the connection
466 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
467 count to the `key_count' argument. The array must be freed by the caller
468 by calling the silc_client_free_private_message_keys function. Note:
469 the keys returned in the array is in raw format. It might not be desired
470 to show the keys as is. The application might choose not to show the keys
471 at all or to show the fingerprints of the keys. */
473 SilcPrivateMessageKeys
474 silc_client_list_private_message_keys(SilcClient client,
475 SilcClientConnection conn,
476 unsigned int *key_count)
478 SilcPrivateMessageKeys keys;
479 unsigned int count = 0;
480 SilcIDCacheEntry id_cache;
481 SilcIDCacheList list;
482 SilcClientEntry entry;
484 if (!silc_idcache_find_by_id(conn->client_cache, SILC_ID_CACHE_ANY,
485 SILC_ID_CLIENT, &list))
488 if (!silc_idcache_list_count(list)) {
489 silc_idcache_list_free(list);
493 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
495 silc_idcache_list_first(list, &id_cache);
497 entry = (SilcClientEntry)id_cache->context;
499 if (entry->send_key) {
500 keys[count].client_entry = entry;
501 keys[count].cipher = entry->send_key->cipher->name;
502 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
503 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
507 if (!silc_idcache_list_next(list, &id_cache))
517 /* Frees the SilcPrivateMessageKeys array returned by the function
518 silc_client_list_private_message_keys. */
520 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
521 unsigned int key_count)