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 = client_entry->send_key;
75 hmac = conn->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 cipher = conn->send_key;
107 silc_packet_encrypt(cipher, hmac, conn->psn_send++,
108 (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
109 packetdata.src_id_len + packetdata.dst_id_len +
112 SILC_LOG_HEXDUMP(("Private message packet, len %d", packet.len),
113 packet.data, packet.len);
115 /* Now actually send the packet */
116 silc_client_packet_send_real(client, sock, force_send);
117 silc_free(packetdata.dst_id);
120 silc_buffer_free(buffer);
123 static void silc_client_private_message_cb(SilcClient client,
124 SilcClientConnection conn,
125 SilcClientEntry *clients,
126 SilcUInt32 clients_count,
129 SilcPacketContext *packet = (SilcPacketContext *)context;
132 silc_packet_context_free(packet);
136 silc_client_private_message(client, conn->sock, packet);
137 silc_packet_context_free(packet);
140 /* Private message received. This processes the private message and
141 finally displays it on the screen. */
143 void silc_client_private_message(SilcClient client,
144 SilcSocketConnection sock,
145 SilcPacketContext *packet)
147 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
148 SilcPrivateMessagePayload payload = NULL;
149 SilcClientID *remote_id = NULL;
150 SilcClientEntry remote_client;
151 SilcMessageFlags flags;
153 if (packet->src_id_type != SILC_ID_CLIENT)
156 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
161 /* Check whether we know this client already */
162 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
163 if (!remote_client || !remote_client->nickname) {
165 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
166 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
169 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
172 /* Resolve the client info */
173 silc_client_get_client_by_id_resolve(client, conn, remote_id,
174 silc_client_private_message_cb,
175 silc_packet_context_dup(packet));
179 /* Parse the payload and decrypt it also if private message key is set */
180 payload = silc_private_message_payload_parse(packet->buffer->data,
182 remote_client->receive_key);
184 silc_free(remote_id);
188 flags = silc_private_message_get_flags(payload);
190 /* Pass the private message to application */
191 client->internal->ops->private_message(
192 client, conn, remote_client, flags,
193 silc_private_message_get_message(payload,
196 /* See if we are away (gone). If we are away we will reply to the
197 sender with the set away message. */
198 if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
199 /* If it's me, ignore */
200 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
203 /* Send the away message */
204 silc_client_send_private_message(client, conn, remote_client,
205 SILC_MESSAGE_FLAG_AUTOREPLY |
206 SILC_MESSAGE_FLAG_NOREPLY,
208 strlen(conn->away->away), TRUE);
213 silc_private_message_payload_free(payload);
214 silc_free(remote_id);
217 /* Function that actually employes the received private message key */
219 static void silc_client_private_message_key_cb(SilcClient client,
220 SilcClientConnection conn,
221 SilcClientEntry *clients,
222 SilcUInt32 clients_count,
225 SilcPacketContext *packet = (SilcPacketContext *)context;
228 unsigned char *cipher;
234 /* Parse the private message key payload */
235 ret = silc_buffer_unformat(packet->buffer,
236 SILC_STR_UI16_NSTRING(&key, &key_len),
237 SILC_STR_UI16_STRING(&cipher),
242 if (key_len > packet->buffer->len)
245 /* Now take the key in use */
246 if (!silc_client_add_private_message_key(client, conn, clients[0],
247 cipher, key, key_len, FALSE, TRUE))
250 /* Print some info for application */
251 client->internal->ops->say(
252 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
253 "Received private message key from %s%s%s %s%s%s",
254 clients[0]->nickname,
255 clients[0]->server ? "@" : "",
256 clients[0]->server ? clients[0]->server : "",
257 clients[0]->username ? "(" : "",
258 clients[0]->username ? clients[0]->username : "",
259 clients[0]->username ? ")" : "");
262 silc_packet_context_free(packet);
265 /* Processes incoming Private Message Key payload. The libary always
266 accepts the key and takes it into use. */
268 void silc_client_private_message_key(SilcClient client,
269 SilcSocketConnection sock,
270 SilcPacketContext *packet)
272 SilcClientID *remote_id;
274 if (packet->src_id_type != SILC_ID_CLIENT)
277 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
282 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
283 silc_client_private_message_key_cb,
284 silc_packet_context_dup(packet));
285 silc_free(remote_id);
288 /* Adds private message key to the client library. The key will be used to
289 encrypt all private message between the client and the remote client
290 indicated by the `client_entry'. If the `key' is NULL and the boolean
291 value `generate_key' is TRUE the library will generate random key.
292 The `key' maybe for example pre-shared-key, passphrase or similar.
293 The `cipher' MAY be provided but SHOULD be NULL to assure that the
294 requirements of the SILC protocol are met. The API, however, allows
295 to allocate any cipher.
297 If `responder' is TRUE then the sending and receiving keys will be
298 set according the client being the receiver of the private key. If
299 FALSE the client is being the sender (or negotiator) of the private
302 It is not necessary to set key for normal private message usage. If the
303 key is not set then the private messages are encrypted using normal
304 session keys. Setting the private key, however, increases the security.
306 Returns FALSE if the key is already set for the `client_entry', TRUE
309 int silc_client_add_private_message_key(SilcClient client,
310 SilcClientConnection conn,
311 SilcClientEntry client_entry,
318 unsigned char private_key[32];
321 SilcSKEKeyMaterial *keymat;
323 assert(client_entry);
325 /* Return FALSE if key already set */
326 if (client_entry->send_key && client_entry->receive_key)
330 cipher = SILC_DEFAULT_CIPHER;
332 /* Check the requested cipher */
333 if (!silc_cipher_is_supported(cipher))
336 /* Generate key if not provided */
337 if (generate_key == TRUE) {
339 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
342 client_entry->generated = TRUE;
346 client_entry->key = silc_memdup(key, key_len);
347 client_entry->key_len = key_len;
349 /* Produce the key material as the protocol defines */
350 keymat = silc_calloc(1, sizeof(*keymat));
351 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
352 client->internal->md5hash, keymat)
353 != SILC_SKE_STATUS_OK)
356 /* Allocate the ciphers */
357 silc_cipher_alloc(cipher, &client_entry->send_key);
358 silc_cipher_alloc(cipher, &client_entry->receive_key);
361 if (responder == TRUE) {
362 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
363 keymat->enc_key_len);
364 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
365 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
366 keymat->enc_key_len);
367 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
369 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
370 keymat->enc_key_len);
371 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
372 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
373 keymat->enc_key_len);
374 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
377 /* Free the key material */
378 silc_ske_free_key_material(keymat);
383 /* Same as above but takes the key material from the SKE key material
384 structure. This structure is received if the application uses the
385 silc_client_send_key_agreement to negotiate the key material. The
386 `cipher' SHOULD be provided as it is negotiated also in the SKE
389 int silc_client_add_private_message_key_ske(SilcClient client,
390 SilcClientConnection conn,
391 SilcClientEntry client_entry,
393 SilcSKEKeyMaterial *key,
396 assert(client_entry);
398 /* Return FALSE if key already set */
399 if (client_entry->send_key && client_entry->receive_key)
403 cipher = SILC_DEFAULT_CIPHER;
405 /* Check the requested cipher */
406 if (!silc_cipher_is_supported(cipher))
409 /* Allocate the ciphers */
410 silc_cipher_alloc(cipher, &client_entry->send_key);
411 silc_cipher_alloc(cipher, &client_entry->receive_key);
414 if (responder == TRUE) {
415 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
417 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
418 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
420 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
422 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
424 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
425 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
427 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
433 /* Sends private message key payload to the remote client indicated by
434 the `client_entry'. If the `force_send' is TRUE the packet is sent
435 immediately. Returns FALSE if error occurs, TRUE otherwise. The
436 application should call this function after setting the key to the
439 Note that the key sent using this function is sent to the remote client
440 through the SILC network. The packet is protected using normal session
443 int silc_client_send_private_message_key(SilcClient client,
444 SilcClientConnection conn,
445 SilcClientEntry client_entry,
448 SilcSocketConnection sock = conn->sock;
452 if (!client_entry->send_key || !client_entry->key)
455 SILC_LOG_DEBUG(("Sending private message key"));
457 cipher_len = strlen(client_entry->send_key->cipher->name);
459 /* Create private message key payload */
460 buffer = silc_buffer_alloc(2 + client_entry->key_len);
461 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
462 silc_buffer_format(buffer,
463 SILC_STR_UI_SHORT(client_entry->key_len),
464 SILC_STR_UI_XNSTRING(client_entry->key,
465 client_entry->key_len),
466 SILC_STR_UI_SHORT(cipher_len),
467 SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
471 /* Send the packet */
472 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
473 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
474 buffer->data, buffer->len, force_send);
480 /* Removes the private message from the library. The key won't be used
481 after this to protect the private messages with the remote `client_entry'
482 client. Returns FALSE on error, TRUE otherwise. */
484 int silc_client_del_private_message_key(SilcClient client,
485 SilcClientConnection conn,
486 SilcClientEntry client_entry)
488 assert(client_entry);
490 if (!client_entry->send_key && !client_entry->receive_key)
493 silc_cipher_free(client_entry->send_key);
494 silc_cipher_free(client_entry->receive_key);
496 if (client_entry->key) {
497 memset(client_entry->key, 0, client_entry->key_len);
498 silc_free(client_entry->key);
501 client_entry->send_key = NULL;
502 client_entry->receive_key = NULL;
503 client_entry->key = NULL;
508 /* Returns array of set private message keys associated to the connection
509 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
510 count to the `key_count' argument. The array must be freed by the caller
511 by calling the silc_client_free_private_message_keys function. Note:
512 the keys returned in the array is in raw format. It might not be desired
513 to show the keys as is. The application might choose not to show the keys
514 at all or to show the fingerprints of the keys. */
516 SilcPrivateMessageKeys
517 silc_client_list_private_message_keys(SilcClient client,
518 SilcClientConnection conn,
519 SilcUInt32 *key_count)
521 SilcPrivateMessageKeys keys;
522 SilcUInt32 count = 0;
523 SilcIDCacheEntry id_cache;
524 SilcIDCacheList list;
525 SilcClientEntry entry;
527 if (!silc_idcache_get_all(conn->client_cache, &list))
530 if (!silc_idcache_list_count(list)) {
531 silc_idcache_list_free(list);
535 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
537 silc_idcache_list_first(list, &id_cache);
539 entry = (SilcClientEntry)id_cache->context;
541 if (entry->send_key) {
542 keys[count].client_entry = entry;
543 keys[count].cipher = entry->send_key->cipher->name;
544 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
545 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
549 if (!silc_idcache_list_next(list, &id_cache))
559 /* Frees the SilcPrivateMessageKeys array returned by the function
560 silc_client_list_private_message_keys. */
562 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
563 SilcUInt32 key_count)
568 /* Sets away `message'. The away message may be set when the client's
569 mode is changed to SILC_UMODE_GONE and the client whishes to reply
570 to anyone who sends private message. The `message' will be sent
571 automatically back to the the client who send private message. If
572 away message is already set this replaces the old message with the
573 new one. If `message' is NULL the old away message is removed.
574 The sender may freely free the memory of the `message'. */
576 void silc_client_set_away_message(SilcClient client,
577 SilcClientConnection conn,
580 if (!message && conn->away) {
581 silc_free(conn->away->away);
582 silc_free(conn->away);
588 conn->away = silc_calloc(1, sizeof(*conn->away));
589 if (conn->away->away)
590 silc_free(conn->away->away);
591 conn->away->away = strdup(message);