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 = NULL;
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 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
165 if (!remote_client ||
166 ((SilcClientEntry)id_cache->context)->nickname == NULL) {
169 remote_client = (SilcClientEntry)id_cache->context;
170 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
171 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
174 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
177 /* Resolve the client info */
178 silc_client_get_client_by_id_resolve(client, conn, remote_id,
179 silc_client_private_message_cb,
180 silc_packet_context_dup(packet));
184 /* Parse the payload and decrypt it also if private message key is set */
185 payload = silc_private_message_payload_parse(packet->buffer->data,
187 remote_client->receive_key);
189 silc_free(remote_id);
193 flags = silc_private_message_get_flags(payload);
195 /* Pass the private message to application */
196 client->internal->ops->private_message(
197 client, conn, remote_client, flags,
198 silc_private_message_get_message(payload,
201 /* See if we are away (gone). If we are away we will reply to the
202 sender with the set away message. */
203 if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
204 /* If it's me, ignore */
205 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
208 /* Send the away message */
209 silc_client_send_private_message(client, conn, remote_client,
210 SILC_MESSAGE_FLAG_AUTOREPLY |
211 SILC_MESSAGE_FLAG_NOREPLY,
213 strlen(conn->away->away), TRUE);
218 silc_private_message_payload_free(payload);
219 silc_free(remote_id);
222 /* Function that actually employes the received private message key */
224 static void silc_client_private_message_key_cb(SilcClient client,
225 SilcClientConnection conn,
226 SilcClientEntry *clients,
227 uint32 clients_count,
230 SilcPacketContext *packet = (SilcPacketContext *)context;
233 unsigned char *cipher;
239 /* Parse the private message key payload */
240 ret = silc_buffer_unformat(packet->buffer,
241 SILC_STR_UI16_NSTRING(&key, &key_len),
242 SILC_STR_UI16_STRING(&cipher),
247 if (key_len > packet->buffer->len)
250 /* Now take the key in use */
251 if (!silc_client_add_private_message_key(client, conn, clients[0],
252 cipher, key, key_len, FALSE, TRUE))
255 /* Print some info for application */
256 client->internal->ops->say(
257 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
258 "Received private message key from %s%s%s %s%s%s",
259 clients[0]->nickname,
260 clients[0]->server ? "@" : "",
261 clients[0]->server ? clients[0]->server : "",
262 clients[0]->username ? "(" : "",
263 clients[0]->username ? clients[0]->username : "",
264 clients[0]->username ? ")" : "");
267 silc_packet_context_free(packet);
270 /* Processes incoming Private Message Key payload. The libary always
271 accepts the key and takes it into use. */
273 void silc_client_private_message_key(SilcClient client,
274 SilcSocketConnection sock,
275 SilcPacketContext *packet)
277 SilcClientID *remote_id;
279 if (packet->src_id_type != SILC_ID_CLIENT)
282 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
287 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
288 silc_client_private_message_key_cb,
289 silc_packet_context_dup(packet));
290 silc_free(remote_id);
293 /* Adds private message key to the client library. The key will be used to
294 encrypt all private message between the client and the remote client
295 indicated by the `client_entry'. If the `key' is NULL and the boolean
296 value `generate_key' is TRUE the library will generate random key.
297 The `key' maybe for example pre-shared-key, passphrase or similar.
298 The `cipher' MAY be provided but SHOULD be NULL to assure that the
299 requirements of the SILC protocol are met. The API, however, allows
300 to allocate any cipher.
302 If `responder' is TRUE then the sending and receiving keys will be
303 set according the client being the receiver of the private key. If
304 FALSE the client is being the sender (or negotiator) of the private
307 It is not necessary to set key for normal private message usage. If the
308 key is not set then the private messages are encrypted using normal
309 session keys. Setting the private key, however, increases the security.
311 Returns FALSE if the key is already set for the `client_entry', TRUE
314 int silc_client_add_private_message_key(SilcClient client,
315 SilcClientConnection conn,
316 SilcClientEntry client_entry,
323 unsigned char private_key[32];
326 SilcSKEKeyMaterial *keymat;
328 assert(client_entry);
330 /* Return FALSE if key already set */
331 if (client_entry->send_key && client_entry->receive_key)
335 cipher = SILC_DEFAULT_CIPHER;
337 /* Check the requested cipher */
338 if (!silc_cipher_is_supported(cipher))
341 /* Generate key if not provided */
342 if (generate_key == TRUE) {
344 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
347 client_entry->generated = TRUE;
351 client_entry->key = silc_calloc(key_len, sizeof(*client_entry->key));
352 memcpy(client_entry->key, key, key_len);
353 client_entry->key_len = key_len;
355 /* Produce the key material as the protocol defines */
356 keymat = silc_calloc(1, sizeof(*keymat));
357 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
358 client->internal->md5hash, keymat)
359 != SILC_SKE_STATUS_OK)
362 /* Allocate the ciphers */
363 silc_cipher_alloc(cipher, &client_entry->send_key);
364 silc_cipher_alloc(cipher, &client_entry->receive_key);
367 if (responder == TRUE) {
368 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
369 keymat->enc_key_len);
370 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
371 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
372 keymat->enc_key_len);
373 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
375 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
376 keymat->enc_key_len);
377 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
378 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
379 keymat->enc_key_len);
380 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
383 /* Free the key material */
384 silc_ske_free_key_material(keymat);
389 /* Same as above but takes the key material from the SKE key material
390 structure. This structure is received if the application uses the
391 silc_client_send_key_agreement to negotiate the key material. The
392 `cipher' SHOULD be provided as it is negotiated also in the SKE
395 int silc_client_add_private_message_key_ske(SilcClient client,
396 SilcClientConnection conn,
397 SilcClientEntry client_entry,
399 SilcSKEKeyMaterial *key,
402 assert(client_entry);
404 /* Return FALSE if key already set */
405 if (client_entry->send_key && client_entry->receive_key)
409 cipher = SILC_DEFAULT_CIPHER;
411 /* Check the requested cipher */
412 if (!silc_cipher_is_supported(cipher))
415 /* Allocate the ciphers */
416 silc_cipher_alloc(cipher, &client_entry->send_key);
417 silc_cipher_alloc(cipher, &client_entry->receive_key);
420 if (responder == TRUE) {
421 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
423 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
424 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
426 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
428 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
430 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
431 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
433 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
439 /* Sends private message key payload to the remote client indicated by
440 the `client_entry'. If the `force_send' is TRUE the packet is sent
441 immediately. Returns FALSE if error occurs, TRUE otherwise. The
442 application should call this function after setting the key to the
445 Note that the key sent using this function is sent to the remote client
446 through the SILC network. The packet is protected using normal session
449 int silc_client_send_private_message_key(SilcClient client,
450 SilcClientConnection conn,
451 SilcClientEntry client_entry,
454 SilcSocketConnection sock = conn->sock;
458 if (!client_entry->send_key || !client_entry->key)
461 SILC_LOG_DEBUG(("Sending private message key"));
463 cipher_len = strlen(client_entry->send_key->cipher->name);
465 /* Create private message key payload */
466 buffer = silc_buffer_alloc(2 + client_entry->key_len);
467 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
468 silc_buffer_format(buffer,
469 SILC_STR_UI_SHORT(client_entry->key_len),
470 SILC_STR_UI_XNSTRING(client_entry->key,
471 client_entry->key_len),
472 SILC_STR_UI_SHORT(cipher_len),
473 SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
477 /* Send the packet */
478 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
479 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
480 buffer->data, buffer->len, force_send);
486 /* Removes the private message from the library. The key won't be used
487 after this to protect the private messages with the remote `client_entry'
488 client. Returns FALSE on error, TRUE otherwise. */
490 int silc_client_del_private_message_key(SilcClient client,
491 SilcClientConnection conn,
492 SilcClientEntry client_entry)
494 assert(client_entry);
496 if (!client_entry->send_key && !client_entry->receive_key)
499 silc_cipher_free(client_entry->send_key);
500 silc_cipher_free(client_entry->receive_key);
502 if (client_entry->key) {
503 memset(client_entry->key, 0, client_entry->key_len);
504 silc_free(client_entry->key);
507 client_entry->send_key = NULL;
508 client_entry->receive_key = NULL;
509 client_entry->key = NULL;
514 /* Returns array of set private message keys associated to the connection
515 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
516 count to the `key_count' argument. The array must be freed by the caller
517 by calling the silc_client_free_private_message_keys function. Note:
518 the keys returned in the array is in raw format. It might not be desired
519 to show the keys as is. The application might choose not to show the keys
520 at all or to show the fingerprints of the keys. */
522 SilcPrivateMessageKeys
523 silc_client_list_private_message_keys(SilcClient client,
524 SilcClientConnection conn,
527 SilcPrivateMessageKeys keys;
529 SilcIDCacheEntry id_cache;
530 SilcIDCacheList list;
531 SilcClientEntry entry;
533 if (!silc_idcache_get_all(conn->client_cache, &list))
536 if (!silc_idcache_list_count(list)) {
537 silc_idcache_list_free(list);
541 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
543 silc_idcache_list_first(list, &id_cache);
545 entry = (SilcClientEntry)id_cache->context;
547 if (entry->send_key) {
548 keys[count].client_entry = entry;
549 keys[count].cipher = entry->send_key->cipher->name;
550 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
551 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
555 if (!silc_idcache_list_next(list, &id_cache))
565 /* Frees the SilcPrivateMessageKeys array returned by the function
566 silc_client_list_private_message_keys. */
568 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
574 /* Sets away `message'. The away message may be set when the client's
575 mode is changed to SILC_UMODE_GONE and the client whishes to reply
576 to anyone who sends private message. The `message' will be sent
577 automatically back to the the client who send private message. If
578 away message is already set this replaces the old message with the
579 new one. If `message' is NULL the old away message is removed.
580 The sender may freely free the memory of the `message'. */
582 void silc_client_set_away_message(SilcClient client,
583 SilcClientConnection conn,
586 if (!message && conn->away) {
587 silc_free(conn->away->away);
588 silc_free(conn->away);
594 conn->away = silc_calloc(1, sizeof(*conn->away));
595 if (conn->away->away)
596 silc_free(conn->away->away);
597 conn->away->away = strdup(message);