X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilcclient%2Fclient_channel.c;h=7dd4f0a6ad59a23572262fb48970de4decda3616;hp=554864320ddc24c53f1e3199218c6aed2a488d83;hb=HEAD;hpb=d5e93886f55a54ba0acd52b799636cf5ea83e060 diff --git a/lib/silcclient/client_channel.c b/lib/silcclient/client_channel.c index 55486432..7dd4f0a6 100644 --- a/lib/silcclient/client_channel.c +++ b/lib/silcclient/client_channel.c @@ -24,6 +24,29 @@ /************************** Channel Message Send ****************************/ +typedef struct { + SilcClient client; + SilcClientConnection conn; + SilcChannelEntry channel; +} *SilcClientChannelMessageContext; + +/* Message payload encoding callback */ + +static void silc_client_send_channel_message_final(SilcBuffer message, + void *context) +{ + SilcClientChannelMessageContext c = context; + + /* Send the channel message */ + if (message) + silc_packet_send_ext(c->conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0, + 0, NULL, SILC_ID_CHANNEL, &c->channel->id, + silc_buffer_datalen(message), NULL, NULL); + + silc_client_unref_channel(c->client, c->conn, c->channel); + silc_free(c); +} + /* Sends channel message to `channel'. */ SilcBool silc_client_send_channel_message(SilcClient client, @@ -35,19 +58,21 @@ SilcBool silc_client_send_channel_message(SilcClient client, unsigned char *data, SilcUInt32 data_len) { + SilcClientChannelMessageContext c; SilcChannelUser chu; - SilcBuffer buffer; SilcCipher cipher; SilcHmac hmac; - SilcBool ret; SilcID sid, rid; SILC_LOG_DEBUG(("Sending channel message")); if (silc_unlikely(!client || !conn || !channel)) return FALSE; - if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash)) + if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash)) { + SILC_LOG_ERROR(("Cannot send signed message without hash, missing " + "arguments")); return FALSE; + } if (silc_unlikely(conn->internal->disconnected)) return FALSE; @@ -74,12 +99,12 @@ SilcBool silc_client_send_channel_message(SilcClient client, if (channel->internal.private_keys) { if (key) { /* Use key application specified */ - cipher = key->cipher; + cipher = key->send_key; hmac = key->hmac; } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY && channel->internal.curr_key) { /* Use current private key */ - cipher = channel->internal.curr_key->cipher; + cipher = channel->internal.curr_key->send_key; hmac = channel->internal.curr_key->hmac; } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY && !channel->internal.curr_key && @@ -88,7 +113,7 @@ SilcBool silc_client_send_channel_message(SilcClient client, and private keys are set. */ silc_dlist_start(channel->internal.private_keys); key = silc_dlist_get(channel->internal.private_keys); - cipher = key->cipher; + cipher = key->send_key; hmac = key->hmac; /* Use this key as current private key */ @@ -109,27 +134,26 @@ SilcBool silc_client_send_channel_message(SilcClient client, return FALSE; } - /* Encode the message payload. This also encrypts the message payload. */ + c = silc_calloc(1, sizeof(*c)); + if (!c) + return FALSE; + + c->client = client; + c->conn = conn; + c->channel = silc_client_ref_channel(client, conn, channel); + sid.type = SILC_ID_CLIENT; sid.u.client_id = chu->client->id; rid.type = SILC_ID_CHANNEL; rid.u.channel_id = chu->channel->id; - buffer = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE, - cipher, hmac, client->rng, NULL, - conn->private_key, hash, &sid, &rid, - NULL); - if (silc_unlikely(!buffer)) { - SILC_LOG_ERROR(("Error encoding channel message")); - return FALSE; - } - /* Send the channel message */ - ret = silc_packet_send_ext(conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0, - 0, NULL, SILC_ID_CHANNEL, &channel->id, - silc_buffer_datalen(buffer), NULL, NULL); + /* Encode the message payload. This also encrypts the message payload. */ + silc_message_payload_encode(flags, data, data_len, TRUE, FALSE, + cipher, hmac, client->rng, NULL, + conn->private_key, hash, &sid, &rid, NULL, + silc_client_send_channel_message_final, c); - silc_buffer_free(buffer); - return ret; + return TRUE; } /************************* Channel Message Receive **************************/ @@ -291,7 +315,7 @@ SILC_FSM_STATE(silc_client_channel_message) /* Parse the message payload. This also decrypts the payload */ payload = silc_message_payload_parse(silc_buffer_data(buffer), silc_buffer_len(buffer), - FALSE, FALSE, key->cipher, + FALSE, FALSE, key->receive_key, key->hmac, packet->src_id, packet->src_id_len, packet->dst_id, @@ -463,12 +487,16 @@ SilcBool silc_client_save_channel_key(SilcClient client, return FALSE; } + channel->cipher = silc_cipher_get_name(channel->internal.send_key); + channel->hmac = silc_hmac_get_name(channel->internal.hmac); + /* Set HMAC key */ silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key, tmp_len, hash); silc_hmac_set_key(channel->internal.hmac, hash, silc_hash_len(silc_hmac_get_hash(channel->internal.hmac))); memset(hash, 0, sizeof(hash)); + silc_channel_key_payload_free(payload); silc_client_unref_channel(client, conn, channel); @@ -544,20 +572,30 @@ SilcBool silc_client_add_channel_private_key(SilcClient client, entry->name = name ? strdup(name) : NULL; /* Allocate the cipher and set the key */ - if (!silc_cipher_alloc(cipher, &entry->cipher)) { + if (!silc_cipher_alloc(cipher, &entry->send_key)) { silc_free(entry); silc_free(entry->name); silc_ske_free_key_material(keymat); return FALSE; } - silc_cipher_set_key(entry->cipher, keymat->send_enc_key, + if (!silc_cipher_alloc(cipher, &entry->receive_key)) { + silc_free(entry); + silc_free(entry->name); + silc_cipher_free(entry->send_key); + silc_ske_free_key_material(keymat); + return FALSE; + } + silc_cipher_set_key(entry->send_key, keymat->send_enc_key, keymat->enc_key_len, TRUE); + silc_cipher_set_key(entry->receive_key, keymat->send_enc_key, + keymat->enc_key_len, FALSE); /* Generate HMAC key from the channel key data and set it */ if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) { silc_free(entry); silc_free(entry->name); - silc_cipher_free(entry->cipher); + silc_cipher_free(entry->send_key); + silc_cipher_free(entry->receive_key); silc_ske_free_key_material(keymat); return FALSE; } @@ -570,8 +608,11 @@ SilcBool silc_client_add_channel_private_key(SilcClient client, /* Add to the private keys list */ silc_dlist_add(channel->internal.private_keys, entry); - if (!channel->internal.curr_key) + if (!channel->internal.curr_key) { channel->internal.curr_key = entry; + channel->cipher = silc_cipher_get_name(entry->send_key); + channel->hmac = silc_cipher_get_name(entry->send_key); + } /* Free the key material */ silc_ske_free_key_material(keymat); @@ -602,12 +643,21 @@ SilcBool silc_client_del_channel_private_keys(SilcClient client, while ((entry = silc_dlist_get(channel->internal.private_keys))) { silc_dlist_del(channel->internal.private_keys, entry); silc_free(entry->name); - silc_cipher_free(entry->cipher); + silc_cipher_free(entry->send_key); + silc_cipher_free(entry->receive_key); silc_hmac_free(entry->hmac); silc_free(entry); } channel->internal.curr_key = NULL; + if (channel->internal.send_key) + channel->cipher = silc_cipher_get_name(channel->internal.send_key); + else + channel->cipher = NULL; + if (channel->internal.hmac) + channel->hmac = silc_hmac_get_name(channel->internal.hmac); + else + channel->hmac = NULL; silc_dlist_uninit(channel->internal.private_keys); channel->internal.private_keys = NULL; @@ -639,12 +689,16 @@ SilcBool silc_client_del_channel_private_key(SilcClient client, if (entry != key) continue; - if (channel->internal.curr_key == entry) + if (channel->internal.curr_key == entry) { channel->internal.curr_key = NULL; + channel->cipher = silc_cipher_get_name(channel->internal.send_key); + channel->hmac = silc_hmac_get_name(channel->internal.hmac); + } silc_dlist_del(channel->internal.private_keys, entry); silc_free(entry->name); - silc_cipher_free(entry->cipher); + silc_cipher_free(entry->send_key); + silc_cipher_free(entry->receive_key); silc_hmac_free(entry->hmac); silc_free(entry); @@ -701,6 +755,8 @@ void silc_client_current_channel_private_key(SilcClient client, if (!channel) return; channel->internal.curr_key = key; + channel->cipher = silc_cipher_get_name(key->send_key); + channel->hmac = silc_hmac_get_name(key->hmac); } /***************************** Utility routines *****************************/ @@ -861,12 +917,29 @@ void silc_client_empty_channel(SilcClient client, SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel, unsigned char *chpk_list, - SilcUInt32 chpk_list_len) + SilcUInt32 chpk_list_len, + SilcBool remove_all) { SilcArgumentDecodedList a, b; SilcDList chpks; SilcBool found; + if (remove_all) { + /* Remove all channel public keys */ + if (!channel->channel_pubkeys) + return FALSE; + + silc_dlist_start(channel->channel_pubkeys); + while ((b = silc_dlist_get(channel->channel_pubkeys))) + silc_dlist_del(channel->channel_pubkeys, b); + + silc_dlist_uninit(channel->channel_pubkeys); + channel->channel_pubkeys = NULL; + + return TRUE; + } + + /* Parse channel public key list and add or remove public keys */ chpks = silc_argument_list_parse_decoded(chpk_list, chpk_list_len, SILC_ARGUMENT_PUBLIC_KEY); if (!chpks)