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 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)remote_id,
166 silc_hash_client_id_compare, NULL,
168 ((SilcClientEntry)id_cache->context)->nickname == NULL) {
170 if (id_cache && id_cache->context) {
171 remote_client = (SilcClientEntry)id_cache->context;
172 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
173 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
176 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
179 /* Resolve the client info */
180 silc_client_get_client_by_id_resolve(client, conn, remote_id,
181 silc_client_private_message_cb,
182 silc_packet_context_dup(packet));
186 remote_client = (SilcClientEntry)id_cache->context;
188 /* Parse the payload and decrypt it also if private message key is set */
189 payload = silc_private_message_payload_parse(packet->buffer->data,
191 remote_client->receive_key);
193 silc_free(remote_id);
197 flags = silc_private_message_get_flags(payload);
199 /* Pass the private message to application */
200 client->internal->ops->private_message(
201 client, conn, remote_client, flags,
202 silc_private_message_get_message(payload,
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->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
208 /* If it's me, ignore */
209 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
212 /* Send the away message */
213 silc_client_send_private_message(client, conn, remote_client,
214 SILC_MESSAGE_FLAG_AUTOREPLY |
215 SILC_MESSAGE_FLAG_NOREPLY,
217 strlen(conn->away->away), TRUE);
222 silc_private_message_payload_free(payload);
223 silc_free(remote_id);
226 /* Function that actually employes the received private message key */
228 static void silc_client_private_message_key_cb(SilcClient client,
229 SilcClientConnection conn,
230 SilcClientEntry *clients,
231 uint32 clients_count,
234 SilcPacketContext *packet = (SilcPacketContext *)context;
237 unsigned char *cipher;
243 /* Parse the private message key payload */
244 ret = silc_buffer_unformat(packet->buffer,
245 SILC_STR_UI16_NSTRING(&key, &key_len),
246 SILC_STR_UI16_STRING(&cipher),
251 if (key_len > packet->buffer->len)
254 /* Now take the key in use */
255 if (!silc_client_add_private_message_key(client, conn, clients[0],
256 cipher, key, key_len, FALSE, TRUE))
259 /* Print some info for application */
260 client->internal->ops->say(
261 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
262 "Received private message key from %s%s%s %s%s%s",
263 clients[0]->nickname,
264 clients[0]->server ? "@" : "",
265 clients[0]->server ? clients[0]->server : "",
266 clients[0]->username ? "(" : "",
267 clients[0]->username ? clients[0]->username : "",
268 clients[0]->username ? ")" : "");
271 silc_packet_context_free(packet);
274 /* Processes incoming Private Message Key payload. The libary always
275 accepts the key and takes it into use. */
277 void silc_client_private_message_key(SilcClient client,
278 SilcSocketConnection sock,
279 SilcPacketContext *packet)
281 SilcClientID *remote_id;
283 if (packet->src_id_type != SILC_ID_CLIENT)
286 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
291 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_calloc(key_len, sizeof(*client_entry->key));
356 memcpy(client_entry->key, key, key_len);
357 client_entry->key_len = key_len;
359 /* Produce the key material as the protocol defines */
360 keymat = silc_calloc(1, sizeof(*keymat));
361 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
362 client->internal->md5hash, keymat)
363 != SILC_SKE_STATUS_OK)
366 /* Allocate the ciphers */
367 silc_cipher_alloc(cipher, &client_entry->send_key);
368 silc_cipher_alloc(cipher, &client_entry->receive_key);
371 if (responder == TRUE) {
372 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
373 keymat->enc_key_len);
374 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
375 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
376 keymat->enc_key_len);
377 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
379 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
380 keymat->enc_key_len);
381 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
382 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
383 keymat->enc_key_len);
384 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
387 /* Free the key material */
388 silc_ske_free_key_material(keymat);
393 /* Same as above but takes the key material from the SKE key material
394 structure. This structure is received if the application uses the
395 silc_client_send_key_agreement to negotiate the key material. The
396 `cipher' SHOULD be provided as it is negotiated also in the SKE
399 int silc_client_add_private_message_key_ske(SilcClient client,
400 SilcClientConnection conn,
401 SilcClientEntry client_entry,
403 SilcSKEKeyMaterial *key,
406 assert(client_entry);
408 /* Return FALSE if key already set */
409 if (client_entry->send_key && client_entry->receive_key)
413 cipher = SILC_DEFAULT_CIPHER;
415 /* Check the requested cipher */
416 if (!silc_cipher_is_supported(cipher))
419 /* Allocate the ciphers */
420 silc_cipher_alloc(cipher, &client_entry->send_key);
421 silc_cipher_alloc(cipher, &client_entry->receive_key);
424 if (responder == TRUE) {
425 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
427 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
428 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
430 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
432 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
434 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
435 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
437 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
443 /* Sends private message key payload to the remote client indicated by
444 the `client_entry'. If the `force_send' is TRUE the packet is sent
445 immediately. Returns FALSE if error occurs, TRUE otherwise. The
446 application should call this function after setting the key to the
449 Note that the key sent using this function is sent to the remote client
450 through the SILC network. The packet is protected using normal session
453 int silc_client_send_private_message_key(SilcClient client,
454 SilcClientConnection conn,
455 SilcClientEntry client_entry,
458 SilcSocketConnection sock = conn->sock;
462 if (!client_entry->send_key || !client_entry->key)
465 SILC_LOG_DEBUG(("Sending private message key"));
467 cipher_len = strlen(client_entry->send_key->cipher->name);
469 /* Create private message key payload */
470 buffer = silc_buffer_alloc(2 + client_entry->key_len);
471 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
472 silc_buffer_format(buffer,
473 SILC_STR_UI_SHORT(client_entry->key_len),
474 SILC_STR_UI_XNSTRING(client_entry->key,
475 client_entry->key_len),
476 SILC_STR_UI_SHORT(cipher_len),
477 SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
481 /* Send the packet */
482 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
483 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
484 buffer->data, buffer->len, force_send);
490 /* Removes the private message from the library. The key won't be used
491 after this to protect the private messages with the remote `client_entry'
492 client. Returns FALSE on error, TRUE otherwise. */
494 int silc_client_del_private_message_key(SilcClient client,
495 SilcClientConnection conn,
496 SilcClientEntry client_entry)
498 assert(client_entry);
500 if (!client_entry->send_key && !client_entry->receive_key)
503 silc_cipher_free(client_entry->send_key);
504 silc_cipher_free(client_entry->receive_key);
506 if (client_entry->key) {
507 memset(client_entry->key, 0, client_entry->key_len);
508 silc_free(client_entry->key);
511 client_entry->send_key = NULL;
512 client_entry->receive_key = NULL;
513 client_entry->key = NULL;
518 /* Returns array of set private message keys associated to the connection
519 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
520 count to the `key_count' argument. The array must be freed by the caller
521 by calling the silc_client_free_private_message_keys function. Note:
522 the keys returned in the array is in raw format. It might not be desired
523 to show the keys as is. The application might choose not to show the keys
524 at all or to show the fingerprints of the keys. */
526 SilcPrivateMessageKeys
527 silc_client_list_private_message_keys(SilcClient client,
528 SilcClientConnection conn,
531 SilcPrivateMessageKeys keys;
533 SilcIDCacheEntry id_cache;
534 SilcIDCacheList list;
535 SilcClientEntry entry;
537 if (!silc_idcache_get_all(conn->client_cache, &list))
540 if (!silc_idcache_list_count(list)) {
541 silc_idcache_list_free(list);
545 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
547 silc_idcache_list_first(list, &id_cache);
549 entry = (SilcClientEntry)id_cache->context;
551 if (entry->send_key) {
552 keys[count].client_entry = entry;
553 keys[count].cipher = entry->send_key->cipher->name;
554 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
555 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
559 if (!silc_idcache_list_next(list, &id_cache))
569 /* Frees the SilcPrivateMessageKeys array returned by the function
570 silc_client_list_private_message_keys. */
572 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
578 /* Sets away `message'. The away message may be set when the client's
579 mode is changed to SILC_UMODE_GONE and the client whishes to reply
580 to anyone who sends private message. The `message' will be sent
581 automatically back to the the client who send private message. If
582 away message is already set this replaces the old message with the
583 new one. If `message' is NULL the old away message is removed.
584 The sender may freely free the memory of the `message'. */
586 void silc_client_set_away_message(SilcClient client,
587 SilcClientConnection conn,
590 if (!message && conn->away) {
591 silc_free(conn->away->away);
592 silc_free(conn->away);
598 conn->away = silc_calloc(1, sizeof(*conn->away));
599 if (conn->away->away)
600 silc_free(conn->away->away);
601 conn->away->away = strdup(message);