From: Pekka Riikonen Date: Tue, 27 Mar 2001 11:08:03 +0000 (+0000) Subject: updates. X-Git-Tag: SILC.0.1~90 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=9b953153b9253683f0d152a405fe1be37d7d065b updates. --- diff --git a/TODO b/TODO index 2b68195c..b8b30a67 100644 --- a/TODO +++ b/TODO @@ -74,9 +74,6 @@ TODO In SILC Server o TODO in commands (command.c and command_reply.c): o RESTART is not implemented - o CMODE should be rewritten as it uses a lot duplicated code. - Some of the modes may still not be implemented or is implemented - the wrong way. o In servers all command reply funtions should still call the pending command reply even if the reply was error. In client it is not called but in server, I think, it must be called. diff --git a/apps/silc/client_ops.c b/apps/silc/client_ops.c index b9748452..c6134960 100644 --- a/apps/silc/client_ops.c +++ b/apps/silc/client_ops.c @@ -183,10 +183,15 @@ void silc_notify(SilcClient client, SilcClientConnection conn, case SILC_NOTIFY_TYPE_CMODE_CHANGE: client_entry = va_arg(vp, SilcClientEntry); - tmp = silc_client_chmode(va_arg(vp, unsigned int)); + tmp_int = va_arg(vp, unsigned int); + (void)va_arg(vp, char *); + (void)va_arg(vp, char *); channel_entry = va_arg(vp, SilcChannelEntry); + + tmp = silc_client_chmode(tmp_int, channel_entry); + if (tmp) - snprintf(message, sizeof(message), "%s changed channel mode to +%s", + snprintf(message, sizeof(message), "%s changed channel mode to +%s", client_entry->nickname, tmp); else snprintf(message, sizeof(message), "%s removed all channel modes", @@ -596,7 +601,8 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn, client->ops->say(client, conn, "Topic for %s: %s", app->screen->bottom_line->channel, topic); - app->screen->bottom_line->channel_mode = silc_client_chmode(mode); + app->screen->bottom_line->channel_mode = + silc_client_chmode(mode, channel); silc_screen_print_bottom_line(app->screen, 0); /* Resolve the client information */ diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 4dd4aeb3..ed29b05e 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -3311,6 +3311,7 @@ SILC_SERVER_CMD_FUNC(cmode) SilcChannelClientEntry chl; SilcBuffer packet, cidp; unsigned char *tmp, *tmp_id, *tmp_mask; + char *cipher = NULL, *hmac = NULL; unsigned int argc, mode_mask, tmp_len, tmp_len2; unsigned short ident = silc_command_get_ident(cmd->payload); @@ -3392,45 +3393,24 @@ SILC_SERVER_CMD_FUNC(cmode) if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) { /* Channel uses private keys to protect traffic. Client(s) has set the key locally they want to use, server does not know that key. */ - /* Nothing interesting to do here now */ + /* Nothing interesting to do here */ } else { if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) { /* The mode is removed and we need to generate and distribute new channel key. Clients are not using private channel keys anymore after this. */ - /* XXX Duplicated code, make own function for this!! LEAVE uses this - as well */ - /* Re-generate channel key */ silc_server_create_channel_key(server, channel, 0); - /* Encode channel key payload to be distributed on the channel */ - packet = - silc_channel_key_payload_encode(tmp_len2, tmp_id, - strlen(channel->channel_key-> - cipher->name), - channel->channel_key->cipher->name, - channel->key_len / 8, channel->key); - - /* If we are normal server then we will send it to our router. If we - are router we will send it to all local servers that has clients on - the channel */ - if (server->server_type == SILC_SERVER) { - if (!server->standalone) - silc_server_packet_send(server, - cmd->server->router->connection, - SILC_PACKET_CHANNEL_KEY, 0, packet->data, - packet->len, TRUE); - } else { - - } - - /* Send to locally connected clients on the channel */ - silc_server_packet_send_local_channel(server, channel, - SILC_PACKET_CHANNEL_KEY, 0, - packet->data, packet->len, FALSE); - silc_buffer_free(packet); + /* Send the channel key. This sends it to our local clients and if + we are normal server to our router as well. */ + silc_server_send_channel_key(server, NULL, channel, + server->server_type == SILC_ROUTER ? + FALSE : !server->standalone); + + cipher = channel->channel_key->cipher->name; + hmac = channel->hmac->hmac->name; } } @@ -3484,70 +3464,42 @@ SILC_SERVER_CMD_FUNC(cmode) if (mode_mask & SILC_CHANNEL_MODE_CIPHER) { if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) { /* Cipher to use protect the traffic */ - unsigned int key_len; /* Get cipher */ - tmp = silc_argument_get_arg_type(cmd->args, 8, NULL); - if (!tmp) { + cipher = silc_argument_get_arg_type(cmd->args, 5, NULL); + if (!cipher) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } - /* XXX Duplicated code, make own function for this!! */ - /* Delete old cipher and allocate the new one */ silc_cipher_free(channel->channel_key); - if (!silc_cipher_alloc(tmp, &channel->channel_key)) { + if (!silc_cipher_alloc(cipher, &channel->channel_key)) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, SILC_STATUS_ERR_UNKNOWN_ALGORITHM); goto out; } - key_len = silc_cipher_get_key_len(channel->channel_key) / 8; /* Re-generate channel key */ - silc_server_create_channel_key(server, channel, key_len); - - /* Encode channel key payload to be distributed on the channel */ - packet = - silc_channel_key_payload_encode(tmp_len2, tmp_id, - strlen(channel->channel_key-> - cipher->name), - channel->channel_key->cipher->name, - channel->key_len / 8, channel->key); - - /* If we are normal server then we will send it to our router. If we - are router we will send it to all local servers that has clients on - the channel */ - if (server->server_type == SILC_SERVER) { - if (!server->standalone) - silc_server_packet_send(server, - cmd->server->router->connection, - SILC_PACKET_CHANNEL_KEY, 0, packet->data, - packet->len, TRUE); - } else { - - } + silc_server_create_channel_key(server, channel, 0); - /* Send to locally connected clients on the channel */ - silc_server_packet_send_local_channel(server, channel, - SILC_PACKET_CHANNEL_KEY, 0, - packet->data, packet->len, FALSE); - silc_buffer_free(packet); + /* Send the channel key. This sends it to our local clients and if + we are normal server to our router as well. */ + silc_server_send_channel_key(server, NULL, channel, + server->server_type == SILC_ROUTER ? + FALSE : !server->standalone); } } else { if (channel->mode & SILC_CHANNEL_MODE_CIPHER) { /* Cipher mode is unset. Remove the cipher and revert back to default cipher */ - char *cipher = channel->channel_key->cipher->name; - - /* Generate new cipher and key for the channel */ - - /* XXX Duplicated code, make own function for this!! */ + cipher = channel->cipher; /* Delete old cipher and allocate default one */ silc_cipher_free(channel->channel_key); - if (!silc_cipher_alloc(cipher, &channel->channel_key)) { + if (!silc_cipher_alloc(cipher ? cipher : "aes-256-cbc", + &channel->channel_key)) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, SILC_STATUS_ERR_UNKNOWN_ALGORITHM); goto out; @@ -3556,32 +3508,66 @@ SILC_SERVER_CMD_FUNC(cmode) /* Re-generate channel key */ silc_server_create_channel_key(server, channel, 0); - /* Encode channel key payload to be distributed on the channel */ - packet = - silc_channel_key_payload_encode(tmp_len2, tmp_id, - strlen(channel->channel_key-> - cipher->name), - channel->channel_key->cipher->name, - channel->key_len / 8, channel->key); - - /* If we are normal server then we will send it to our router. If we - are router we will send it to all local servers that has clients on - the channel */ - if (server->server_type == SILC_SERVER) { - if (!server->standalone) - silc_server_packet_send(server, - cmd->server->router->connection, - SILC_PACKET_CHANNEL_KEY, 0, packet->data, - packet->len, TRUE); - } else { - + /* Send the channel key. This sends it to our local clients and if + we are normal server to our router as well. */ + silc_server_send_channel_key(server, NULL, channel, + server->server_type == SILC_ROUTER ? + FALSE : !server->standalone); + } + } + + if (mode_mask & SILC_CHANNEL_MODE_HMAC) { + if (!(channel->mode & SILC_CHANNEL_MODE_HMAC)) { + /* HMAC to use protect the traffic */ + unsigned char hash[32]; + + /* Get hmac */ + hmac = silc_argument_get_arg_type(cmd->args, 6, NULL); + if (!hmac) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; } - - /* Send to locally connected clients on the channel */ - silc_server_packet_send_local_channel(server, channel, - SILC_PACKET_CHANNEL_KEY, 0, - packet->data, packet->len, FALSE); - silc_buffer_free(packet); + + /* Delete old hmac and allocate the new one */ + silc_hmac_free(channel->hmac); + if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, + SILC_STATUS_ERR_UNKNOWN_ALGORITHM); + goto out; + } + + /* Set the HMAC key out of current channel key. The client must do + this locally. */ + silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, + hash); + silc_hmac_set_key(channel->hmac, hash, + silc_hash_len(channel->hmac->hash)); + memset(hash, 0, sizeof(hash)); + } + } else { + if (channel->mode & SILC_CHANNEL_MODE_HMAC) { + /* Hmac mode is unset. Remove the hmac and revert back to + default hmac */ + unsigned char hash[32]; + hmac = channel->hmac_name; + + /* Delete old hmac and allocate default one */ + silc_hmac_free(channel->hmac); + if (!silc_hmac_alloc(hmac ? hmac : "hmac-sha1-96", NULL, + &channel->hmac)) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, + SILC_STATUS_ERR_UNKNOWN_ALGORITHM); + goto out; + } + + /* Set the HMAC key out of current channel key. The client must do + this locally. */ + silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, + hash); + silc_hmac_set_key(channel->hmac, hash, + silc_hash_len(channel->hmac->hash)); + memset(hash, 0, sizeof(hash)); } } @@ -3591,16 +3577,19 @@ SILC_SERVER_CMD_FUNC(cmode) /* Send CMODE_CHANGE notify */ cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); silc_server_send_notify_to_channel(server, NULL, channel, FALSE, - SILC_NOTIFY_TYPE_CMODE_CHANGE, 2, + SILC_NOTIFY_TYPE_CMODE_CHANGE, 4, cidp->data, cidp->len, - tmp_mask, tmp_len); + tmp_mask, tmp_len, + cipher, cipher ? strlen(cipher) : 0, + hmac, hmac ? strlen(hmac) : 0); /* Set CMODE notify type to network */ if (!server->standalone) silc_server_send_notify_cmode(server, server->router->connection, server->server_type == SILC_ROUTER ? TRUE : FALSE, channel, - mode_mask, client->id, SILC_ID_CLIENT_LEN); + mode_mask, client->id, SILC_ID_CLIENT_LEN, + cipher, hmac); /* Send command reply to sender */ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE, diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index 4b865ad8..fe25519c 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -722,6 +722,11 @@ SILC_SERVER_CMD_REPLY_FUNC(join) silc_free(id); } + if (entry->hmac_name && hmac) { + silc_free(entry->hmac_name); + entry->hmac_name = strdup(hmac->hmac->name); + } + /* Get the ban list */ tmp = silc_argument_get_arg_type(cmd->args, 8, &len); if (tmp) { diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index 888f5bc2..a15acc16 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -629,6 +629,10 @@ int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry) memset(entry->key, 0, entry->key_len / 8); silc_free(entry->key); } + if (entry->cipher) + silc_free(entry->cipher); + if (entry->hmac_name) + silc_free(entry->hmac_name); /* Free all data, free also any reference from the client's channel list since they share the same memory. */ diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h index 63756484..ae2757d3 100644 --- a/apps/silcd/idlist.h +++ b/apps/silcd/idlist.h @@ -356,6 +356,11 @@ struct SilcClientEntryStruct { Default cipher of the channel. If this is NULL then server picks the cipher to be used. This can be set at SILC_COMMAND_JOIN. + char *hmac_name + + Default hmac of the channel. If this is NULL then server picks + the cipher to be used. This can be set at SILC_COMMAND_JOIN. + SilcServerEntry router This is a pointer to the server list. This is the router server @@ -388,6 +393,7 @@ struct SilcChannelEntryStruct { int global_users; char *topic; char *cipher; + char *hmac_name; unsigned int user_limit; unsigned char *passphrase; diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index ecfab1cf..d261e514 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -425,6 +425,26 @@ void silc_server_notify(SilcServer server, /* Change mode */ channel->mode = mode; silc_free(channel_id); + + /* Get the hmac */ + tmp = silc_argument_get_arg_type(args, 4, &tmp_len); + if (tmp) { + unsigned char hash[32]; + + if (channel->hmac) + silc_hmac_free(channel->hmac); + if (!silc_hmac_alloc(tmp, NULL, &channel->hmac)) + goto out; + + /* Set the HMAC key out of current channel key. The client must do + this locally. */ + silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, + hash); + silc_hmac_set_key(channel->hmac, hash, + silc_hash_len(channel->hmac->hash)); + memset(hash, 0, sizeof(hash)); + } + break; case SILC_NOTIFY_TYPE_CUMODE_CHANGE: diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index 4b271c4d..714479ea 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -947,7 +947,8 @@ void silc_server_send_notify_cmode(SilcServer server, SilcChannelEntry channel, unsigned int mode_mask, SilcClientID *client_id, - unsigned int client_id_len) + unsigned int client_id_len, + char *cipher, char *hmac) { SilcBuffer idp; unsigned char mode[4]; @@ -957,8 +958,10 @@ void silc_server_send_notify_cmode(SilcServer server, silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id, SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE, - 2, idp->data, idp->len, - mode, 4); + 4, idp->data, idp->len, + mode, 4, + cipher, cipher ? strlen(cipher) : 0, + hmac, hmac ? strlen(hmac) : 0); silc_buffer_free(idp); } diff --git a/apps/silcd/packet_send.h b/apps/silcd/packet_send.h index cef2bbe4..89f3d615 100644 --- a/apps/silcd/packet_send.h +++ b/apps/silcd/packet_send.h @@ -127,7 +127,8 @@ void silc_server_send_notify_cmode(SilcServer server, SilcChannelEntry channel, unsigned int mode_mask, SilcClientID *client_id, - unsigned int client_id_len); + unsigned int client_id_len, + char *cipher, char *hmac); void silc_server_send_notify_cumode(SilcServer server, SilcSocketConnection sock, int broadcast, diff --git a/apps/silcd/server.c b/apps/silcd/server.c index df6a94db..a6ae79ff 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -2477,6 +2477,9 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server, return NULL; } + entry->cipher = strdup(cipher); + entry->hmac_name = strdup(hmac); + /* Now create the actual key material */ silc_server_create_channel_key(server, entry, silc_cipher_get_key_len(key) / 8); @@ -2670,6 +2673,10 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server, goto out; } + if (channel->cipher) + silc_free(channel->cipher); + channel->cipher = strdup(cipher); + /* Save the key */ channel->key_len = tmp_len * 8; channel->key = silc_calloc(tmp_len, sizeof(unsigned char)); diff --git a/doc/draft-riikonen-silc-pp-01.nroff b/doc/draft-riikonen-silc-pp-01.nroff index 8ab11cf1..8dddf602 100644 --- a/doc/draft-riikonen-silc-pp-01.nroff +++ b/doc/draft-riikonen-silc-pp-01.nroff @@ -1229,11 +1229,16 @@ ID's sent in arguments are sent inside ID Payload. Sent when channel mode has changed. This type must be sent only to the clients who is joined on the channel whose mode was changed. - Max Arguments: 2 + Max Arguments: 4 Arguments: (1) (2) + (3) [] (4) <[hmac>] The is the client who changed the mode. The - is the new mode mask of the channel. + is the new mode mask of the channel. The client can safely ignore + the argument since the SILC_PACKET_CHANNEL_KEY packet will + force the new channel key change anyway. The argument is + important since the client is responsible of setting the new HMAC + and the hmac key into use. 8 SILC_NOTIFY_TYPE_CUMODE_CHANGE diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 4ea2a2d8..300789bf 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -1285,17 +1285,17 @@ char *silc_client_chmode(unsigned int mode, SilcChannelEntry channel) strncat(string, "a", 1); if (mode & SILC_CHANNEL_MODE_CIPHER) { - char cipher[50]; + char cipher[30]; memset(cipher, 0, sizeof(cipher)); - snprintf(cipher, sizeof(cipher), "c (%s)", + snprintf(cipher, sizeof(cipher), " c (%s)", channel->channel_key->cipher->name); strncat(string, cipher, strlen(cipher)); } if (mode & SILC_CHANNEL_MODE_HMAC) { - char hmac[50]; + char hmac[30]; memset(hmac, 0, sizeof(hmac)); - snprintf(hmac, sizeof(hmac), "h (%s)", + snprintf(hmac, sizeof(hmac), " h (%s)", channel->hmac->hmac->name); strncat(string, hmac, strlen(hmac)); } diff --git a/lib/silcclient/client.h b/lib/silcclient/client.h index f7c6e331..e0ff8e76 100644 --- a/lib/silcclient/client.h +++ b/lib/silcclient/client.h @@ -247,7 +247,7 @@ void silc_client_replace_from_channels(SilcClient client, SilcClientConnection conn, SilcClientEntry old, SilcClientEntry new); -char *silc_client_chmode(unsigned int mode); +char *silc_client_chmode(unsigned int mode, SilcChannelEntry channel); char *silc_client_chumode(unsigned int mode); char *silc_client_chumode_char(unsigned int mode); void silc_client_process_failure(SilcClient client, diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index bccd1009..0aa343ee 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -454,10 +454,28 @@ void silc_client_notify_by_server(SilcClient client, /* Save the new mode */ channel->mode = mode; + /* Get the hmac */ + tmp = silc_argument_get_arg_type(args, 4, &tmp_len); + if (tmp) { + unsigned char hash[32]; + + if (channel->hmac) + silc_hmac_free(channel->hmac); + if (!silc_hmac_alloc(tmp, NULL, &channel->hmac)) + goto out; + + silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, + hash); + silc_hmac_set_key(channel->hmac, hash, + silc_hash_len(channel->hmac->hash)); + memset(hash, 0, sizeof(hash)); + } + /* Notify application. The channel entry is sent last as this notify is for channel but application don't know it from the arguments sent by server. */ - client->ops->notify(client, conn, type, client_entry, mode, channel); + client->ops->notify(client, conn, type, client_entry, mode, NULL, + tmp, channel); break; case SILC_NOTIFY_TYPE_CUMODE_CHANGE: diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index cf3c0c4e..7a6f3ea9 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -1217,13 +1217,23 @@ SILC_CLIENT_CMD_FUNC(cmode) case 'c': if (add) { mode |= SILC_CHANNEL_MODE_CIPHER; - type = 8; + type = 5; arg = cmd->argv[3]; arg_len = cmd->argv_lens[3]; } else { mode &= ~SILC_CHANNEL_MODE_CIPHER; } break; + case 'h': + if (add) { + mode |= SILC_CHANNEL_MODE_HMAC; + type = 6; + arg = cmd->argv[3]; + arg_len = cmd->argv_lens[3]; + } else { + mode &= ~SILC_CHANNEL_MODE_HMAC; + } + break; default: COMMAND_ERROR; goto out;