+Thu Sep 13 20:24:52 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added defines SILC_DEFAULT_CIPHER, SILC_DEFAULT_HMAC,
+ SILC_DEFAULT_HASH and SILC_DEFAULT_PKCS in the file
+ lib/silccrypt/[silccipher.h|silchmac.h|silchash.h|silcpkcs.h].
+
+ * Removed channel key rekey task deleting from the function
+ silc_server_save_channel_key. Affected file silcd/server.c.
+ Added explicit timeout task context instead that is used to
+ delete the task if we are registering a new task before the
+ new task has elapsed.
+
+ * When channel key rekey occurs the client library now saves
+ the old channel key for a short period of time (10 seconds) and
+ is able to use it in case some is still sending channel
+ messages encrypted with the old key after the rekey. Affected
+ file lib/silcclient/[idlist.h|client_channel.c].
+
Sun Sep 9 15:49:16 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
* Added check to the silc_server_new_id_real to not accept
TODO/bugs In SILC Server
========================
- o When the primary router connection is lost the server should be marked
- standalone again untill the connection is resumed back to the router.
-
o Add perhaps /var/run/silcd.pid for PID information for the server.
o Add a timeout to handling incmoing JOIN commands. It should be
/* Delete old cipher and allocate default one */
silc_cipher_free(channel->channel_key);
- if (!silc_cipher_alloc(cipher ? cipher : "aes-256-cbc",
+ if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER,
&channel->channel_key)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
/* Delete old hmac and allocate default one */
silc_hmac_free(channel->hmac);
- if (!silc_hmac_alloc(hmac ? hmac : "hmac-sha1-96", NULL,
+ if (!silc_hmac_alloc(hmac ? hmac : SILC_DEFAULT_HMAC, NULL,
&channel->hmac)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
channel->channel_key = channel_key;
channel->hmac = hmac;
if (!channel->hmac)
- if (!silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac)) {
+ if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
silc_free(channel);
return NULL;
}
void *context;
SilcChannelEntry channel;
uint32 key_len;
+ SilcTask task;
} *SilcServerChannelRekey;
/* Generic rekey context for connections */
return;
}
- switch(ctx->conn_type) {
+ switch (ctx->conn_type) {
case SILC_SOCKET_TYPE_CLIENT:
{
SilcClientEntry client;
case SILC_SOCKET_TYPE_CLIENT:
/* Parse the packet with timeout */
silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_packet_parse_real,
- (void *)parser_context, 0, 100000,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ silc_server_packet_parse_real,
+ (void *)parser_context, 0, 100000,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
break;
case SILC_SOCKET_TYPE_SERVER:
case SILC_SOCKET_TYPE_ROUTER:
/* Packets from servers are parsed as soon as possible */
silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_packet_parse_real,
- (void *)parser_context, 0, 1,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ silc_server_packet_parse_real,
+ (void *)parser_context, 0, 1,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
break;
default:
return;
SILC_LOG_DEBUG(("Parsing packet type %d", type));
/* Parse the packet type */
- switch(type) {
+ switch (type) {
case SILC_PACKET_DISCONNECT:
SILC_LOG_DEBUG(("Disconnect packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
sconn->remote_port = port;
silc_schedule_task_add(server->schedule, 0,
- silc_server_connect_router,
- (void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ silc_server_connect_router,
+ (void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
SILC_TASK_CALLBACK(silc_server_close_connection_final)
i->server = server;
i->client = client;
silc_schedule_task_add(server->schedule, 0,
- silc_server_free_client_data_timeout,
- (void *)i, 300, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ silc_server_free_client_data_timeout,
+ (void *)i, 300, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
client->router = NULL;
client->connection = NULL;
{
SILC_LOG_DEBUG(("Start"));
- switch(sock->type) {
+ switch (sock->type) {
case SILC_SOCKET_TYPE_CLIENT:
{
SilcClientEntry user_data = (SilcClientEntry)sock->user_data;
while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
if (!silc_server_create_channel_key(server, channel, 0))
return FALSE;
+
+ /* Do not send the channel key if private channel key mode is set */
+ if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
+ continue;
+
silc_server_send_channel_key(server, NULL, channel,
server->server_type == SILC_ROUTER ?
FALSE : !server->standalone);
SILC_LOG_DEBUG(("Creating new channel"));
if (!cipher)
- cipher = "aes-256-cbc";
+ cipher = SILC_DEFAULT_CIPHER;
if (!hmac)
- hmac = "hmac-sha1-96";
+ hmac = SILC_DEFAULT_HMAC;
/* Allocate cipher */
if (!silc_cipher_alloc(cipher, &key))
SILC_LOG_DEBUG(("Creating new channel"));
if (!cipher)
- cipher = "aes-256-cbc";
+ cipher = SILC_DEFAULT_CIPHER;
if (!hmac)
- hmac = "hmac-sha1-96";
+ hmac = SILC_DEFAULT_HMAC;
/* Allocate cipher */
if (!silc_cipher_alloc(cipher, &key))
SilcServerChannelRekey rekey = (SilcServerChannelRekey)context;
SilcServer server = (SilcServer)rekey->context;
+ rekey->task = NULL;
+
if (!silc_server_create_channel_key(server, rekey->channel, rekey->key_len))
return;
+
silc_server_send_channel_key(server, NULL, rekey->channel, FALSE);
}
}
if (!channel->channel_key)
- if (!silc_cipher_alloc("aes-256-cbc", &channel->channel_key))
+ if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->channel_key))
return FALSE;
if (key_len)
/* Generate HMAC key from the channel key data and set it */
if (!channel->hmac)
- silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac);
+ silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac);
silc_hash_make(channel->hmac->hash, channel->key, len, hash);
silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
memset(hash, 0, sizeof(hash));
channel->rekey->context = (void *)server;
channel->rekey->channel = channel;
channel->rekey->key_len = key_len;
+ if (channel->rekey->task)
+ silc_schedule_task_del(server->schedule, channel->rekey->task);
- silc_schedule_task_add(server->schedule, 0,
- silc_server_channel_key_rekey,
- (void *)channel->rekey, 3600, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ channel->rekey->task =
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_channel_key_rekey,
+ (void *)channel->rekey, 3600, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
return TRUE;
/* Generate HMAC key from the channel key data and set it */
if (!channel->hmac)
- silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac);
+ silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac);
silc_hash_make(channel->hmac->hash, tmp, tmp_len, hash);
silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
channel->rekey = silc_calloc(1, sizeof(*channel->rekey));
channel->rekey->context = (void *)server;
channel->rekey->channel = channel;
+ if (channel->rekey->task)
+ silc_schedule_task_del(server->schedule, channel->rekey->task);
- silc_schedule_task_del_by_callback(server->schedule,
- silc_server_channel_key_rekey);
- silc_schedule_task_add(server->schedule, 0,
- silc_server_channel_key_rekey,
- (void *)channel->rekey, 3600, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ channel->rekey->task =
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_channel_key_rekey,
+ (void *)channel->rekey, 3600, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
out:
- if (id)
- silc_free(id);
+ silc_free(id);
if (payload)
silc_channel_key_payload_free(payload);
while (id_cache) {
entry = (SilcServerEntry)id_cache->context;
- /* Do not announce the one we've sending our announcments and
+ /* Do not announce the one we've sending our announcements and
do not announce ourself. */
if (entry == remote || entry == server->id_entry) {
if (!silc_idcache_list_next(list, &id_cache))
{
int i;
- /* Cache the received Client ID's and modes. This cache expires
- whenever server sends notify message to channel. It means two things;
- some user has joined or leaved the channel. XXX TODO! */
for (i = 0; i < user_count; i++) {
uint16 idp_len;
uint32 mode;
/* Parse the channel message payload. This also decrypts the payload */
payload = silc_channel_message_payload_parse(buffer, channel->channel_key,
channel->hmac);
- if (!payload)
- goto out;
+
+ /* If decryption failed and we have just performed channel key rekey
+ we will use the old key in decryption. If that fails too then we
+ cannot do more and will drop the packet. */
+ if (!payload) {
+ if (!channel->old_channel_key)
+ goto out;
+
+ payload = silc_channel_message_payload_parse(buffer,
+ channel->old_channel_key,
+ channel->old_hmac);
+ if (!payload)
+ goto out;
+ }
} else if (channel->private_keys) {
SilcChannelPrivateKey entry;
silc_channel_message_payload_free(payload);
}
+/* Timeout callback that is called after a short period of time after the
+ new channel key has been created. This removes the old channel key all
+ together. */
+
+SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
+{
+ SilcChannelEntry channel = (SilcChannelEntry)context;
+
+ if (channel->old_channel_key)
+ silc_cipher_free(channel->old_channel_key);
+ if (channel->old_hmac)
+ silc_hmac_free(channel->old_hmac);
+ channel->old_channel_key = NULL;
+ channel->old_hmac = NULL;
+ channel->rekey_task = NULL;
+}
+
/* Saves channel key from encoded `key_payload'. This is used when we
receive Channel Key Payload and when we are processing JOIN command
reply. */
SilcBuffer key_payload,
SilcChannelEntry channel)
{
- unsigned char *id_string, *key, *cipher, hash[32];
+ unsigned char *id_string, *key, *cipher, *hmac, hash[32];
uint32 tmp_len;
SilcChannelID *id;
SilcIDCacheEntry id_cache = NULL;
channel = (SilcChannelEntry)id_cache->context;
}
+ hmac = channel->hmac ? channel->hmac->hmac->name : SILC_DEFAULT_HMAC;
+
+ /* Save the old key for a short period of time so that we can decrypt
+ channel message even after the rekey if some client would be sending
+ messages with the old key after the rekey. */
+ if (channel->old_channel_key)
+ silc_cipher_free(channel->old_channel_key);
+ if (channel->old_hmac)
+ silc_hmac_free(channel->old_hmac);
+ if (channel->rekey_task)
+ silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
+ channel->old_channel_key = channel->channel_key;
+ channel->old_hmac = channel->hmac;
+ channel->rekey_task =
+ silc_schedule_task_add(conn->client->schedule, 0,
+ silc_client_save_channel_key_rekey, channel,
+ 10, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
+ /* Free the old channel key data */
+ silc_free(channel->key);
+
/* Save the key */
key = silc_channel_key_get_key(payload, &tmp_len);
cipher = silc_channel_key_get_cipher(payload, NULL);
if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
conn->client->ops->say(conn->client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Cannot talk to channel: unsupported cipher %s", cipher);
+ "Cannot talk to channel: unsupported cipher %s",
+ cipher);
goto out;
}
silc_cipher_set_key(channel->channel_key, key, channel->key_len);
/* Generate HMAC key from the channel key data and set it */
- if (!channel->hmac)
- silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac);
+ silc_hmac_alloc(hmac, NULL, &channel->hmac);
silc_hash_make(channel->hmac->hash, key, tmp_len, hash);
silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
memset(hash, 0, sizeof(hash));
return FALSE;
if (!cipher)
- cipher = "aes-256-cbc";
+ cipher = SILC_DEFAULT_CIPHER;
if (!hmac)
- hmac = "hmac-sha1-96";
+ hmac = SILC_DEFAULT_HMAC;
if (!silc_cipher_is_supported(cipher))
return FALSE;
return FALSE;
if (!cipher)
- cipher = "aes-256-cbc";
+ cipher = SILC_DEFAULT_CIPHER;
/* Check the requested cipher */
if (!silc_cipher_is_supported(cipher))
return FALSE;
if (!cipher)
- cipher = "aes-256-cbc";
+ cipher = SILC_DEFAULT_CIPHER;
/* Check the requested cipher */
if (!silc_cipher_is_supported(cipher))
silc_cipher_free(channel->channel_key);
if (channel->hmac)
silc_hmac_free(channel->hmac);
+ if (channel->old_channel_key)
+ silc_cipher_free(channel->old_channel_key);
+ if (channel->old_hmac)
+ silc_hmac_free(channel->old_hmac);
+ if (channel->rekey_task)
+ silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
silc_client_del_channel_private_keys(client, conn, channel);
silc_free(channel);
return ret;
SilcHmac hmac; /* Current HMAC */
SilcDList private_keys; /* List of private keys or NULL */
SilcChannelPrivateKey curr_key; /* Current private key */
+
+ /* Old channel key is saved for a short period of time when rekey occurs
+ in case if someone is sending messages after the rekey encrypted with
+ the old key, we can still decrypt them. */
+ SilcCipher old_channel_key;
+ SilcHmac old_hmac;
+ SilcTask rekey_task;
} *SilcChannelEntry;
/* Server entry context. This represents one server. When server information
*
***/
unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
- uint32 *data_len);
+ uint32 *data_len);
/****f* silccore/SilcChannelAPI/silc_channel_message_get_mac
*
/* Static list of ciphers for silc_cipher_register_default(). */
extern SilcCipherObject silc_default_ciphers[];
+/* Default cipher in the SILC protocol */
+#define SILC_DEFAULT_CIPHER "aes-256-cbc"
+
/* Macros */
/* Function names in SILC Crypto modules. The name of the cipher
/* Default hash functions for silc_hash_register_default(). */
extern SilcHashObject silc_default_hash[];
+/* Default HASH function in the SILC protocol */
+#define SILC_DEFAULT_HASH "sha1"
+
/* Macros */
/* Following macros are used to implement the SILC Hash API. These
/* Default hmacs for silc_hmac_register_default(). */
extern SilcHmacObject silc_default_hmacs[];
+/* Default HMAC in the SILC protocol */
+#define SILC_DEFAULT_HMAC "hmac-sha1-96"
+
/* Prototypes */
bool silc_hmac_register(SilcHmacObject *hmac);
bool silc_hmac_unregister(SilcHmacObject *hmac);
/* Static list of PKCS for silc_pkcs_register_default(). */
extern SilcPKCSObject silc_default_pkcs[];
+/* Default PKXS in the SILC protocol */
+#define SILC_DEFAULT_PKCS "rsa"
+
/* Macros */
/* Macros used to implement the SILC PKCS API */