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;
151 unsigned char *message;
152 SilcUInt32 message_len;
154 if (packet->src_id_type != SILC_ID_CLIENT)
157 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
162 /* Check whether we know this client already */
163 remote_client = silc_client_get_client_by_id(client, conn, remote_id);
164 if (!remote_client || !remote_client->nickname) {
166 if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
167 remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
170 remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
171 remote_client->resolve_cmd_ident = conn->cmd_ident + 1;
174 /* Resolve the client info */
175 silc_client_get_client_by_id_resolve(client, conn, remote_id,
176 silc_client_private_message_cb,
177 silc_packet_context_dup(packet));
181 /* Parse the payload and decrypt it also if private message key is set */
182 payload = silc_private_message_payload_parse(packet->buffer->data,
184 remote_client->receive_key);
186 silc_free(remote_id);
190 flags = silc_private_message_get_flags(payload);
192 /* Pass the private message to application */
193 message = silc_private_message_get_message(payload, &message_len);
194 client->internal->ops->private_message(client, conn, remote_client, flags,
195 message, message_len);
197 /* See if we are away (gone). If we are away we will reply to the
198 sender with the set away message. */
199 if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
200 /* If it's me, ignore */
201 if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
204 /* Send the away message */
205 silc_client_send_private_message(client, conn, remote_client,
206 SILC_MESSAGE_FLAG_AUTOREPLY |
207 SILC_MESSAGE_FLAG_NOREPLY,
209 strlen(conn->away->away), TRUE);
214 silc_private_message_payload_free(payload);
215 silc_free(remote_id);
218 /* Function that actually employes the received private message key */
220 static void silc_client_private_message_key_cb(SilcClient client,
221 SilcClientConnection conn,
222 SilcClientEntry *clients,
223 SilcUInt32 clients_count,
226 SilcPacketContext *packet = (SilcPacketContext *)context;
229 unsigned char *cipher;
235 /* Parse the private message key payload */
236 ret = silc_buffer_unformat(packet->buffer,
237 SILC_STR_UI16_NSTRING(&key, &key_len),
238 SILC_STR_UI16_STRING(&cipher),
243 if (key_len > packet->buffer->len)
246 /* Now take the key in use */
247 if (!silc_client_add_private_message_key(client, conn, clients[0],
248 cipher, key, key_len, FALSE, TRUE))
251 /* Print some info for application */
252 client->internal->ops->say(
253 client, conn, SILC_CLIENT_MESSAGE_AUDIT,
254 "Received private message key from %s%s%s %s%s%s",
255 clients[0]->nickname,
256 clients[0]->server ? "@" : "",
257 clients[0]->server ? clients[0]->server : "",
258 clients[0]->username ? "(" : "",
259 clients[0]->username ? clients[0]->username : "",
260 clients[0]->username ? ")" : "");
263 silc_packet_context_free(packet);
266 /* Processes incoming Private Message Key payload. The libary always
267 accepts the key and takes it into use. */
269 void silc_client_private_message_key(SilcClient client,
270 SilcSocketConnection sock,
271 SilcPacketContext *packet)
273 SilcClientID *remote_id;
275 if (packet->src_id_type != SILC_ID_CLIENT)
278 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
283 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
284 silc_client_private_message_key_cb,
285 silc_packet_context_dup(packet));
286 silc_free(remote_id);
289 /* Adds private message key to the client library. The key will be used to
290 encrypt all private message between the client and the remote client
291 indicated by the `client_entry'. If the `key' is NULL and the boolean
292 value `generate_key' is TRUE the library will generate random key.
293 The `key' maybe for example pre-shared-key, passphrase or similar.
294 The `cipher' MAY be provided but SHOULD be NULL to assure that the
295 requirements of the SILC protocol are met. The API, however, allows
296 to allocate any cipher.
298 If `responder' is TRUE then the sending and receiving keys will be
299 set according the client being the receiver of the private key. If
300 FALSE the client is being the sender (or negotiator) of the private
303 It is not necessary to set key for normal private message usage. If the
304 key is not set then the private messages are encrypted using normal
305 session keys. Setting the private key, however, increases the security.
307 Returns FALSE if the key is already set for the `client_entry', TRUE
310 int silc_client_add_private_message_key(SilcClient client,
311 SilcClientConnection conn,
312 SilcClientEntry client_entry,
319 unsigned char private_key[32];
322 SilcSKEKeyMaterial *keymat;
324 assert(client_entry);
326 /* Return FALSE if key already set */
327 if (client_entry->send_key && client_entry->receive_key)
331 cipher = SILC_DEFAULT_CIPHER;
333 /* Check the requested cipher */
334 if (!silc_cipher_is_supported(cipher))
337 /* Generate key if not provided */
338 if (generate_key == TRUE) {
340 for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
343 client_entry->generated = TRUE;
347 client_entry->key = silc_memdup(key, key_len);
348 client_entry->key_len = key_len;
350 /* Produce the key material as the protocol defines */
351 keymat = silc_calloc(1, sizeof(*keymat));
352 if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
353 client->internal->md5hash, keymat)
354 != SILC_SKE_STATUS_OK)
357 /* Allocate the ciphers */
358 silc_cipher_alloc(cipher, &client_entry->send_key);
359 silc_cipher_alloc(cipher, &client_entry->receive_key);
362 if (responder == TRUE) {
363 silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
364 keymat->enc_key_len);
365 silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
366 silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
367 keymat->enc_key_len);
368 silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
370 silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
371 keymat->enc_key_len);
372 silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
373 silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
374 keymat->enc_key_len);
375 silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
378 /* Free the key material */
379 silc_ske_free_key_material(keymat);
384 /* Same as above but takes the key material from the SKE key material
385 structure. This structure is received if the application uses the
386 silc_client_send_key_agreement to negotiate the key material. The
387 `cipher' SHOULD be provided as it is negotiated also in the SKE
390 int silc_client_add_private_message_key_ske(SilcClient client,
391 SilcClientConnection conn,
392 SilcClientEntry client_entry,
394 SilcSKEKeyMaterial *key,
397 assert(client_entry);
399 /* Return FALSE if key already set */
400 if (client_entry->send_key && client_entry->receive_key)
404 cipher = SILC_DEFAULT_CIPHER;
406 /* Check the requested cipher */
407 if (!silc_cipher_is_supported(cipher))
410 /* Allocate the ciphers */
411 silc_cipher_alloc(cipher, &client_entry->send_key);
412 silc_cipher_alloc(cipher, &client_entry->receive_key);
415 if (responder == TRUE) {
416 silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
418 silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
419 silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
421 silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
423 silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
425 silc_cipher_set_iv(client_entry->send_key, key->send_iv);
426 silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
428 silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
434 /* Sends private message key payload to the remote client indicated by
435 the `client_entry'. If the `force_send' is TRUE the packet is sent
436 immediately. Returns FALSE if error occurs, TRUE otherwise. The
437 application should call this function after setting the key to the
440 Note that the key sent using this function is sent to the remote client
441 through the SILC network. The packet is protected using normal session
444 int silc_client_send_private_message_key(SilcClient client,
445 SilcClientConnection conn,
446 SilcClientEntry client_entry,
449 SilcSocketConnection sock = conn->sock;
453 if (!client_entry->send_key || !client_entry->key)
456 SILC_LOG_DEBUG(("Sending private message key"));
458 cipher_len = strlen(client_entry->send_key->cipher->name);
460 /* Create private message key payload */
461 buffer = silc_buffer_alloc(2 + client_entry->key_len);
462 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
463 silc_buffer_format(buffer,
464 SILC_STR_UI_SHORT(client_entry->key_len),
465 SILC_STR_UI_XNSTRING(client_entry->key,
466 client_entry->key_len),
467 SILC_STR_UI_SHORT(cipher_len),
468 SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
472 /* Send the packet */
473 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
474 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
475 buffer->data, buffer->len, force_send);
481 /* Removes the private message from the library. The key won't be used
482 after this to protect the private messages with the remote `client_entry'
483 client. Returns FALSE on error, TRUE otherwise. */
485 int silc_client_del_private_message_key(SilcClient client,
486 SilcClientConnection conn,
487 SilcClientEntry client_entry)
489 assert(client_entry);
491 if (!client_entry->send_key && !client_entry->receive_key)
494 silc_cipher_free(client_entry->send_key);
495 silc_cipher_free(client_entry->receive_key);
497 if (client_entry->key) {
498 memset(client_entry->key, 0, client_entry->key_len);
499 silc_free(client_entry->key);
502 client_entry->send_key = NULL;
503 client_entry->receive_key = NULL;
504 client_entry->key = NULL;
509 /* Returns array of set private message keys associated to the connection
510 `conn'. Returns allocated SilcPrivateMessageKeys array and the array
511 count to the `key_count' argument. The array must be freed by the caller
512 by calling the silc_client_free_private_message_keys function. Note:
513 the keys returned in the array is in raw format. It might not be desired
514 to show the keys as is. The application might choose not to show the keys
515 at all or to show the fingerprints of the keys. */
517 SilcPrivateMessageKeys
518 silc_client_list_private_message_keys(SilcClient client,
519 SilcClientConnection conn,
520 SilcUInt32 *key_count)
522 SilcPrivateMessageKeys keys;
523 SilcUInt32 count = 0;
524 SilcIDCacheEntry id_cache;
525 SilcIDCacheList list;
526 SilcClientEntry entry;
528 if (!silc_idcache_get_all(conn->client_cache, &list))
531 if (!silc_idcache_list_count(list)) {
532 silc_idcache_list_free(list);
536 keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
538 silc_idcache_list_first(list, &id_cache);
540 entry = (SilcClientEntry)id_cache->context;
542 if (entry->send_key) {
543 keys[count].client_entry = entry;
544 keys[count].cipher = entry->send_key->cipher->name;
545 keys[count].key = entry->generated == FALSE ? entry->key : NULL;
546 keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
550 if (!silc_idcache_list_next(list, &id_cache))
560 /* Frees the SilcPrivateMessageKeys array returned by the function
561 silc_client_list_private_message_keys. */
563 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
564 SilcUInt32 key_count)
569 /* Sets away `message'. The away message may be set when the client's
570 mode is changed to SILC_UMODE_GONE and the client whishes to reply
571 to anyone who sends private message. The `message' will be sent
572 automatically back to the the client who send private message. If
573 away message is already set this replaces the old message with the
574 new one. If `message' is NULL the old away message is removed.
575 The sender may freely free the memory of the `message'. */
577 void silc_client_set_away_message(SilcClient client,
578 SilcClientConnection conn,
581 if (!message && conn->away) {
582 silc_free(conn->away->away);
583 silc_free(conn->away);
589 conn->away = silc_calloc(1, sizeof(*conn->away));
590 if (conn->away->away)
591 silc_free(conn->away->away);
592 conn->away->away = strdup(message);