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->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 silc_packet_encrypt(cipher, hmac, conn->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;
152 if (packet->src_id_type != SILC_ID_CLIENT)
155 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
160 /* Check whether we know this client already */
161 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
162 if (!remote_client || !remote_client->nickname) {
164 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
165 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
168 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
171 /* Resolve the client info */
172 silc_client_get_client_by_id_resolve(client, conn, remote_id,
173 silc_client_private_message_cb,
174 silc_packet_context_dup(packet));
178 /* Parse the payload and decrypt it also if private message key is set */
179 payload = silc_private_message_payload_parse(packet->buffer->data,
181 remote_client->receive_key);
183 silc_free(remote_id);
187 flags = silc_private_message_get_flags(payload);
189 /* Pass the private message to application */
190 client->internal->ops->private_message(
191 client, conn, remote_client, flags,
192 silc_private_message_get_message(payload,
195 /* See if we are away (gone). If we are away we will reply to the
196 sender with the set away message. */
197 if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
198 /* If it's me, ignore */
199 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
202 /* Send the away message */
203 silc_client_send_private_message(client, conn, remote_client,
204 SILC_MESSAGE_FLAG_AUTOREPLY |
205 SILC_MESSAGE_FLAG_NOREPLY,
207 strlen(conn->away->away), TRUE);
212 silc_private_message_payload_free(payload);
213 silc_free(remote_id);
216 /* Function that actually employes the received private message key */
218 static void silc_client_private_message_key_cb(SilcClient client,
219 SilcClientConnection conn,
220 SilcClientEntry *clients,
221 SilcUInt32 clients_count,
224 SilcPacketContext *packet = (SilcPacketContext *)context;
227 unsigned char *cipher;
233 /* Parse the private message key payload */
234 ret = silc_buffer_unformat(packet->buffer,
235 SILC_STR_UI16_NSTRING(&key, &key_len),
236 SILC_STR_UI16_STRING(&cipher),
241 if (key_len > packet->buffer->len)
244 /* Now take the key in use */
245 if (!silc_client_add_private_message_key(client, conn, clients[0],
246 cipher, key, key_len, FALSE, TRUE))
249 /* Print some info for application */
250 client->internal->ops->say(
251 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
252 "Received private message key from %s%s%s %s%s%s",
253 clients[0]->nickname,
254 clients[0]->server ? "@" : "",
255 clients[0]->server ? clients[0]->server : "",
256 clients[0]->username ? "(" : "",
257 clients[0]->username ? clients[0]->username : "",
258 clients[0]->username ? ")" : "");
261 silc_packet_context_free(packet);
264 /* Processes incoming Private Message Key payload. The libary always
265 accepts the key and takes it into use. */
267 void silc_client_private_message_key(SilcClient client,
268 SilcSocketConnection sock,
269 SilcPacketContext *packet)
271 SilcClientID *remote_id;
273 if (packet->src_id_type != SILC_ID_CLIENT)
276 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
281 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
282 silc_client_private_message_key_cb,
283 silc_packet_context_dup(packet));
284 silc_free(remote_id);
287 /* Adds private message key to the client library. The key will be used to
288 encrypt all private message between the client and the remote client
289 indicated by the `client_entry'. If the `key' is NULL and the boolean
290 value `generate_key' is TRUE the library will generate random key.
291 The `key' maybe for example pre-shared-key, passphrase or similar.
292 The `cipher' MAY be provided but SHOULD be NULL to assure that the
293 requirements of the SILC protocol are met. The API, however, allows
294 to allocate any cipher.
296 If `responder' is TRUE then the sending and receiving keys will be
297 set according the client being the receiver of the private key. If
298 FALSE the client is being the sender (or negotiator) of the private
301 It is not necessary to set key for normal private message usage. If the
302 key is not set then the private messages are encrypted using normal
303 session keys. Setting the private key, however, increases the security.
305 Returns FALSE if the key is already set for the `client_entry', TRUE
308 int silc_client_add_private_message_key(SilcClient client,
309 SilcClientConnection conn,
310 SilcClientEntry client_entry,
317 unsigned char private_key[32];
320 SilcSKEKeyMaterial *keymat;
322 assert(client_entry);
324 /* Return FALSE if key already set */
325 if (client_entry->send_key && client_entry->receive_key)
329 cipher = SILC_DEFAULT_CIPHER;
331 /* Check the requested cipher */
332 if (!silc_cipher_is_supported(cipher))
335 /* Generate key if not provided */
336 if (generate_key == TRUE) {
338 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
341 client_entry->generated = TRUE;
345 client_entry->key = silc_memdup(key, key_len);
346 client_entry->key_len = key_len;
348 /* Produce the key material as the protocol defines */
349 keymat = silc_calloc(1, sizeof(*keymat));
350 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
351 client->internal->md5hash, keymat)
352 != SILC_SKE_STATUS_OK)
355 /* Allocate the ciphers */
356 silc_cipher_alloc(cipher, &client_entry->send_key);
357 silc_cipher_alloc(cipher, &client_entry->receive_key);
360 if (responder == TRUE) {
361 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
362 keymat->enc_key_len);
363 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
364 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
365 keymat->enc_key_len);
366 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
368 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
369 keymat->enc_key_len);
370 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
371 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
372 keymat->enc_key_len);
373 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
376 /* Free the key material */
377 silc_ske_free_key_material(keymat);
382 /* Same as above but takes the key material from the SKE key material
383 structure. This structure is received if the application uses the
384 silc_client_send_key_agreement to negotiate the key material. The
385 `cipher' SHOULD be provided as it is negotiated also in the SKE
388 int silc_client_add_private_message_key_ske(SilcClient client,
389 SilcClientConnection conn,
390 SilcClientEntry client_entry,
392 SilcSKEKeyMaterial *key,
395 assert(client_entry);
397 /* Return FALSE if key already set */
398 if (client_entry->send_key && client_entry->receive_key)
402 cipher = SILC_DEFAULT_CIPHER;
404 /* Check the requested cipher */
405 if (!silc_cipher_is_supported(cipher))
408 /* Allocate the ciphers */
409 silc_cipher_alloc(cipher, &client_entry->send_key);
410 silc_cipher_alloc(cipher, &client_entry->receive_key);
413 if (responder == TRUE) {
414 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
416 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
417 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
419 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
421 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
423 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
424 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
426 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
432 /* Sends private message key payload to the remote client indicated by
433 the `client_entry'. If the `force_send' is TRUE the packet is sent
434 immediately. Returns FALSE if error occurs, TRUE otherwise. The
435 application should call this function after setting the key to the
438 Note that the key sent using this function is sent to the remote client
439 through the SILC network. The packet is protected using normal session
442 int silc_client_send_private_message_key(SilcClient client,
443 SilcClientConnection conn,
444 SilcClientEntry client_entry,
447 SilcSocketConnection sock = conn->sock;
451 if (!client_entry->send_key || !client_entry->key)
454 SILC_LOG_DEBUG(("Sending private message key"));
456 cipher_len = strlen(client_entry->send_key->cipher->name);
458 /* Create private message key payload */
459 buffer = silc_buffer_alloc(2 + client_entry->key_len);
460 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
461 silc_buffer_format(buffer,
462 SILC_STR_UI_SHORT(client_entry->key_len),
463 SILC_STR_UI_XNSTRING(client_entry->key,
464 client_entry->key_len),
465 SILC_STR_UI_SHORT(cipher_len),
466 SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
470 /* Send the packet */
471 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
472 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
473 buffer->data, buffer->len, force_send);
479 /* Removes the private message from the library. The key won't be used
480 after this to protect the private messages with the remote `client_entry'
481 client. Returns FALSE on error, TRUE otherwise. */
483 int silc_client_del_private_message_key(SilcClient client,
484 SilcClientConnection conn,
485 SilcClientEntry client_entry)
487 assert(client_entry);
489 if (!client_entry->send_key && !client_entry->receive_key)
492 silc_cipher_free(client_entry->send_key);
493 silc_cipher_free(client_entry->receive_key);
495 if (client_entry->key) {
496 memset(client_entry->key, 0, client_entry->key_len);
497 silc_free(client_entry->key);
500 client_entry->send_key = NULL;
501 client_entry->receive_key = NULL;
502 client_entry->key = NULL;
507 /* Returns array of set private message keys associated to the connection
508 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
509 count to the `key_count' argument. The array must be freed by the caller
510 by calling the silc_client_free_private_message_keys function. Note:
511 the keys returned in the array is in raw format. It might not be desired
512 to show the keys as is. The application might choose not to show the keys
513 at all or to show the fingerprints of the keys. */
515 SilcPrivateMessageKeys
516 silc_client_list_private_message_keys(SilcClient client,
517 SilcClientConnection conn,
518 SilcUInt32 *key_count)
520 SilcPrivateMessageKeys keys;
521 SilcUInt32 count = 0;
522 SilcIDCacheEntry id_cache;
523 SilcIDCacheList list;
524 SilcClientEntry entry;
526 if (!silc_idcache_get_all(conn->client_cache, &list))
529 if (!silc_idcache_list_count(list)) {
530 silc_idcache_list_free(list);
534 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
536 silc_idcache_list_first(list, &id_cache);
538 entry = (SilcClientEntry)id_cache->context;
540 if (entry->send_key) {
541 keys[count].client_entry = entry;
542 keys[count].cipher = entry->send_key->cipher->name;
543 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
544 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
548 if (!silc_idcache_list_next(list, &id_cache))
558 /* Frees the SilcPrivateMessageKeys array returned by the function
559 silc_client_list_private_message_keys. */
561 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
562 SilcUInt32 key_count)
567 /* Sets away `message'. The away message may be set when the client's
568 mode is changed to SILC_UMODE_GONE and the client whishes to reply
569 to anyone who sends private message. The `message' will be sent
570 automatically back to the the client who send private message. If
571 away message is already set this replaces the old message with the
572 new one. If `message' is NULL the old away message is removed.
573 The sender may freely free the memory of the `message'. */
575 void silc_client_set_away_message(SilcClient client,
576 SilcClientConnection conn,
579 if (!message && conn->away) {
580 silc_free(conn->away->away);
581 silc_free(conn->away);
587 conn->away = silc_calloc(1, sizeof(*conn->away));
588 if (conn->away->away)
589 silc_free(conn->away->away);
590 conn->away->away = strdup(message);