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 "silcincludes.h"
25 #include "silcclient.h"
26 #include "client_internal.h"
28 /* Sends private message to remote client. If private message key has
29 not been set with this client then the message will be encrypted using
30 normal session keys. Private messages are special packets in SILC
31 network hence we need this own function for them. This is similiar
32 to silc_client_packet_send_to_channel except that we send private
33 message. The `data' is the private message. If the `force_send' is
34 TRUE the packet is sent immediately. */
36 void silc_client_send_private_message(SilcClient client,
37 SilcClientConnection conn,
38 SilcClientEntry client_entry,
39 SilcMessageFlags flags,
44 SilcSocketConnection sock;
46 SilcPacketContext packetdata;
47 const SilcBufferStruct packet;
52 assert(client && conn && client_entry);
54 SILC_LOG_DEBUG(("Sending private message"));
56 /* Encode private message payload */
57 buffer = silc_private_message_payload_encode(flags,
59 client_entry->send_key,
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 = conn->internal->send_key;
77 hmac = conn->internal->hmac_send;
78 block_len = silc_cipher_get_block_len(cipher);
80 /* Set the packet context pointers. */
82 data_len = buffer->len;
83 packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
84 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
85 packetdata.src_id = conn->local_id_data;
86 packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
87 packetdata.src_id_type = SILC_ID_CLIENT;
88 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
89 packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
90 packetdata.dst_id_type = SILC_ID_CLIENT;
91 data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
92 packetdata.src_id_len +
93 packetdata.dst_id_len);
94 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
95 packetdata.src_id_len + packetdata.dst_id_len;
96 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
97 packetdata.src_id_len +
98 packetdata.dst_id_len), block_len);
100 /* Create the outgoing packet */
101 if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
102 data, data_len, (const SilcBuffer)&packet)) {
103 SILC_LOG_ERROR(("Error assembling packet"));
107 /* Encrypt the header and padding of the packet. */
108 silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
109 (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
110 packetdata.src_id_len + packetdata.dst_id_len +
113 SILC_LOG_HEXDUMP(("Private message packet, len %d", packet.len),
114 packet.data, packet.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 SilcUInt32 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 SilcClientID *remote_id = NULL;
151 SilcClientEntry remote_client;
152 SilcMessageFlags flags;
153 unsigned char *message;
154 SilcUInt32 message_len;
155 SilcCipher cipher = NULL;
157 if (packet->src_id_type != SILC_ID_CLIENT)
160 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
165 /* Check whether we know this client already */
166 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
167 if (!remote_client || !remote_client->nickname) {
169 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
170 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
173 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
174 remote_client->resolve_cmd_ident = conn->cmd_ident + 1;
177 /* Resolve the client info */
178 silc_client_get_client_by_id_resolve(client, conn, remote_id, NULL,
179 silc_client_private_message_cb,
180 silc_packet_context_dup(packet));
184 cipher = remote_client->receive_key;
185 if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher) {
186 silc_free(remote_id);
190 /* Parse the payload and decrypt it also if private message key is set */
191 payload = silc_private_message_payload_parse(packet->buffer->data,
192 packet->buffer->len, cipher);
194 silc_free(remote_id);
198 flags = silc_private_message_get_flags(payload);
200 /* Pass the private message to application */
201 message = silc_private_message_get_message(payload, &message_len);
202 client->internal->ops->private_message(client, conn, remote_client, flags,
203 message, message_len);
205 /* See if we are away (gone). If we are away we will reply to the
206 sender with the set away message. */
207 if (conn->internal->away && conn->internal->away->away &&
208 !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
209 /* If it's me, ignore */
210 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
213 /* Send the away message */
214 silc_client_send_private_message(client, conn, remote_client,
215 SILC_MESSAGE_FLAG_AUTOREPLY |
216 SILC_MESSAGE_FLAG_NOREPLY,
217 conn->internal->away->away,
218 strlen(conn->internal->away->away), TRUE);
223 silc_private_message_payload_free(payload);
224 silc_free(remote_id);
227 /* Function that actually employes the received private message key */
229 static void silc_client_private_message_key_cb(SilcClient client,
230 SilcClientConnection conn,
231 SilcClientEntry *clients,
232 SilcUInt32 clients_count,
235 SilcPacketContext *packet = (SilcPacketContext *)context;
238 unsigned char *cipher;
244 /* Parse the private message key payload */
245 ret = silc_buffer_unformat(packet->buffer,
246 SILC_STR_UI16_NSTRING(&key, &key_len),
247 SILC_STR_UI16_STRING(&cipher),
252 if (key_len > packet->buffer->len)
255 /* Now take the key in use */
256 if (!silc_client_add_private_message_key(client, conn, clients[0],
257 cipher, key, key_len, FALSE, TRUE))
260 /* Print some info for application */
261 client->internal->ops->say(
262 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
263 "Received private message key from %s%s%s %s%s%s",
264 clients[0]->nickname,
265 clients[0]->server ? "@" : "",
266 clients[0]->server ? clients[0]->server : "",
267 clients[0]->username ? "(" : "",
268 clients[0]->username ? clients[0]->username : "",
269 clients[0]->username ? ")" : "");
272 silc_packet_context_free(packet);
275 /* Processes incoming Private Message Key payload. The libary always
276 accepts the key and takes it into use. */
278 void silc_client_private_message_key(SilcClient client,
279 SilcSocketConnection sock,
280 SilcPacketContext *packet)
282 SilcClientID *remote_id;
284 if (packet->src_id_type != SILC_ID_CLIENT)
287 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
292 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
294 silc_client_private_message_key_cb,
295 silc_packet_context_dup(packet));
296 silc_free(remote_id);
299 /* Adds private message key to the client library. The key will be used to
300 encrypt all private message between the client and the remote client
301 indicated by the `client_entry'. If the `key' is NULL and the boolean
302 value `generate_key' is TRUE the library will generate random key.
303 The `key' maybe for example pre-shared-key, passphrase or similar.
304 The `cipher' MAY be provided but SHOULD be NULL to assure that the
305 requirements of the SILC protocol are met. The API, however, allows
306 to allocate any cipher.
308 If `responder' is TRUE then the sending and receiving keys will be
309 set according the client being the receiver of the private key. If
310 FALSE the client is being the sender (or negotiator) of the private
313 It is not necessary to set key for normal private message usage. If the
314 key is not set then the private messages are encrypted using normal
315 session keys. Setting the private key, however, increases the security.
317 Returns FALSE if the key is already set for the `client_entry', TRUE
320 int silc_client_add_private_message_key(SilcClient client,
321 SilcClientConnection conn,
322 SilcClientEntry client_entry,
329 unsigned char private_key[32];
332 SilcSKEKeyMaterial *keymat;
334 assert(client && client_entry);
336 /* Return FALSE if key already set */
337 if (client_entry->send_key && client_entry->receive_key)
341 cipher = SILC_DEFAULT_CIPHER;
343 /* Check the requested cipher */
344 if (!silc_cipher_is_supported(cipher))
347 /* Generate key if not provided */
348 if (generate_key == TRUE) {
350 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
353 client_entry->generated = TRUE;
357 client_entry->key = silc_memdup(key, key_len);
358 client_entry->key_len = key_len;
360 /* Produce the key material as the protocol defines */
361 keymat = silc_calloc(1, sizeof(*keymat));
362 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
363 client->md5hash, keymat)
364 != SILC_SKE_STATUS_OK)
367 /* Allocate the ciphers */
368 silc_cipher_alloc(cipher, &client_entry->send_key);
369 silc_cipher_alloc(cipher, &client_entry->receive_key);
372 if (responder == TRUE) {
373 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
374 keymat->enc_key_len);
375 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
376 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
377 keymat->enc_key_len);
378 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
380 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
381 keymat->enc_key_len);
382 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
383 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
384 keymat->enc_key_len);
385 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
388 /* Free the key material */
389 silc_ske_free_key_material(keymat);
394 /* Same as above but takes the key material from the SKE key material
395 structure. This structure is received if the application uses the
396 silc_client_send_key_agreement to negotiate the key material. The
397 `cipher' SHOULD be provided as it is negotiated also in the SKE
400 int silc_client_add_private_message_key_ske(SilcClient client,
401 SilcClientConnection conn,
402 SilcClientEntry client_entry,
404 SilcSKEKeyMaterial *key,
407 assert(client && client_entry);
409 /* Return FALSE if key already set */
410 if (client_entry->send_key && client_entry->receive_key)
414 cipher = SILC_DEFAULT_CIPHER;
416 /* Check the requested cipher */
417 if (!silc_cipher_is_supported(cipher))
420 /* Allocate the ciphers */
421 silc_cipher_alloc(cipher, &client_entry->send_key);
422 silc_cipher_alloc(cipher, &client_entry->receive_key);
425 if (responder == TRUE) {
426 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
428 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
429 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
431 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
433 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
435 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
436 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
438 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
444 /* Sends private message key payload to the remote client indicated by
445 the `client_entry'. If the `force_send' is TRUE the packet is sent
446 immediately. Returns FALSE if error occurs, TRUE otherwise. The
447 application should call this function after setting the key to the
450 Note that the key sent using this function is sent to the remote client
451 through the SILC network. The packet is protected using normal session
454 int silc_client_send_private_message_key(SilcClient client,
455 SilcClientConnection conn,
456 SilcClientEntry client_entry,
459 SilcSocketConnection sock;
464 assert(client && conn && client_entry);
467 if (!client_entry->send_key || !client_entry->key)
470 SILC_LOG_DEBUG(("Sending private message key"));
472 cipher = silc_cipher_get_name(client_entry->send_key);
473 cipher_len = strlen(cipher);
475 /* Create private message key payload */
476 buffer = silc_buffer_alloc(2 + client_entry->key_len);
477 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
478 silc_buffer_format(buffer,
479 SILC_STR_UI_SHORT(client_entry->key_len),
480 SILC_STR_UI_XNSTRING(client_entry->key,
481 client_entry->key_len),
482 SILC_STR_UI_SHORT(cipher_len),
483 SILC_STR_UI_XNSTRING(cipher,
487 /* Send the packet */
488 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
489 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
490 buffer->data, buffer->len, force_send);
496 /* Removes the private message from the library. The key won't be used
497 after this to protect the private messages with the remote `client_entry'
498 client. Returns FALSE on error, TRUE otherwise. */
500 int silc_client_del_private_message_key(SilcClient client,
501 SilcClientConnection conn,
502 SilcClientEntry client_entry)
504 assert(client && client_entry);
506 if (!client_entry->send_key && !client_entry->receive_key)
509 silc_cipher_free(client_entry->send_key);
510 silc_cipher_free(client_entry->receive_key);
512 if (client_entry->key) {
513 memset(client_entry->key, 0, client_entry->key_len);
514 silc_free(client_entry->key);
517 client_entry->send_key = NULL;
518 client_entry->receive_key = NULL;
519 client_entry->key = NULL;
524 /* Returns array of set private message keys associated to the connection
525 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
526 count to the `key_count' argument. The array must be freed by the caller
527 by calling the silc_client_free_private_message_keys function. Note:
528 the keys returned in the array is in raw format. It might not be desired
529 to show the keys as is. The application might choose not to show the keys
530 at all or to show the fingerprints of the keys. */
532 SilcPrivateMessageKeys
533 silc_client_list_private_message_keys(SilcClient client,
534 SilcClientConnection conn,
535 SilcUInt32 *key_count)
537 SilcPrivateMessageKeys keys;
538 SilcUInt32 count = 0;
539 SilcIDCacheEntry id_cache;
540 SilcIDCacheList list;
541 SilcClientEntry entry;
543 assert(client && conn);
545 if (!silc_idcache_get_all(conn->internal->client_cache, &list))
548 if (!silc_idcache_list_count(list)) {
549 silc_idcache_list_free(list);
553 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
555 silc_idcache_list_first(list, &id_cache);
557 entry = (SilcClientEntry)id_cache->context;
559 if (entry->send_key) {
560 keys[count].client_entry = entry;
561 keys[count].cipher = (char *)silc_cipher_get_name(entry->send_key);
562 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
563 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
567 if (!silc_idcache_list_next(list, &id_cache))
577 /* Frees the SilcPrivateMessageKeys array returned by the function
578 silc_client_list_private_message_keys. */
580 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
581 SilcUInt32 key_count)
586 /* Sets away `message'. The away message may be set when the client's
587 mode is changed to SILC_UMODE_GONE and the client whishes to reply
588 to anyone who sends private message. The `message' will be sent
589 automatically back to the the client who send private message. If
590 away message is already set this replaces the old message with the
591 new one. If `message' is NULL the old away message is removed.
592 The sender may freely free the memory of the `message'. */
594 void silc_client_set_away_message(SilcClient client,
595 SilcClientConnection conn,
598 assert(client && conn);
600 if (!message && conn->internal->away) {
601 silc_free(conn->internal->away->away);
602 silc_free(conn->internal->away);
603 conn->internal->away = NULL;
607 if (!conn->internal->away)
608 conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
609 if (conn->internal->away->away)
610 silc_free(conn->internal->away->away);
611 conn->internal->away->away = strdup(message);