/*
- client_prvmsg.c
+ client_prvmsg.c
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2001 Pekka Riikonen
+ Copyright (C) 1997 - 2002 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
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; version 2 of the License.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
SilcMessageFlags flags,
unsigned char *data,
SilcUInt32 data_len,
- int force_send)
+ bool force_send)
{
- SilcSocketConnection sock = conn->sock;
+ SilcSocketConnection sock;
SilcBuffer buffer;
SilcPacketContext packetdata;
const SilcBufferStruct packet;
SilcHmac hmac;
int block_len;
+ assert(client && conn && client_entry);
+ sock = conn->sock;
SILC_LOG_DEBUG(("Sending private message"));
/* Encode private message payload */
buffer = silc_private_message_payload_encode(flags,
data_len, data,
client_entry->send_key,
+ client_entry->hmac_send,
client->rng);
/* If we don't have private message specific key then private messages
/* We have private message specific key */
/* Get data used in the encryption */
- cipher = conn->send_key;
- hmac = conn->hmac_send;
+ cipher = conn->internal->send_key;
+ hmac = conn->internal->hmac_send;
block_len = silc_cipher_get_block_len(cipher);
/* Set the packet context pointers. */
packetdata.dst_id_len);
packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
packetdata.src_id_len + packetdata.dst_id_len;
- packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len +
- packetdata.dst_id_len), block_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,
}
/* Encrypt the header and padding of the packet. */
- silc_packet_encrypt(cipher, hmac, conn->psn_send++,
- (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
+ 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);
/* 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);
out:
unsigned char *message;
SilcUInt32 message_len;
SilcCipher cipher = NULL;
+ SilcHmac hmac = NULL;
if (packet->src_id_type != SILC_ID_CLIENT)
goto out;
}
cipher = remote_client->receive_key;
- if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher) {
+ hmac = remote_client->hmac_receive;
+ if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher && !hmac) {
silc_free(remote_id);
return;
}
/* Parse the payload and decrypt it also if private message key is set */
payload = silc_private_message_payload_parse(packet->buffer->data,
- packet->buffer->len, cipher);
+ packet->buffer->len,
+ cipher, hmac);
if (!payload) {
silc_free(remote_id);
return;
/* See if we are away (gone). If we are away we will reply to the
sender with the set away message. */
- if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
+ 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))
goto out;
silc_client_send_private_message(client, conn, remote_client,
SILC_MESSAGE_FLAG_AUTOREPLY |
SILC_MESSAGE_FLAG_NOREPLY,
- conn->away->away,
- strlen(conn->away->away), TRUE);
+ conn->internal->away->away,
+ strlen(conn->internal->away->away), TRUE);
}
out:
SilcPacketContext *packet = (SilcPacketContext *)context;
unsigned char *key;
SilcUInt16 key_len;
- unsigned char *cipher;
+ unsigned char *cipher = NULL, *hmac = NULL;
int ret;
if (!clients)
/* Parse the private message key payload */
ret = silc_buffer_unformat(packet->buffer,
SILC_STR_UI16_NSTRING(&key, &key_len),
- SILC_STR_UI16_STRING(&cipher),
+ SILC_STR_UI16_STRING_ALLOC(&cipher),
+ SILC_STR_UI16_STRING_ALLOC(&hmac),
SILC_STR_END);
if (!ret)
goto out;
/* Now take the key in use */
if (!silc_client_add_private_message_key(client, conn, clients[0],
- cipher, key, key_len, FALSE, TRUE))
+ cipher, hmac, key, key_len,
+ FALSE, TRUE))
goto out;
/* Print some info for application */
clients[0]->username ? ")" : "");
out:
+ silc_free(cipher);
+ silc_free(hmac);
silc_packet_context_free(packet);
}
indicated by the `client_entry'. If the `key' is NULL and the boolean
value `generate_key' is TRUE the library will generate random key.
The `key' maybe for example pre-shared-key, passphrase or similar.
- The `cipher' MAY be provided but SHOULD be NULL to assure that the
- requirements of the SILC protocol are met. The API, however, allows
- to allocate any cipher.
+ The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure
+ that the requirements of the SILC protocol are met. The API, however,
+ allows to allocate any cipher and HMAC.
If `responder' is TRUE then the sending and receiving keys will be
set according the client being the receiver of the private key. If
Returns FALSE if the key is already set for the `client_entry', TRUE
otherwise. */
-int silc_client_add_private_message_key(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- char *cipher,
- unsigned char *key,
- SilcUInt32 key_len,
- bool generate_key,
- bool responder)
+bool 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,
+ bool generate_key,
+ bool responder)
{
unsigned char private_key[32];
SilcUInt32 len;
int i;
SilcSKEKeyMaterial *keymat;
- assert(client_entry);
+ assert(client && client_entry);
/* Return FALSE if key already set */
if (client_entry->send_key && client_entry->receive_key)
if (!cipher)
cipher = SILC_DEFAULT_CIPHER;
+ if (!hmac)
+ hmac = SILC_DEFAULT_HMAC;
- /* Check the requested cipher */
+ /* Check the requested cipher and HMAC */
if (!silc_cipher_is_supported(cipher))
return FALSE;
+ if (!silc_hmac_is_supported(hmac))
+ return FALSE;
/* Generate key if not provided */
if (generate_key == TRUE) {
len = 32;
- for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng);
+ for (i = 0; i < len; i++)
+ private_key[i] = silc_rng_get_byte_fast(client->rng);
key = private_key;
key_len = len;
client_entry->generated = TRUE;
/* 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->internal->md5hash, keymat)
+ client->md5hash, keymat)
!= SILC_SKE_STATUS_OK)
return FALSE;
- /* Allocate the ciphers */
+ /* 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 keys */
if (responder == TRUE) {
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_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);
}
/* Free the key material */
/* Same as above but takes the key material from the SKE key material
structure. This structure is received if the application uses the
silc_client_send_key_agreement to negotiate the key material. The
- `cipher' SHOULD be provided as it is negotiated also in the SKE
- protocol. */
-
-int silc_client_add_private_message_key_ske(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- char *cipher,
- SilcSKEKeyMaterial *key,
- bool responder)
+ `cipher' and `hmac' SHOULD be provided as it is negotiated also in
+ the SKE protocol. */
+
+bool silc_client_add_private_message_key_ske(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry,
+ const char *cipher,
+ const char *hmac,
+ SilcSKEKeyMaterial *key,
+ bool responder)
{
- assert(client_entry);
+ assert(client && client_entry);
/* Return FALSE if key already set */
if (client_entry->send_key && client_entry->receive_key)
if (!cipher)
cipher = SILC_DEFAULT_CIPHER;
+ if (!hmac)
+ hmac = SILC_DEFAULT_HMAC;
- /* Check the requested cipher */
+ /* Check the requested cipher and HMAC */
if (!silc_cipher_is_supported(cipher))
return FALSE;
+ if (!silc_hmac_is_supported(hmac))
+ return FALSE;
- /* Allocate the ciphers */
+ /* 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 keys */
if (responder == TRUE) {
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);
} else {
silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
key->enc_key_len);
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);
}
return TRUE;
through the SILC network. The packet is protected using normal session
keys. */
-int silc_client_send_private_message_key(SilcClient client,
+bool silc_client_send_private_message_key(SilcClient client,
SilcClientConnection conn,
SilcClientEntry client_entry,
- int force_send)
+ bool force_send)
{
- SilcSocketConnection sock = conn->sock;
+ SilcSocketConnection sock;
SilcBuffer buffer;
- int cipher_len;
+ int cipher_len, hmac_len;
+ const char *cipher, *hmac;
+
+ assert(client && conn && client_entry);
+ sock = conn->sock;
if (!client_entry->send_key || !client_entry->key)
return FALSE;
SILC_LOG_DEBUG(("Sending private message key"));
- cipher_len = strlen(client_entry->send_key->cipher->name);
+ cipher = silc_cipher_get_name(client_entry->send_key);
+ cipher_len = strlen(cipher);
+ hmac = silc_hmac_get_name(client_entry->hmac_send);
+ hmac_len = strlen(hmac);
/* Create private message key payload */
buffer = silc_buffer_alloc(2 + client_entry->key_len);
SILC_STR_UI_XNSTRING(client_entry->key,
client_entry->key_len),
SILC_STR_UI_SHORT(cipher_len),
- SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
+ SILC_STR_UI_XNSTRING(cipher,
cipher_len),
+ SILC_STR_UI_SHORT(hmac_len),
+ SILC_STR_UI_XNSTRING(hmac,
+ hmac_len),
SILC_STR_END);
/* Send the packet */
after this to protect the private messages with the remote `client_entry'
client. Returns FALSE on error, TRUE otherwise. */
-int silc_client_del_private_message_key(SilcClient client,
+bool silc_client_del_private_message_key(SilcClient client,
SilcClientConnection conn,
SilcClientEntry client_entry)
{
- assert(client_entry);
+ assert(client && client_entry);
if (!client_entry->send_key && !client_entry->receive_key)
return FALSE;
SilcIDCacheList list;
SilcClientEntry entry;
- if (!silc_idcache_get_all(conn->client_cache, &list))
+ assert(client && conn);
+
+ if (!silc_idcache_get_all(conn->internal->client_cache, &list))
return NULL;
if (!silc_idcache_list_count(list)) {
if (entry->send_key) {
keys[count].client_entry = entry;
- keys[count].cipher = entry->send_key->cipher->name;
+ 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;
count++;
SilcClientConnection conn,
char *message)
{
- if (!message && conn->away) {
- silc_free(conn->away->away);
- silc_free(conn->away);
- conn->away = NULL;
+ assert(client && conn);
+
+ if (!message && conn->internal->away) {
+ silc_free(conn->internal->away->away);
+ silc_free(conn->internal->away);
+ conn->internal->away = NULL;
}
if (message) {
- if (!conn->away)
- conn->away = silc_calloc(1, sizeof(*conn->away));
- if (conn->away->away)
- silc_free(conn->away->away);
- conn->away->away = strdup(message);
+ if (!conn->internal->away)
+ conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
+ if (conn->internal->away->away)
+ silc_free(conn->internal->away->away);
+ conn->internal->away->away = strdup(message);
}
}