X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcclient%2Fclient_prvmsg.c;h=6c6c56ca22709c1ed5cf710779b075f8c9062f99;hb=3df964f52d094db8ea9e8981fee73ff2a59e365c;hp=3b43a1f808de058873225f0f786b62d88165696b;hpb=087575e2f4248e52d8db5900f757b847e65d9d91;p=silc.git diff --git a/lib/silcclient/client_prvmsg.c b/lib/silcclient/client_prvmsg.c index 3b43a1f8..6c6c56ca 100644 --- a/lib/silcclient/client_prvmsg.c +++ b/lib/silcclient/client_prvmsg.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2004 Pekka Riikonen + Copyright (C) 1997 - 2006 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,210 +17,162 @@ */ /* $Id$ */ -/* This file includes the private message sending and receiving routines - and private message key handling routines. */ #include "silc.h" #include "silcclient.h" #include "client_internal.h" -/* Sends private message to remote client. If private message key has - not been set with this client then the message will be encrypted using - normal session keys. Private messages are special packets in SILC - network hence we need this own function for them. This is similiar - to silc_client_packet_send_to_channel except that we send private - message. The `data' is the private message. If the `force_send' is - TRUE the packet is sent immediately. */ +/************************** Private Message Send ****************************/ + +/* Sends private message to remote client. */ SilcBool silc_client_send_private_message(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - SilcMessageFlags flags, - unsigned char *data, - SilcUInt32 data_len, - SilcBool force_send) + SilcClientConnection conn, + SilcClientEntry client_entry, + SilcMessageFlags flags, + unsigned char *data, + SilcUInt32 data_len) { - SilcSocketConnection sock; SilcBuffer buffer; - SilcPacketContext packetdata; - const SilcBufferStruct packet; - SilcCipher cipher; - SilcHmac hmac; - int block_len; - SilcBool ret = FALSE; - - assert(client && conn && client_entry); - sock = conn->sock; + SilcBool ret; + SILC_LOG_DEBUG(("Sending private message")); + if (!client || !conn || !client_entry) + return FALSE; + /* Encode private message payload */ - buffer = silc_message_payload_encode(flags, data, data_len, - !client_entry->send_key ? FALSE : - !client_entry->generated, - TRUE, client_entry->send_key, - client_entry->hmac_send, - client->rng, NULL, client->private_key, - client->sha1hash); + buffer = + silc_message_payload_encode(flags, data, data_len, + (!client_entry->internal.send_key ? FALSE : + !client_entry->internal.generated), + TRUE, client_entry->internal.send_key, + client_entry->internal.hmac_send, + client->rng, NULL, conn->private_key, + client->sha1hash, NULL); if (!buffer) { SILC_LOG_ERROR(("Error encoding private message")); return FALSE; } - /* If we don't have private message specific key then private messages - are just as any normal packet thus call normal packet sending. If - the key exist then the encryption process is a bit different and - will be done in the rest of this function. */ - if (!client_entry->send_key) { - silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE, - client_entry->id, SILC_ID_CLIENT, NULL, NULL, - buffer->data, buffer->len, force_send); - ret = TRUE; - goto out; - } - - /* We have private message specific key */ - - /* Get data used in the encryption */ - cipher = conn->internal->send_key; - hmac = conn->internal->hmac_send; - block_len = silc_cipher_get_block_len(cipher); - - /* Set the packet context pointers. */ - data = buffer->data; - data_len = buffer->len; - packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY; - packetdata.type = SILC_PACKET_PRIVATE_MESSAGE; - packetdata.src_id = conn->local_id_data; - packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT); - packetdata.src_id_type = SILC_ID_CLIENT; - packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT); - packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT); - packetdata.dst_id_type = SILC_ID_CLIENT; - data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN + - packetdata.src_id_len + - packetdata.dst_id_len); - packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + - packetdata.src_id_len + packetdata.dst_id_len; - SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + - packetdata.src_id_len + - packetdata.dst_id_len), block_len, packetdata.padlen); - - /* Create the outgoing packet */ - if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock, - data, data_len, (const SilcBuffer)&packet)) { - SILC_LOG_ERROR(("Error assembling packet")); - goto out; - } + /* Send the private message packet */ + ret = silc_packet_send_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE, + client_entry->internal.send_key ? + SILC_PACKET_FLAG_PRIVMSG_KEY : 0, + 0, NULL, SILC_ID_CLIENT, &client_entry->id, + silc_buffer_datalen(buffer), NULL, NULL); - /* Encrypt the header and padding of the packet. */ - silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++, - (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN + - packetdata.src_id_len + packetdata.dst_id_len + - packetdata.padlen); - - SILC_LOG_HEXDUMP(("Private message packet, len %d", packet.len), - packet.data, packet.len); - - /* Now actually send the packet */ - silc_client_packet_send_real(client, sock, force_send); - - /* Check for mandatory rekey */ - if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD) - silc_schedule_task_add(client->schedule, sock->sock, - silc_client_rekey_callback, sock, 0, 1, - SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); - - silc_free(packetdata.dst_id); - - ret = TRUE; - - out: silc_buffer_free(buffer); - return ret; } -static void silc_client_private_message_cb(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) +/************************* Private Message Receive **************************/ + +/* Private message waiting context */ +typedef struct { + SilcMutex wait_lock; + SilcCond wait_cond; + SilcDList message_queue; + unsigned int stopped : 1; +} *SilcClientPrivateMessageWait; + +/* Client resolving callback. This continues the private message packet + processing in the packet processor thread, which is in waiting state + (for incoming packets) when we get here. We can safely continue in + the thread and then return back to waiting when we do it synchronously. */ + +static void silc_client_private_message_resolved(SilcClient client, + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context) { - SilcPacketContext *packet = (SilcPacketContext *)context; - if (!clients) { - silc_packet_context_free(packet); + silc_packet_free(context); return; } - silc_client_private_message(client, conn->sock, packet); - silc_packet_context_free(packet); + /* Continue processing the private message packet */ + silc_fsm_set_state_context(&conn->internal->packet_thread, context); + silc_fsm_next(&conn->internal->packet_thread, silc_client_private_message); + silc_fsm_continue_sync(&conn->internal->packet_thread); } -/* Private message received. This processes the private message and - finally displays it on the screen. */ +/* Private message received. */ -void silc_client_private_message(SilcClient client, - SilcSocketConnection sock, - SilcPacketContext *packet) +SILC_FSM_STATE(silc_client_private_message) { - SilcClientConnection conn = (SilcClientConnection)sock->user_data; + SilcClientConnection conn = fsm_context; + SilcClient client = conn->client; + SilcPacket packet = state_context; SilcMessagePayload payload = NULL; - SilcClientID *remote_id = NULL; + SilcClientID remote_id; SilcClientEntry remote_client; SilcMessageFlags flags; unsigned char *message; SilcUInt32 message_len; - SilcCipher cipher = NULL; - SilcHmac hmac = NULL; + SilcClientPrivateMessageWait pmw; if (packet->src_id_type != SILC_ID_CLIENT) goto out; - remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, - SILC_ID_CLIENT); - if (!remote_id) + if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT, + &remote_id, sizeof(remote_id))) goto out; /* Check whether we know this client already */ - remote_client = silc_client_get_client_by_id(client, conn, remote_id); + remote_client = silc_client_get_client_by_id(client, conn, &remote_id); if (!remote_client || !remote_client->nickname) { - if (remote_client) { - if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) { - remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING; - goto out; - } - remote_client->status |= SILC_CLIENT_STATUS_RESOLVING; - remote_client->resolve_cmd_ident = conn->cmd_ident + 1; - } - - /* Resolve the client info */ - silc_client_get_client_by_id_resolve(client, conn, remote_id, NULL, - silc_client_private_message_cb, - silc_packet_context_dup(packet)); - return; + /* Resolve the client info. We return back to packet thread to receive + other packets while we wait for the resolving to finish. */ + silc_client_get_client_by_id_resolve(client, conn, &remote_id, NULL, + silc_client_private_message_resolved, + packet); + silc_fsm_next(fsm, silc_client_connection_st_packet); + return SILC_FSM_CONTINUE; } - cipher = remote_client->receive_key; - hmac = remote_client->hmac_receive; - if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher && !hmac) { - silc_free(remote_id); - return; - } + if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && + !remote_client->internal.receive_key && + !remote_client->internal.hmac_receive) + goto out; /* Parse the payload and decrypt it also if private message key is set */ - payload = silc_message_payload_parse(packet->buffer->data, - packet->buffer->len, TRUE, - !remote_client->generated, - cipher, hmac); - if (!payload) { - silc_free(remote_id); - return; - } + payload = + silc_message_payload_parse(silc_buffer_datalen(&packet->buffer), + TRUE, !remote_client->internal.generated, + remote_client->internal.receive_key, + remote_client->internal.hmac_receive, + NULL, FALSE, NULL); + if (!payload) + goto out; - flags = silc_message_get_flags(payload); +#if 0 /* We need to rethink this. This doesn't work with multiple + waiters, and performance is suboptimal. */ + /* Check if some thread is waiting for this private message */ + silc_mutex_lock(conn->internal->lock); + if (conn->internal->privmsg_wait && + silc_hash_table_find_ext(conn->internal->privmsg_wait, + &remote_client->id, NULL, (void **)&pmw, + NULL, NULL, silc_hash_id_compare_full, + SILC_32_TO_PTR(SILC_ID_CLIENT))) { + /* Signal that message was received */ + silc_mutex_unlock(conn->internal->lock); + silc_mutex_lock(pmw->wait_lock); + if (!pmw->stopped) { + silc_dlist_add(pmw->message_queue, payload); + silc_cond_broadcast(pmw->wait_cond); + silc_mutex_unlock(pmw->wait_lock); + silc_packet_free(packet); + goto out; + } + silc_mutex_unlock(pmw->wait_lock); + } else + silc_mutex_unlock(conn->internal->lock); +#endif /* 0 */ /* Pass the private message to application */ + flags = silc_message_get_flags(payload); message = silc_message_get_data(payload, &message_len); client->internal->ops->private_message(client, conn, remote_client, payload, flags, message, message_len); @@ -230,7 +182,7 @@ void silc_client_private_message(SilcClient client, if (conn->internal->away && conn->internal->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) { /* If it's me, ignore */ - if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id)) + if (SILC_ID_CLIENT_COMPARE(&remote_id, conn->local_id)) goto out; /* Send the away message */ @@ -238,75 +190,217 @@ void silc_client_private_message(SilcClient client, SILC_MESSAGE_FLAG_AUTOREPLY | SILC_MESSAGE_FLAG_NOREPLY, conn->internal->away->away, - strlen(conn->internal->away->away), TRUE); + strlen(conn->internal->away->away)); } out: + /** Packet processed */ if (payload) silc_message_payload_free(payload); - silc_free(remote_id); + silc_packet_free(packet); + silc_fsm_next(fsm, silc_client_connection_st_packet); + return SILC_FSM_CONTINUE; +} + +#if 0 /* XXX we need to rethink this */ +/* Initialize private message waiting in a thread. */ + +void *silc_client_private_message_wait_init(SilcClientConnection conn, + SilcClientEntry client_entry) +{ + SilcClientPrivateMessageWait pmw; + + pmw = silc_calloc(1, sizeof(*pmw)); + if (!pmw) + return NULL; + + pmw->message_queue = silc_dlist_init(); + if (!pmw->message_queue) { + silc_free(pmw); + return NULL; + } + + /* Allocate mutex and conditional variable */ + if (!silc_mutex_alloc(&pmw->wait_lock)) { + silc_dlist_uninit(pmw->message_queue); + silc_free(pmw); + return NULL; + } + if (!silc_cond_alloc(&pmw->wait_cond)) { + silc_dlist_uninit(pmw->message_queue); + silc_mutex_free(pmw->wait_lock); + silc_free(pmw); + return NULL; + } + + silc_mutex_lock(conn->internal->lock); + + /* Allocate waiting hash table */ + if (!conn->internal->privmsg_wait) { + conn->internal->privmsg_wait = + silc_hash_table_alloc(0, silc_hash_id, + SILC_32_TO_PTR(SILC_ID_CLIENT), + silc_hash_id_compare, + SILC_32_TO_PTR(SILC_ID_CLIENT), NULL, NULL, TRUE); + if (!conn->internal->privmsg_wait) { + silc_mutex_unlock(conn->internal->lock); + silc_dlist_uninit(pmw->message_queue); + silc_mutex_free(pmw->wait_lock); + silc_cond_free(pmw->wait_cond); + silc_free(pmw); + return NULL; + } + } + + /* Add to waiting hash table */ + silc_hash_table_add(conn->internal->privmsg_wait, client_entry->id, pmw); + + silc_mutex_unlock(conn->internal->lock); + + return (void *)pmw; +} + +/* Uninitialize private message waiting. */ + +void silc_client_private_message_wait_uninit(SilcClientConnection conn, + SilcClientEntry client_entry, + void *waiter) +{ + SilcClientPrivateMessageWait pmw = waiter; + SilcMessagePayload payload; + + /* Signal any threads to stop waiting */ + silc_mutex_lock(pmw->wait_lock); + pmw->stopped = TRUE; + silc_cond_broadcast(pmw->wait_cond); + silc_mutex_unlock(pmw->wait_lock); + + /* Re-acquire lock and free resources */ + silc_mutex_lock(pmw->wait_lock); + + /* Free any remaining message */ + silc_dlist_start(pmw->message_queue); + while ((payload = silc_dlist_get(pmw->message_queue))) + silc_message_payload_free(payload); + + silc_dlist_uninit(pmw->message_queue); + silc_cond_free(pmw->wait_cond); + silc_mutex_unlock(pmw->wait_lock); + silc_mutex_free(pmw->wait_lock); + + silc_mutex_lock(conn->internal->lock); + silc_hash_table_del_by_context(conn->internal->privmsg_wait, + client_entry->id, pmw); + silc_mutex_unlock(conn->internal->lock); + + silc_free(pmw); +} + +/* Blocks the calling process or thread until a private message has been + received from the specified client. */ + +SilcBool silc_client_private_message_wait(SilcClientConnection conn, + SilcClientEntry client_entry, + void *waiter, + SilcMessagePayload *payload) +{ + SilcClientPrivateMessageWait pmw = waiter; + SilcPacket packet; + + silc_mutex_lock(pmw->wait_lock); + + /* Wait here until private message has been received */ + while (silc_dlist_count(pmw->message_queue) == 0) { + if (pmw->stopped) { + silc_mutex_unlock(pmw->wait_lock); + return FALSE; + } + silc_cond_wait(pmw->wait_cond, pmw->wait_lock); + } + + /* Return message */ + silc_dlist_start(pmw->message_queue); + *payload = silc_dlist_get(pmw->message_queue); + silc_dlist_del(pmw->message_queue, *payload); + + silc_mutex_unlock(pmw->wait_lock); + + return TRUE; } +#endif /* 0 */ -/* Function that actually employes the received private message key */ +/*************************** Private Message Key ****************************/ + +/* Client resolving callback. Here we simply mark that we are the responder + side of this private message key request. */ static void silc_client_private_message_key_cb(SilcClient client, SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, + SilcStatus status, + SilcDList clients, void *context) { - SilcPacketContext *packet = (SilcPacketContext *)context; - unsigned char *key; - SilcUInt16 key_len; + SilcPacket packet = context; unsigned char *cipher = NULL, *hmac = NULL; + SilcClientEntry client_entry; int ret; - if (!clients) - goto out; + if (!clients) { + silc_packet_free(packet); + return; + } /* Parse the private message key payload */ - ret = silc_buffer_unformat(packet->buffer, - SILC_STR_UI16_NSTRING(&key, &key_len), + ret = silc_buffer_unformat(&packet->buffer, SILC_STR_UI16_STRING_ALLOC(&cipher), SILC_STR_UI16_STRING_ALLOC(&hmac), SILC_STR_END); if (!ret) goto out; - if (key_len > packet->buffer->len) - goto out; - /* Mark that we are responder */ - clients[0]->prv_resp = TRUE; + client_entry = silc_dlist_get(clients); + client_entry->internal.prv_resp = TRUE; + + /* XXX we should notify application that remote wants to set up the + static key */ out: silc_free(cipher); silc_free(hmac); - silc_packet_context_free(packet); + silc_packet_free(packet); } /* Processes incoming Private Message Key payload to indicate that the sender whishes to set up a static private message key. */ -void silc_client_private_message_key(SilcClient client, - SilcSocketConnection sock, - SilcPacketContext *packet) +SILC_FSM_STATE(silc_client_private_message_key) { - SilcClientID *remote_id; + SilcClientConnection conn = fsm_context; + SilcClient client = conn->client; + SilcPacket packet = state_context; + SilcClientID remote_id; - if (packet->src_id_type != SILC_ID_CLIENT) - return; + if (packet->src_id_type != SILC_ID_CLIENT) { + silc_packet_free(packet); + goto out; + } - remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, - SILC_ID_CLIENT); - if (!remote_id) - return; + if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT, + &remote_id, sizeof(remote_id))) { + silc_packet_free(packet); + goto out; + } - silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id, - NULL, + /* Always resolve the remote client. The actual packet is processed + in the resolving callback. */ + silc_client_get_client_by_id_resolve(client, conn, &remote_id, NULL, silc_client_private_message_key_cb, - silc_packet_context_dup(packet)); - silc_free(remote_id); + packet); + + out: + silc_fsm_next(fsm, silc_client_connection_st_packet); + return SILC_FSM_CONTINUE; } /* Adds private message key to the client library. The key will be used to @@ -331,24 +425,26 @@ void silc_client_private_message_key(SilcClient client, otherwise. */ SilcBool silc_client_add_private_message_key(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - const char *cipher, - const char *hmac, - unsigned char *key, - SilcUInt32 key_len, - SilcBool generate_key, - SilcBool responder) + SilcClientConnection conn, + SilcClientEntry client_entry, + const char *cipher, + const char *hmac, + unsigned char *key, + SilcUInt32 key_len, + SilcBool generate_key, + SilcBool responder) { unsigned char private_key[32]; SilcUInt32 len; + SilcSKEKeyMaterial keymat; + SilcBool ret; int i; - SilcSKEKeyMaterial *keymat; - assert(client && client_entry); + if (!client || !client_entry) + return FALSE; /* Return FALSE if key already set */ - if (client_entry->send_key && client_entry->receive_key) + if (client_entry->internal.send_key && client_entry->internal.receive_key) return FALSE; if (!cipher) @@ -369,55 +465,30 @@ SilcBool silc_client_add_private_message_key(SilcClient client, private_key[i] = silc_rng_get_byte_fast(client->rng); key = private_key; key_len = len; - client_entry->generated = TRUE; } /* Save the key */ - client_entry->key = silc_memdup(key, key_len); - client_entry->key_len = key_len; + client_entry->internal.key = silc_memdup(key, key_len); + client_entry->internal.key_len = key_len; /* Produce the key material as the protocol defines */ - keymat = silc_calloc(1, sizeof(*keymat)); - if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16, - client->sha1hash, keymat) - != SILC_SKE_STATUS_OK) + keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16, + client->sha1hash); + if (!keymat) return FALSE; - /* Allocate the cipher and HMAC */ - silc_cipher_alloc(cipher, &client_entry->send_key); - silc_cipher_alloc(cipher, &client_entry->receive_key); - silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send); - silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive); + /* Set the key into use */ + ret = silc_client_add_private_message_key_ske(client, conn, client_entry, + cipher, hmac, keymat, + responder); - /* Set the keys */ - if (responder == TRUE) { - silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key, - keymat->enc_key_len); - silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv); - silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key, - keymat->enc_key_len); - silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv); - silc_hmac_set_key(client_entry->hmac_send, keymat->receive_hmac_key, - keymat->hmac_key_len); - silc_hmac_set_key(client_entry->hmac_receive, keymat->send_hmac_key, - keymat->hmac_key_len); - } else { - silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key, - keymat->enc_key_len); - silc_cipher_set_iv(client_entry->send_key, keymat->send_iv); - silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key, - keymat->enc_key_len); - silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv); - silc_hmac_set_key(client_entry->hmac_send, keymat->send_hmac_key, - keymat->hmac_key_len); - silc_hmac_set_key(client_entry->hmac_receive, keymat->receive_hmac_key, - keymat->hmac_key_len); - } + if (!generate_key) + client_entry->internal.generated = FALSE; /* Free the key material */ silc_ske_free_key_material(keymat); - return TRUE; + return ret; } /* Same as above but takes the key material from the SKE key material @@ -427,17 +498,18 @@ SilcBool silc_client_add_private_message_key(SilcClient client, the SKE protocol. */ SilcBool silc_client_add_private_message_key_ske(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - const char *cipher, - const char *hmac, - SilcSKEKeyMaterial *key, - SilcBool responder) + SilcClientConnection conn, + SilcClientEntry client_entry, + const char *cipher, + const char *hmac, + SilcSKEKeyMaterial keymat, + SilcBool responder) { - assert(client && client_entry); + if (!client || !client_entry) + return FALSE; /* Return FALSE if key already set */ - if (client_entry->send_key && client_entry->receive_key) + if (client_entry->internal.send_key && client_entry->internal.receive_key) return FALSE; if (!cipher) @@ -451,37 +523,51 @@ SilcBool silc_client_add_private_message_key_ske(SilcClient client, if (!silc_hmac_is_supported(hmac)) return FALSE; - client_entry->generated = TRUE; + client_entry->internal.generated = TRUE; /* Allocate the cipher and HMAC */ - silc_cipher_alloc(cipher, &client_entry->send_key); - silc_cipher_alloc(cipher, &client_entry->receive_key); - silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send); - silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive); + if (!silc_cipher_alloc(cipher, &client_entry->internal.send_key)) + return FALSE; + if (!silc_cipher_alloc(cipher, &client_entry->internal.receive_key)) + return FALSE; + if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_send)) + return FALSE; + if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_receive)) + return FALSE; /* Set the keys */ if (responder == TRUE) { - silc_cipher_set_key(client_entry->send_key, key->receive_enc_key, - key->enc_key_len); - silc_cipher_set_iv(client_entry->send_key, key->receive_iv); - silc_cipher_set_key(client_entry->receive_key, key->send_enc_key, - key->enc_key_len); - silc_cipher_set_iv(client_entry->receive_key, key->send_iv); - silc_hmac_set_key(client_entry->hmac_send, key->receive_hmac_key, - key->hmac_key_len); - silc_hmac_set_key(client_entry->hmac_receive, key->send_hmac_key, - key->hmac_key_len); + silc_cipher_set_key(client_entry->internal.send_key, + keymat->receive_enc_key, + keymat->enc_key_len); + silc_cipher_set_iv(client_entry->internal.send_key, + keymat->receive_iv); + silc_cipher_set_key(client_entry->internal.receive_key, + keymat->send_enc_key, + keymat->enc_key_len); + silc_cipher_set_iv(client_entry->internal.receive_key, keymat->send_iv); + silc_hmac_set_key(client_entry->internal.hmac_send, + keymat->receive_hmac_key, + keymat->hmac_key_len); + silc_hmac_set_key(client_entry->internal.hmac_receive, + keymat->send_hmac_key, + keymat->hmac_key_len); } else { - silc_cipher_set_key(client_entry->send_key, key->send_enc_key, - key->enc_key_len); - silc_cipher_set_iv(client_entry->send_key, key->send_iv); - silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key, - key->enc_key_len); - silc_cipher_set_iv(client_entry->receive_key, key->receive_iv); - silc_hmac_set_key(client_entry->hmac_send, key->send_hmac_key, - key->hmac_key_len); - silc_hmac_set_key(client_entry->hmac_receive, key->receive_hmac_key, - key->hmac_key_len); + silc_cipher_set_key(client_entry->internal.send_key, + keymat->send_enc_key, + keymat->enc_key_len); + silc_cipher_set_iv(client_entry->internal.send_key, + keymat->send_iv); + silc_cipher_set_key(client_entry->internal.receive_key, + keymat->receive_enc_key, + keymat->enc_key_len); + silc_cipher_set_iv(client_entry->internal.receive_key, keymat->receive_iv); + silc_hmac_set_key(client_entry->internal.hmac_send, + keymat->send_hmac_key, + keymat->hmac_key_len); + silc_hmac_set_key(client_entry->internal.hmac_receive, + keymat->receive_hmac_key, + keymat->hmac_key_len); } return TRUE; @@ -491,46 +577,48 @@ SilcBool silc_client_add_private_message_key_ske(SilcClient client, going to be the initiator, if and when, the users set up a static private message key (not Key Agreement). */ -SilcBool silc_client_send_private_message_key_request(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry) +SilcBool +silc_client_send_private_message_key_request(SilcClient client, + SilcClientConnection conn, + SilcClientEntry client_entry) { - SilcSocketConnection sock; - SilcBuffer buffer; + SilcBufferStruct buffer; int cipher_len, hmac_len; const char *cipher, *hmac; + SilcBool ret; - assert(client && conn && client_entry); + if (!client || !conn || !client_entry) + return FALSE; - sock = conn->sock; - if (!client_entry->send_key || !client_entry->key) + if (!client_entry->internal.send_key && !client_entry->internal.receive_key) return FALSE; SILC_LOG_DEBUG(("Sending private message key indicator")); - cipher = silc_cipher_get_name(client_entry->send_key); + cipher = silc_cipher_get_name(client_entry->internal.send_key); cipher_len = strlen(cipher); - hmac = silc_hmac_get_name(client_entry->hmac_send); + hmac = silc_hmac_get_name(client_entry->internal.hmac_send); hmac_len = strlen(hmac); /* Create private message key payload */ - buffer = silc_buffer_alloc_size(4 + cipher_len + hmac_len); - silc_buffer_format(buffer, - SILC_STR_UI_SHORT(cipher_len), - SILC_STR_UI_XNSTRING(cipher, - cipher_len), - SILC_STR_UI_SHORT(hmac_len), - SILC_STR_UI_XNSTRING(hmac, - hmac_len), - SILC_STR_END); + memset(&buffer, 0, sizeof(buffer)); + if (silc_buffer_format(&buffer, + SILC_STR_UI_SHORT(cipher_len), + SILC_STR_UI_XNSTRING(cipher, + cipher_len), + SILC_STR_UI_SHORT(hmac_len), + SILC_STR_UI_XNSTRING(hmac, + hmac_len), + SILC_STR_END) < 0) + return FALSE; /* Send the packet */ - silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY, - client_entry->id, SILC_ID_CLIENT, NULL, NULL, - buffer->data, buffer->len, TRUE); - silc_free(buffer); + ret = silc_packet_send_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE_KEY, + 0, 0, NULL, SILC_ID_CLIENT, &client_entry->id, + silc_buffer_datalen(&buffer), NULL, NULL); + silc_buffer_purge(&buffer); - return TRUE; + return ret; } /* Removes the private message from the library. The key won't be used @@ -538,25 +626,26 @@ SilcBool silc_client_send_private_message_key_request(SilcClient client, client. Returns FALSE on error, TRUE otherwise. */ SilcBool silc_client_del_private_message_key(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry) + SilcClientConnection conn, + SilcClientEntry client_entry) { - assert(client && client_entry); + if (!client || !client_entry) + return FALSE; - if (!client_entry->send_key && !client_entry->receive_key) + if (!client_entry->internal.send_key && !client_entry->internal.receive_key) return FALSE; - silc_cipher_free(client_entry->send_key); - silc_cipher_free(client_entry->receive_key); + silc_cipher_free(client_entry->internal.send_key); + silc_cipher_free(client_entry->internal.receive_key); - if (client_entry->key) { - memset(client_entry->key, 0, client_entry->key_len); - silc_free(client_entry->key); + if (client_entry->internal.key) { + memset(client_entry->internal.key, 0, client_entry->internal.key_len); + silc_free(client_entry->internal.key); } - client_entry->send_key = NULL; - client_entry->receive_key = NULL; - client_entry->key = NULL; + client_entry->internal.send_key = NULL; + client_entry->internal.receive_key = NULL; + client_entry->internal.key = NULL; return TRUE; } @@ -576,36 +665,33 @@ silc_client_list_private_message_keys(SilcClient client, { SilcPrivateMessageKeys keys; SilcUInt32 count = 0; + SilcList list; SilcIDCacheEntry id_cache; - SilcIDCacheList list; SilcClientEntry entry; - assert(client && conn); + if (!client || !conn) + return NULL; if (!silc_idcache_get_all(conn->internal->client_cache, &list)) return NULL; - if (!silc_idcache_list_count(list)) { - silc_idcache_list_free(list); + keys = silc_calloc(silc_list_count(list), sizeof(*keys)); + if (!keys) return NULL; - } - - keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys)); - silc_idcache_list_first(list, &id_cache); - while (id_cache) { - entry = (SilcClientEntry)id_cache->context; - - if (entry->send_key) { + silc_list_start(list); + while ((id_cache = silc_list_get(list))) { + entry = id_cache->context; + if (entry->internal.send_key) { keys[count].client_entry = entry; - keys[count].cipher = (char *)silc_cipher_get_name(entry->send_key); - keys[count].key = entry->generated == FALSE ? entry->key : NULL; - keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0; + keys[count].cipher = (char *)silc_cipher_get_name(entry->internal. + send_key); + keys[count].key = (entry->internal.generated == FALSE ? + entry->internal.key : NULL); + keys[count].key_len = (entry->internal.generated == FALSE ? + entry->internal.key_len : 0); count++; } - - if (!silc_idcache_list_next(list, &id_cache)) - break; } if (key_count)