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, strlen(conn->nickname),
55 client_entry->send_key);
57 /* If we don't have private message specific key then private messages
58 are just as any normal packet thus call normal packet sending. If
59 the key exist then the encryption process is a bit different and
60 will be done in the rest of this function. */
61 if (!client_entry->send_key) {
62 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
63 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
64 buffer->data, buffer->len, force_send);
68 /* We have private message specific key */
70 /* Get data used in the encryption */
71 cipher = client_entry->send_key;
74 /* Set the packet context pointers. */
75 packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
76 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
77 packetdata.src_id = conn->local_id_data;
78 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
79 packetdata.src_id_type = SILC_ID_CLIENT;
80 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
81 packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
82 packetdata.dst_id_type = SILC_ID_CLIENT;
83 packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
84 packetdata.src_id_len + packetdata.dst_id_len;
85 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
86 packetdata.src_id_len +
87 packetdata.dst_id_len));
89 /* Prepare outgoing data buffer for packet sending */
90 silc_packet_send_prepare(sock,
91 SILC_PACKET_HEADER_LEN +
92 packetdata.src_id_len +
93 packetdata.dst_id_len,
97 packetdata.buffer = sock->outbuf;
99 /* Put the actual encrypted message payload data into the buffer. */
100 silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
102 /* Create the outgoing packet */
103 silc_packet_assemble(&packetdata);
105 /* Encrypt the header and padding of the packet. */
106 cipher = conn->send_key;
107 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
108 packetdata.src_id_len + packetdata.dst_id_len +
111 SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
112 sock->outbuf->data, sock->outbuf->len);
114 /* Now actually send the packet */
115 silc_client_packet_send_real(client, sock, force_send);
116 silc_free(packetdata.dst_id);
119 silc_buffer_free(buffer);
122 static void silc_client_private_message_cb(SilcClient client,
123 SilcClientConnection conn,
124 SilcClientEntry *clients,
125 uint32 clients_count,
128 SilcPacketContext *packet = (SilcPacketContext *)context;
130 silc_client_private_message(client, conn->sock, packet);
131 silc_packet_context_free(packet);
134 /* Private message received. This processes the private message and
135 finally displays it on the screen. */
137 void silc_client_private_message(SilcClient client,
138 SilcSocketConnection sock,
139 SilcPacketContext *packet)
141 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
142 SilcPrivateMessagePayload payload = NULL;
143 SilcIDCacheEntry id_cache;
144 SilcClientID *remote_id = NULL;
145 SilcClientEntry remote_client;
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(conn->client_cache, remote_id,
157 SILC_ID_CLIENT, &id_cache)) {
158 /* Resolve the client info */
159 silc_client_get_client_by_id_resolve(client, conn, remote_id,
160 silc_client_private_message_cb,
161 silc_packet_context_dup(packet));
165 remote_client = (SilcClientEntry)id_cache->context;
167 /* Parse the payload and decrypt it also if private message key is set */
168 payload = silc_private_message_payload_parse(packet->buffer,
169 remote_client->send_key);
171 silc_free(remote_id);
175 /* Pass the private message to application */
176 client->ops->private_message(client, conn, remote_client,
177 silc_private_message_get_flags(payload),
178 silc_private_message_get_message(payload,
181 /* See if we are away (gone). If we are away we will reply to the
182 sender with the set away message. */
183 if (conn->away && conn->away->away) {
184 /* If it's me, ignore */
185 if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
188 /* Send the away message */
189 silc_client_send_private_message(client, conn, remote_client,
190 SILC_MESSAGE_FLAG_AUTOREPLY,
192 strlen(conn->away->away), TRUE);
197 silc_private_message_payload_free(payload);
199 silc_free(remote_id);
202 /* Function that actually employes the received private message key */
204 static void silc_client_private_message_key_cb(SilcClient client,
205 SilcClientConnection conn,
206 SilcClientEntry *clients,
207 uint32 clients_count,
210 SilcPacketContext *packet = (SilcPacketContext *)context;
213 unsigned char *cipher;
219 /* Parse the private message key payload */
220 ret = silc_buffer_unformat(packet->buffer,
221 SILC_STR_UI16_NSTRING(&key, &key_len),
222 SILC_STR_UI16_STRING(&cipher),
227 if (key_len > packet->buffer->len)
230 /* Now take the key in use */
231 if (!silc_client_add_private_message_key(client, conn, clients[0],
232 cipher, key, key_len, FALSE))
235 /* Print some info for application */
236 client->ops->say(client, conn,
237 "Received private message key from %s%s%s %s%s%s",
238 clients[0]->nickname,
239 clients[0]->server ? "@" : "",
240 clients[0]->server ? clients[0]->server : "",
241 clients[0]->username ? "(" : "",
242 clients[0]->username ? clients[0]->username : "",
243 clients[0]->username ? ")" : "");
246 silc_packet_context_free(packet);
249 /* Processes incoming Private Message Key payload. The libary always
250 accepts the key and takes it into use. */
252 void silc_client_private_message_key(SilcClient client,
253 SilcSocketConnection sock,
254 SilcPacketContext *packet)
256 SilcClientID *remote_id;
258 if (packet->src_id_type != SILC_ID_CLIENT)
261 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
266 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
267 silc_client_private_message_key_cb,
268 silc_packet_context_dup(packet));
269 silc_free(remote_id);
272 /* Adds private message key to the client library. The key will be used to
273 encrypt all private message between the client and the remote client
274 indicated by the `client_entry'. If the `key' is NULL and the boolean
275 value `generate_key' is TRUE the library will generate random key.
276 The `key' maybe for example pre-shared-key, passphrase or similar.
277 The `cipher' MAY be provided but SHOULD be NULL to assure that the
278 requirements of the SILC protocol are met. The API, however, allows
279 to allocate any cipher.
281 It is not necessary to set key for normal private message usage. If the
282 key is not set then the private messages are encrypted using normal
283 session keys. Setting the private key, however, increases the security.
285 Returns FALSE if the key is already set for the `client_entry', TRUE
288 int silc_client_add_private_message_key(SilcClient client,
289 SilcClientConnection conn,
290 SilcClientEntry client_entry,
296 unsigned char private_key[32];
299 SilcSKEKeyMaterial *keymat;
301 assert(client_entry);
303 /* Return FALSE if key already set */
304 if (client_entry->send_key && client_entry->receive_key)
308 cipher = "aes-256-cbc";
310 /* Check the requested cipher */
311 if (!silc_cipher_is_supported(cipher))
314 /* Generate key if not provided */
315 if (generate_key == TRUE) {
317 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
320 client_entry->generated = TRUE;
324 client_entry->key = silc_calloc(key_len, sizeof(*client_entry->key));
325 memcpy(client_entry->key, key, key_len);
326 client_entry->key_len = key_len;
328 /* Produce the key material as the protocol defines */
329 keymat = silc_calloc(1, sizeof(*keymat));
330 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
331 client->md5hash, keymat)
332 != SILC_SKE_STATUS_OK)
335 /* Allocate the ciphers */
336 silc_cipher_alloc(cipher, &client_entry->send_key);
337 silc_cipher_alloc(cipher, &client_entry->receive_key);
340 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
341 keymat->enc_key_len);
342 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
343 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
344 keymat->enc_key_len);
345 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
347 /* Free the key material */
348 silc_ske_free_key_material(keymat);
353 /* Same as above but takes the key material from the SKE key material
354 structure. This structure is received if the application uses the
355 silc_client_send_key_agreement to negotiate the key material. The
356 `cipher' SHOULD be provided as it is negotiated also in the SKE
359 int silc_client_add_private_message_key_ske(SilcClient client,
360 SilcClientConnection conn,
361 SilcClientEntry client_entry,
363 SilcSKEKeyMaterial *key)
365 assert(client_entry);
367 /* Return FALSE if key already set */
368 if (client_entry->send_key && client_entry->receive_key)
372 cipher = "aes-256-cbc";
374 /* Check the requested cipher */
375 if (!silc_cipher_is_supported(cipher))
378 /* Allocate the ciphers */
379 silc_cipher_alloc(cipher, &client_entry->send_key);
380 silc_cipher_alloc(cipher, &client_entry->receive_key);
383 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
385 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
386 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
388 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
393 /* Sends private message key payload to the remote client indicated by
394 the `client_entry'. If the `force_send' is TRUE the packet is sent
395 immediately. Returns FALSE if error occurs, TRUE otherwise. The
396 application should call this function after setting the key to the
399 Note that the key sent using this function is sent to the remote client
400 through the SILC network. The packet is protected using normal session
403 int silc_client_send_private_message_key(SilcClient client,
404 SilcClientConnection conn,
405 SilcClientEntry client_entry,
408 SilcSocketConnection sock = conn->sock;
412 if (!client_entry->send_key || !client_entry->key)
415 SILC_LOG_DEBUG(("Sending private message key"));
417 cipher_len = strlen(client_entry->send_key->cipher->name);
419 /* Create private message key payload */
420 buffer = silc_buffer_alloc(2 + client_entry->key_len);
421 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
422 silc_buffer_format(buffer,
423 SILC_STR_UI_SHORT(client_entry->key_len),
424 SILC_STR_UI_XNSTRING(client_entry->key,
425 client_entry->key_len),
426 SILC_STR_UI_SHORT(cipher_len),
427 SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
431 /* Send the packet */
432 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
433 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
434 buffer->data, buffer->len, force_send);
440 /* Removes the private message from the library. The key won't be used
441 after this to protect the private messages with the remote `client_entry'
442 client. Returns FALSE on error, TRUE otherwise. */
444 int silc_client_del_private_message_key(SilcClient client,
445 SilcClientConnection conn,
446 SilcClientEntry client_entry)
448 assert(client_entry);
450 if (!client_entry->send_key && !client_entry->receive_key)
453 silc_cipher_free(client_entry->send_key);
454 silc_cipher_free(client_entry->receive_key);
456 if (client_entry->key) {
457 memset(client_entry->key, 0, client_entry->key_len);
458 silc_free(client_entry->key);
461 client_entry->send_key = NULL;
462 client_entry->receive_key = NULL;
463 client_entry->key = NULL;
468 /* Returns array of set private message keys associated to the connection
469 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
470 count to the `key_count' argument. The array must be freed by the caller
471 by calling the silc_client_free_private_message_keys function. Note:
472 the keys returned in the array is in raw format. It might not be desired
473 to show the keys as is. The application might choose not to show the keys
474 at all or to show the fingerprints of the keys. */
476 SilcPrivateMessageKeys
477 silc_client_list_private_message_keys(SilcClient client,
478 SilcClientConnection conn,
481 SilcPrivateMessageKeys keys;
483 SilcIDCacheEntry id_cache;
484 SilcIDCacheList list;
485 SilcClientEntry entry;
487 if (!silc_idcache_find_by_id(conn->client_cache, SILC_ID_CACHE_ANY,
488 SILC_ID_CLIENT, &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,