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 = conn->sock;
46 SilcPacketContext packetdata;
47 const SilcBufferStruct packet;
52 SILC_LOG_DEBUG(("Sending private message"));
54 /* Encode private message payload */
55 buffer = silc_private_message_payload_encode(flags,
57 client_entry->send_key,
60 /* If we don't have private message specific key then private messages
61 are just as any normal packet thus call normal packet sending. If
62 the key exist then the encryption process is a bit different and
63 will be done in the rest of this function. */
64 if (!client_entry->send_key) {
65 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
66 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
67 buffer->data, buffer->len, force_send);
71 /* We have private message specific key */
73 /* Get data used in the encryption */
74 cipher = conn->internal->send_key;
75 hmac = conn->internal->hmac_send;
76 block_len = silc_cipher_get_block_len(cipher);
78 /* Set the packet context pointers. */
80 data_len = buffer->len;
81 packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
82 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
83 packetdata.src_id = conn->local_id_data;
84 packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
85 packetdata.src_id_type = SILC_ID_CLIENT;
86 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
87 packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
88 packetdata.dst_id_type = SILC_ID_CLIENT;
89 data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
90 packetdata.src_id_len +
91 packetdata.dst_id_len);
92 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
93 packetdata.src_id_len + packetdata.dst_id_len;
94 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
95 packetdata.src_id_len +
96 packetdata.dst_id_len), block_len);
98 /* Create the outgoing packet */
99 if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
100 data, data_len, (const SilcBuffer)&packet)) {
101 SILC_LOG_ERROR(("Error assembling packet"));
105 /* Encrypt the header and padding of the packet. */
106 silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
107 (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
108 packetdata.src_id_len + packetdata.dst_id_len +
111 SILC_LOG_HEXDUMP(("Private message packet, len %d", packet.len),
112 packet.data, packet.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 SilcUInt32 clients_count,
128 SilcPacketContext *packet = (SilcPacketContext *)context;
131 silc_packet_context_free(packet);
135 silc_client_private_message(client, conn->sock, packet);
136 silc_packet_context_free(packet);
139 /* Private message received. This processes the private message and
140 finally displays it on the screen. */
142 void silc_client_private_message(SilcClient client,
143 SilcSocketConnection sock,
144 SilcPacketContext *packet)
146 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
147 SilcPrivateMessagePayload payload = NULL;
148 SilcClientID *remote_id = NULL;
149 SilcClientEntry remote_client;
150 SilcMessageFlags flags;
151 unsigned char *message;
152 SilcUInt32 message_len;
153 SilcCipher cipher = NULL;
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 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
165 if (!remote_client || !remote_client->nickname) {
167 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
168 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
171 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
172 remote_client->resolve_cmd_ident = conn->cmd_ident + 1;
175 /* Resolve the client info */
176 silc_client_get_client_by_id_resolve(client, conn, remote_id, NULL,
177 silc_client_private_message_cb,
178 silc_packet_context_dup(packet));
182 cipher = remote_client->receive_key;
183 if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher) {
184 silc_free(remote_id);
188 /* Parse the payload and decrypt it also if private message key is set */
189 payload = silc_private_message_payload_parse(packet->buffer->data,
190 packet->buffer->len, cipher);
192 silc_free(remote_id);
196 flags = silc_private_message_get_flags(payload);
198 /* Pass the private message to application */
199 message = silc_private_message_get_message(payload, &message_len);
200 client->internal->ops->private_message(client, conn, remote_client, flags,
201 message, message_len);
203 /* See if we are away (gone). If we are away we will reply to the
204 sender with the set away message. */
205 if (conn->internal->away && conn->internal->away->away &&
206 !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
207 /* If it's me, ignore */
208 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
211 /* Send the away message */
212 silc_client_send_private_message(client, conn, remote_client,
213 SILC_MESSAGE_FLAG_AUTOREPLY |
214 SILC_MESSAGE_FLAG_NOREPLY,
215 conn->internal->away->away,
216 strlen(conn->internal->away->away), TRUE);
221 silc_private_message_payload_free(payload);
222 silc_free(remote_id);
225 /* Function that actually employes the received private message key */
227 static void silc_client_private_message_key_cb(SilcClient client,
228 SilcClientConnection conn,
229 SilcClientEntry *clients,
230 SilcUInt32 clients_count,
233 SilcPacketContext *packet = (SilcPacketContext *)context;
236 unsigned char *cipher;
242 /* Parse the private message key payload */
243 ret = silc_buffer_unformat(packet->buffer,
244 SILC_STR_UI16_NSTRING(&key, &key_len),
245 SILC_STR_UI16_STRING(&cipher),
250 if (key_len > packet->buffer->len)
253 /* Now take the key in use */
254 if (!silc_client_add_private_message_key(client, conn, clients[0],
255 cipher, key, key_len, FALSE, TRUE))
258 /* Print some info for application */
259 client->internal->ops->say(
260 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
261 "Received private message key from %s%s%s %s%s%s",
262 clients[0]->nickname,
263 clients[0]->server ? "@" : "",
264 clients[0]->server ? clients[0]->server : "",
265 clients[0]->username ? "(" : "",
266 clients[0]->username ? clients[0]->username : "",
267 clients[0]->username ? ")" : "");
270 silc_packet_context_free(packet);
273 /* Processes incoming Private Message Key payload. The libary always
274 accepts the key and takes it into use. */
276 void silc_client_private_message_key(SilcClient client,
277 SilcSocketConnection sock,
278 SilcPacketContext *packet)
280 SilcClientID *remote_id;
282 if (packet->src_id_type != SILC_ID_CLIENT)
285 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
290 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
292 silc_client_private_message_key_cb,
293 silc_packet_context_dup(packet));
294 silc_free(remote_id);
297 /* Adds private message key to the client library. The key will be used to
298 encrypt all private message between the client and the remote client
299 indicated by the `client_entry'. If the `key' is NULL and the boolean
300 value `generate_key' is TRUE the library will generate random key.
301 The `key' maybe for example pre-shared-key, passphrase or similar.
302 The `cipher' MAY be provided but SHOULD be NULL to assure that the
303 requirements of the SILC protocol are met. The API, however, allows
304 to allocate any cipher.
306 If `responder' is TRUE then the sending and receiving keys will be
307 set according the client being the receiver of the private key. If
308 FALSE the client is being the sender (or negotiator) of the private
311 It is not necessary to set key for normal private message usage. If the
312 key is not set then the private messages are encrypted using normal
313 session keys. Setting the private key, however, increases the security.
315 Returns FALSE if the key is already set for the `client_entry', TRUE
318 int silc_client_add_private_message_key(SilcClient client,
319 SilcClientConnection conn,
320 SilcClientEntry client_entry,
327 unsigned char private_key[32];
330 SilcSKEKeyMaterial *keymat;
332 assert(client_entry);
334 /* Return FALSE if key already set */
335 if (client_entry->send_key && client_entry->receive_key)
339 cipher = SILC_DEFAULT_CIPHER;
341 /* Check the requested cipher */
342 if (!silc_cipher_is_supported(cipher))
345 /* Generate key if not provided */
346 if (generate_key == TRUE) {
348 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
351 client_entry->generated = TRUE;
355 client_entry->key = silc_memdup(key, key_len);
356 client_entry->key_len = key_len;
358 /* Produce the key material as the protocol defines */
359 keymat = silc_calloc(1, sizeof(*keymat));
360 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
361 client->md5hash, keymat)
362 != SILC_SKE_STATUS_OK)
365 /* Allocate the ciphers */
366 silc_cipher_alloc(cipher, &client_entry->send_key);
367 silc_cipher_alloc(cipher, &client_entry->receive_key);
370 if (responder == TRUE) {
371 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
372 keymat->enc_key_len);
373 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
374 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
375 keymat->enc_key_len);
376 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
378 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
379 keymat->enc_key_len);
380 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
381 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
382 keymat->enc_key_len);
383 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
386 /* Free the key material */
387 silc_ske_free_key_material(keymat);
392 /* Same as above but takes the key material from the SKE key material
393 structure. This structure is received if the application uses the
394 silc_client_send_key_agreement to negotiate the key material. The
395 `cipher' SHOULD be provided as it is negotiated also in the SKE
398 int silc_client_add_private_message_key_ske(SilcClient client,
399 SilcClientConnection conn,
400 SilcClientEntry client_entry,
402 SilcSKEKeyMaterial *key,
405 assert(client_entry);
407 /* Return FALSE if key already set */
408 if (client_entry->send_key && client_entry->receive_key)
412 cipher = SILC_DEFAULT_CIPHER;
414 /* Check the requested cipher */
415 if (!silc_cipher_is_supported(cipher))
418 /* Allocate the ciphers */
419 silc_cipher_alloc(cipher, &client_entry->send_key);
420 silc_cipher_alloc(cipher, &client_entry->receive_key);
423 if (responder == TRUE) {
424 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
426 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
427 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
429 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
431 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
433 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
434 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
436 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
442 /* Sends private message key payload to the remote client indicated by
443 the `client_entry'. If the `force_send' is TRUE the packet is sent
444 immediately. Returns FALSE if error occurs, TRUE otherwise. The
445 application should call this function after setting the key to the
448 Note that the key sent using this function is sent to the remote client
449 through the SILC network. The packet is protected using normal session
452 int silc_client_send_private_message_key(SilcClient client,
453 SilcClientConnection conn,
454 SilcClientEntry client_entry,
457 SilcSocketConnection sock = conn->sock;
462 if (!client_entry->send_key || !client_entry->key)
465 SILC_LOG_DEBUG(("Sending private message key"));
467 cipher = silc_cipher_get_name(client_entry->send_key);
468 cipher_len = strlen(cipher);
470 /* Create private message key payload */
471 buffer = silc_buffer_alloc(2 + client_entry->key_len);
472 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
473 silc_buffer_format(buffer,
474 SILC_STR_UI_SHORT(client_entry->key_len),
475 SILC_STR_UI_XNSTRING(client_entry->key,
476 client_entry->key_len),
477 SILC_STR_UI_SHORT(cipher_len),
478 SILC_STR_UI_XNSTRING(cipher,
482 /* Send the packet */
483 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
484 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
485 buffer->data, buffer->len, force_send);
491 /* Removes the private message from the library. The key won't be used
492 after this to protect the private messages with the remote `client_entry'
493 client. Returns FALSE on error, TRUE otherwise. */
495 int silc_client_del_private_message_key(SilcClient client,
496 SilcClientConnection conn,
497 SilcClientEntry client_entry)
499 assert(client_entry);
501 if (!client_entry->send_key && !client_entry->receive_key)
504 silc_cipher_free(client_entry->send_key);
505 silc_cipher_free(client_entry->receive_key);
507 if (client_entry->key) {
508 memset(client_entry->key, 0, client_entry->key_len);
509 silc_free(client_entry->key);
512 client_entry->send_key = NULL;
513 client_entry->receive_key = NULL;
514 client_entry->key = NULL;
519 /* Returns array of set private message keys associated to the connection
520 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
521 count to the `key_count' argument. The array must be freed by the caller
522 by calling the silc_client_free_private_message_keys function. Note:
523 the keys returned in the array is in raw format. It might not be desired
524 to show the keys as is. The application might choose not to show the keys
525 at all or to show the fingerprints of the keys. */
527 SilcPrivateMessageKeys
528 silc_client_list_private_message_keys(SilcClient client,
529 SilcClientConnection conn,
530 SilcUInt32 *key_count)
532 SilcPrivateMessageKeys keys;
533 SilcUInt32 count = 0;
534 SilcIDCacheEntry id_cache;
535 SilcIDCacheList list;
536 SilcClientEntry entry;
538 if (!silc_idcache_get_all(conn->internal->client_cache, &list))
541 if (!silc_idcache_list_count(list)) {
542 silc_idcache_list_free(list);
546 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
548 silc_idcache_list_first(list, &id_cache);
550 entry = (SilcClientEntry)id_cache->context;
552 if (entry->send_key) {
553 keys[count].client_entry = entry;
554 keys[count].cipher = (char *)silc_cipher_get_name(entry->send_key);
555 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
556 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
560 if (!silc_idcache_list_next(list, &id_cache))
570 /* Frees the SilcPrivateMessageKeys array returned by the function
571 silc_client_list_private_message_keys. */
573 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
574 SilcUInt32 key_count)
579 /* Sets away `message'. The away message may be set when the client's
580 mode is changed to SILC_UMODE_GONE and the client whishes to reply
581 to anyone who sends private message. The `message' will be sent
582 automatically back to the the client who send private message. If
583 away message is already set this replaces the old message with the
584 new one. If `message' is NULL the old away message is removed.
585 The sender may freely free the memory of the `message'. */
587 void silc_client_set_away_message(SilcClient client,
588 SilcClientConnection conn,
591 if (!message && conn->internal->away) {
592 silc_free(conn->internal->away->away);
593 silc_free(conn->internal->away);
594 conn->internal->away = NULL;
598 if (!conn->internal->away)
599 conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
600 if (conn->internal->away->away)
601 silc_free(conn->internal->away->away);
602 conn->internal->away->away = strdup(message);