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;
50 SILC_LOG_DEBUG(("Sending private message"));
52 /* Encode private message payload */
53 buffer = silc_private_message_payload_encode(flags,
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;
72 hmac = conn->hmac_send;
73 block_len = silc_cipher_get_block_len(cipher);
75 /* Set the packet context pointers. */
76 packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
77 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
78 packetdata.src_id = conn->local_id_data;
79 packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
80 packetdata.src_id_type = SILC_ID_CLIENT;
81 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
82 packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
83 packetdata.dst_id_type = SILC_ID_CLIENT;
84 packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
85 packetdata.src_id_len + packetdata.dst_id_len;
86 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
87 packetdata.src_id_len +
88 packetdata.dst_id_len), block_len);
90 /* Prepare outgoing data buffer for packet sending */
91 silc_packet_send_prepare(sock,
92 SILC_PACKET_HEADER_LEN +
93 packetdata.src_id_len +
94 packetdata.dst_id_len,
98 packetdata.buffer = sock->outbuf;
100 /* Put the actual encrypted message payload data into the buffer. */
101 silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
103 /* Create the outgoing packet */
104 silc_packet_assemble(&packetdata, cipher);
106 /* Encrypt the header and padding of the packet. */
107 cipher = conn->send_key;
108 silc_packet_encrypt(cipher, hmac, conn->psn_send++,
109 sock->outbuf, SILC_PACKET_HEADER_LEN +
110 packetdata.src_id_len + packetdata.dst_id_len +
113 SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
114 sock->outbuf->data, sock->outbuf->len);
116 /* Now actually send the packet */
117 silc_client_packet_send_real(client, sock, force_send);
118 silc_free(packetdata.dst_id);
121 silc_buffer_free(buffer);
124 static void silc_client_private_message_cb(SilcClient client,
125 SilcClientConnection conn,
126 SilcClientEntry *clients,
127 uint32 clients_count,
130 SilcPacketContext *packet = (SilcPacketContext *)context;
133 silc_packet_context_free(packet);
137 silc_client_private_message(client, conn->sock, packet);
138 silc_packet_context_free(packet);
141 /* Private message received. This processes the private message and
142 finally displays it on the screen. */
144 void silc_client_private_message(SilcClient client,
145 SilcSocketConnection sock,
146 SilcPacketContext *packet)
148 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
149 SilcPrivateMessagePayload payload = NULL;
150 SilcIDCacheEntry id_cache;
151 SilcClientID *remote_id = NULL;
152 SilcClientEntry remote_client;
153 SilcMessageFlags flags;
155 if (packet->src_id_type != SILC_ID_CLIENT)
158 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
163 /* Check whether we know this client already */
164 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)remote_id,
166 silc_hash_client_id_compare, NULL,
168 ((SilcClientEntry)id_cache->context)->nickname == NULL) {
169 /* Resolve the client info */
170 silc_client_get_client_by_id_resolve(client, conn, remote_id,
171 silc_client_private_message_cb,
172 silc_packet_context_dup(packet));
176 remote_client = (SilcClientEntry)id_cache->context;
178 /* Parse the payload and decrypt it also if private message key is set */
179 payload = silc_private_message_payload_parse(packet->buffer,
180 remote_client->receive_key);
182 silc_free(remote_id);
186 flags = silc_private_message_get_flags(payload);
188 /* Pass the private message to application */
189 client->ops->private_message(client, conn, remote_client, flags,
190 silc_private_message_get_message(payload,
193 /* See if we are away (gone). If we are away we will reply to the
194 sender with the set away message. */
195 if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
196 /* If it's me, ignore */
197 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
200 /* Send the away message */
201 silc_client_send_private_message(client, conn, remote_client,
202 SILC_MESSAGE_FLAG_AUTOREPLY |
203 SILC_MESSAGE_FLAG_NOREPLY,
205 strlen(conn->away->away), TRUE);
210 silc_private_message_payload_free(payload);
212 silc_free(remote_id);
215 /* Function that actually employes the received private message key */
217 static void silc_client_private_message_key_cb(SilcClient client,
218 SilcClientConnection conn,
219 SilcClientEntry *clients,
220 uint32 clients_count,
223 SilcPacketContext *packet = (SilcPacketContext *)context;
226 unsigned char *cipher;
232 /* Parse the private message key payload */
233 ret = silc_buffer_unformat(packet->buffer,
234 SILC_STR_UI16_NSTRING(&key, &key_len),
235 SILC_STR_UI16_STRING(&cipher),
240 if (key_len > packet->buffer->len)
243 /* Now take the key in use */
244 if (!silc_client_add_private_message_key(client, conn, clients[0],
245 cipher, key, key_len, FALSE, TRUE))
248 /* Print some info for application */
249 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
250 "Received private message key from %s%s%s %s%s%s",
251 clients[0]->nickname,
252 clients[0]->server ? "@" : "",
253 clients[0]->server ? clients[0]->server : "",
254 clients[0]->username ? "(" : "",
255 clients[0]->username ? clients[0]->username : "",
256 clients[0]->username ? ")" : "");
259 silc_packet_context_free(packet);
262 /* Processes incoming Private Message Key payload. The libary always
263 accepts the key and takes it into use. */
265 void silc_client_private_message_key(SilcClient client,
266 SilcSocketConnection sock,
267 SilcPacketContext *packet)
269 SilcClientID *remote_id;
271 if (packet->src_id_type != SILC_ID_CLIENT)
274 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
279 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
280 silc_client_private_message_key_cb,
281 silc_packet_context_dup(packet));
282 silc_free(remote_id);
285 /* Adds private message key to the client library. The key will be used to
286 encrypt all private message between the client and the remote client
287 indicated by the `client_entry'. If the `key' is NULL and the boolean
288 value `generate_key' is TRUE the library will generate random key.
289 The `key' maybe for example pre-shared-key, passphrase or similar.
290 The `cipher' MAY be provided but SHOULD be NULL to assure that the
291 requirements of the SILC protocol are met. The API, however, allows
292 to allocate any cipher.
294 If `responder' is TRUE then the sending and receiving keys will be
295 set according the client being the receiver of the private key. If
296 FALSE the client is being the sender (or negotiator) of the private
299 It is not necessary to set key for normal private message usage. If the
300 key is not set then the private messages are encrypted using normal
301 session keys. Setting the private key, however, increases the security.
303 Returns FALSE if the key is already set for the `client_entry', TRUE
306 int silc_client_add_private_message_key(SilcClient client,
307 SilcClientConnection conn,
308 SilcClientEntry client_entry,
315 unsigned char private_key[32];
318 SilcSKEKeyMaterial *keymat;
320 assert(client_entry);
322 /* Return FALSE if key already set */
323 if (client_entry->send_key && client_entry->receive_key)
327 cipher = SILC_DEFAULT_CIPHER;
329 /* Check the requested cipher */
330 if (!silc_cipher_is_supported(cipher))
333 /* Generate key if not provided */
334 if (generate_key == TRUE) {
336 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
339 client_entry->generated = TRUE;
343 client_entry->key = silc_calloc(key_len, sizeof(*client_entry->key));
344 memcpy(client_entry->key, key, key_len);
345 client_entry->key_len = key_len;
347 /* Produce the key material as the protocol defines */
348 keymat = silc_calloc(1, sizeof(*keymat));
349 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
350 client->md5hash, keymat)
351 != SILC_SKE_STATUS_OK)
354 /* Allocate the ciphers */
355 silc_cipher_alloc(cipher, &client_entry->send_key);
356 silc_cipher_alloc(cipher, &client_entry->receive_key);
359 if (responder == TRUE) {
360 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
361 keymat->enc_key_len);
362 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
363 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
364 keymat->enc_key_len);
365 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
367 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
368 keymat->enc_key_len);
369 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
370 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
371 keymat->enc_key_len);
372 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
375 /* Free the key material */
376 silc_ske_free_key_material(keymat);
381 /* Same as above but takes the key material from the SKE key material
382 structure. This structure is received if the application uses the
383 silc_client_send_key_agreement to negotiate the key material. The
384 `cipher' SHOULD be provided as it is negotiated also in the SKE
387 int silc_client_add_private_message_key_ske(SilcClient client,
388 SilcClientConnection conn,
389 SilcClientEntry client_entry,
391 SilcSKEKeyMaterial *key,
394 assert(client_entry);
396 /* Return FALSE if key already set */
397 if (client_entry->send_key && client_entry->receive_key)
401 cipher = SILC_DEFAULT_CIPHER;
403 /* Check the requested cipher */
404 if (!silc_cipher_is_supported(cipher))
407 /* Allocate the ciphers */
408 silc_cipher_alloc(cipher, &client_entry->send_key);
409 silc_cipher_alloc(cipher, &client_entry->receive_key);
412 if (responder == TRUE) {
413 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
415 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
416 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
418 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
420 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
422 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
423 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
425 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
431 /* Sends private message key payload to the remote client indicated by
432 the `client_entry'. If the `force_send' is TRUE the packet is sent
433 immediately. Returns FALSE if error occurs, TRUE otherwise. The
434 application should call this function after setting the key to the
437 Note that the key sent using this function is sent to the remote client
438 through the SILC network. The packet is protected using normal session
441 int silc_client_send_private_message_key(SilcClient client,
442 SilcClientConnection conn,
443 SilcClientEntry client_entry,
446 SilcSocketConnection sock = conn->sock;
450 if (!client_entry->send_key || !client_entry->key)
453 SILC_LOG_DEBUG(("Sending private message key"));
455 cipher_len = strlen(client_entry->send_key->cipher->name);
457 /* Create private message key payload */
458 buffer = silc_buffer_alloc(2 + client_entry->key_len);
459 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
460 silc_buffer_format(buffer,
461 SILC_STR_UI_SHORT(client_entry->key_len),
462 SILC_STR_UI_XNSTRING(client_entry->key,
463 client_entry->key_len),
464 SILC_STR_UI_SHORT(cipher_len),
465 SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
469 /* Send the packet */
470 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
471 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
472 buffer->data, buffer->len, force_send);
478 /* Removes the private message from the library. The key won't be used
479 after this to protect the private messages with the remote `client_entry'
480 client. Returns FALSE on error, TRUE otherwise. */
482 int silc_client_del_private_message_key(SilcClient client,
483 SilcClientConnection conn,
484 SilcClientEntry client_entry)
486 assert(client_entry);
488 if (!client_entry->send_key && !client_entry->receive_key)
491 silc_cipher_free(client_entry->send_key);
492 silc_cipher_free(client_entry->receive_key);
494 if (client_entry->key) {
495 memset(client_entry->key, 0, client_entry->key_len);
496 silc_free(client_entry->key);
499 client_entry->send_key = NULL;
500 client_entry->receive_key = NULL;
501 client_entry->key = NULL;
506 /* Returns array of set private message keys associated to the connection
507 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
508 count to the `key_count' argument. The array must be freed by the caller
509 by calling the silc_client_free_private_message_keys function. Note:
510 the keys returned in the array is in raw format. It might not be desired
511 to show the keys as is. The application might choose not to show the keys
512 at all or to show the fingerprints of the keys. */
514 SilcPrivateMessageKeys
515 silc_client_list_private_message_keys(SilcClient client,
516 SilcClientConnection conn,
519 SilcPrivateMessageKeys keys;
521 SilcIDCacheEntry id_cache;
522 SilcIDCacheList list;
523 SilcClientEntry entry;
525 if (!silc_idcache_get_all(conn->client_cache, &list))
528 if (!silc_idcache_list_count(list)) {
529 silc_idcache_list_free(list);
533 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
535 silc_idcache_list_first(list, &id_cache);
537 entry = (SilcClientEntry)id_cache->context;
539 if (entry->send_key) {
540 keys[count].client_entry = entry;
541 keys[count].cipher = entry->send_key->cipher->name;
542 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
543 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
547 if (!silc_idcache_list_next(list, &id_cache))
557 /* Frees the SilcPrivateMessageKeys array returned by the function
558 silc_client_list_private_message_keys. */
560 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
566 /* Sets away `message'. The away message may be set when the client's
567 mode is changed to SILC_UMODE_GONE and the client whishes to reply
568 to anyone who sends private message. The `message' will be sent
569 automatically back to the the client who send private message. If
570 away message is already set this replaces the old message with the
571 new one. If `message' is NULL the old away message is removed.
572 The sender may freely free the memory of the `message'. */
574 void silc_client_set_away_message(SilcClient client,
575 SilcClientConnection conn,
578 if (!message && conn->away) {
579 silc_free(conn->away->away);
580 silc_free(conn->away);
586 conn->away = silc_calloc(1, sizeof(*conn->away));
587 if (conn->away->away)
588 silc_free(conn->away->away);
589 conn->away->away = strdup(message);