From 579f5c6c93c452155943b6526f4c64f6deb27982 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 1 Apr 2001 20:07:47 +0000 Subject: [PATCH] updates. --- CHANGES | 80 +++++ README | 38 ++- TODO | 18 -- apps/silc/client_ops.c | 18 +- apps/silc/local_command.c | 20 +- apps/silcd/command.c | 255 +++++++++++----- apps/silcd/command_reply.c | 20 +- apps/silcd/idlist.h | 15 + apps/silcd/packet_receive.c | 3 + apps/silcd/protocol.c | 10 +- apps/silcd/server.c | 77 ++++- doc/draft-riikonen-silc-ke-auth-02.nroff | 204 ++++++------- doc/draft-riikonen-silc-spec-01.nroff | 1 + doc/draft-riikonen-silc-spec-02.nroff | 59 +++- lib/silcclient/client.c | 50 ++-- lib/silcclient/client.h | 3 +- lib/silcclient/command.c | 68 ++++- lib/silcclient/protocol.c | 18 +- lib/silcclient/silcapi.h | 8 +- lib/silccore/silcauth.c | 61 ++-- lib/silccore/silcauth.h | 7 +- lib/silccore/silcmode.h | 34 ++- lib/silccrypt/silcpkcs.c | 4 + lib/silcske/payload.c | 358 ++++------------------- lib/silcske/payload.h | 23 +- lib/silcske/payload_internal.h | 17 +- lib/silcske/silcske.c | 258 +++++++++++----- lib/silcske/silcske.h | 24 +- 28 files changed, 1032 insertions(+), 719 deletions(-) diff --git a/CHANGES b/CHANGES index 81ef7f01..235599ae 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,83 @@ +Sun Apr 1 19:49:34 EEST 2001 Pekka Riikonen + + * Added SILC_UMODE_GONE mode to indicate when the client is not + present in the SILC network. Added also support to the local + command AWAY that will set this mode. Added support of showing + "xxx is gone" in WHOIS command. The USERS command shows the + gone status as well. + + * Fixed setting server and router operator privileges in the + server's UMODE command. Affected file silcd/command.c. + + * Merged the SKE KE1 and KE2 payloads into one payload. The + new KE payload is equivalent to the old KE2 payload. + + Cleaned up the SKE Start Payload parsing. It now uses the + simple buffer unformatting to do the parsing. A lot faster + now. + + Added new Mutual Authentication flag (SILC_SKE_SP_FLAG_MUTUAL) + to the SKE that is used to indicate whether both of the SKE + parties should perform authentication. By default only the + responder performs authentication. By setting this flag also + the initiator must do authentication. By default it is unset + since in normal SKE case, client to server connection, only + the responder should do authentication. When doing SKE between + two clients both should perform authentication. Updated the + code and the protocol specs. + + * A little fix to IDENTIFY command in the server. Search the + client first by hash not nickname. Affected file is + silcd/command.c. + + * Fixed the silc_client_close_connection to support closing + the client to client connections wihtout deleting too much + data. Affected file lib/silcclient/client.c. + + * Fixed a fatal bug in server and client; if KE1 or KE2 packets + are received if protocol used to be active but is not anymore + the application would crash due to NULL pointer dereference. + Affected files silcd/server.c and lib/silcclient/client.c. + + * Added `hash' field to the SilcClientConnection to include + the hash function negotiated in the SKE protocol. + + * Added new channel mode SILC_CMODE_FOUNDER_AUTH that is used + to set the channel founder authentication data. A client can + claim the founder rights later by providing the authentication + data to the CUMODE command using SILC_CUMODE_FOUNDER mode. + This way the channel founder can regain the channel founder + privileges even it is left the channel. This works only on + local server and the client must be connected to the same + server to be able to regain the founder rights. Updated the + protocol specs accordingly. + + Added support to the CMODE command in the client to set the + founder auth data. Read the README to see how to set it. + + Added support to the CUMODE command to claim the founder + rights. Read the README to see how to do it. + + Added support for the founder authentication to the Channel + Entry in the server. Affected file silcd/idlist.h. + + Added support for the SILC_CMODE_FOUNDER_AUTH mode in the + server's CMODE command. Affected file silcd/command.c. + + * Added the following new functions into lib/silccore/silcauth.[ch]: + silc_auth_get_method and silc_auth_get_data. + + * The server now saves the remote hosts public key to the + SilcIDListData pointer. Affected file silcd/protocol.c. + + * The normal server now does not remove the channel entry from + the cache if the founder authentication data is set. It used + to remove it if the founder was the last one on the channel on + the server and left the channel. The auth data is saved and + if the channel is re-joined later the old entry is used with + the old auth data. Affected files silcd/command_reply.c and + silcd/server.c. + Sat Mar 31 15:38:36 EEST 2001 Pekka Riikonen * Fixed packet processing on slow links. Partial packets were diff --git a/README b/README index 520601e3..da6a575d 100644 --- a/README +++ b/README @@ -88,12 +88,21 @@ SILC Commands be provided when joining to the channel. c Set/unset channel's cipher h Set/unset channel's hmac + f <-pubkey| + Set/unset channel founder authentication. + Channel founder may set this mode so that + if the client leaves the channel it can + claim the founder rights when it returns + to the channel. If -pubkey is set then + the authentication will be done using the + client's public key. You can claim the + founder rights using the CUMODE command. Multiple modes can be set/unset at once if the modes does not require any arguments. If mode requires an argument then only one mode can be set at once. - /CUMODE +|- [@] + /CUMODE +|- [@] [-pubkey|] Changes/set user's mode on a channel. Most of the modes require that the client who changes some client's mode must @@ -101,26 +110,39 @@ SILC Commands user modes are available: a [@] + Set/unset all modes (cannot be used to set both founder and operator rights, can be used only to remove both modes at once). - f [@] - Unset channel founder. Channel founder rights - cannot be set by user (only by server) so this - can be used only to unset the mode. + + f [@] [-pubkey|] + + Set/Unset channel founder. If the -pubkey + option or is provided then the + client is claiming the founder rights by + providing the channel founder authentication + data. If the -pubkey is provided then the + authentication is performed using the + client's public key. If you are channel + founder you can set the channel founder + authentication using CMODE command. + o [@] + Set/unset channel operator. Requires that you are channel operator or channel founder. /UMODE +|- - Sets/unsets user mode. Currently none of the modes can - be set by the user so this command can be merely used to - unset some mode. Following user modes are available: + Sets/unsets user mode. Note that some of the modes the + client cannot set itself. The following user modes are + available: a Unset all modes s Unset server operator privileges r Unset router operator privileges + g Set/unset to be gone (or use /AWAY command) + /MSG diff --git a/TODO b/TODO index 2c9c5dfc..27988137 100644 --- a/TODO +++ b/TODO @@ -150,28 +150,10 @@ TODO in the protocol before SILC 0.x to various security reasons (the server must not trust the public keys blindly without third party verification; that's why SENDKEY is not for servers). - o Define AWAY command to set the indication flag whether the - client is present or not. Do not save the away message to the - server though. - o Define the channel founder property to be permanent locally in - the server so that channel founder can regain its rights even - if it disconnects from the server. Thus, define a new command - or channel user mode that can be used to set the channel founder - passphrase or public key that can be used in the authentication - when regaining the founder rights. o New features in the KE/auth protocol (draft-riikonen-silc-ke-auth-xx.txt): - o Merge the KE1 and KE2 payloads into one KE payload that has - the `signature' field. Provide it only if the perty is - required to do authentication. - o Add MUTUAL_AUTH flag to indicate that the party must perform - authentication (to sign with their private key). Initiator - may set it to indicate that it can authenticate but responder - MAY require for the initiator to do authentication by setting - the flag at the KE Start Payload reply phase. The responder - performs authentication always as now as well. o Define group exchange support for the SKE so that the SKE could be performed among more than two entities. This is not a showstopper and may be defined later. diff --git a/apps/silc/client_ops.c b/apps/silc/client_ops.c index 5e3c1332..3165b7d8 100644 --- a/apps/silc/client_ops.c +++ b/apps/silc/client_ops.c @@ -522,12 +522,18 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn, } } - if (mode) - client->ops->say(client, conn, "%s is %s", nickname, - (mode & SILC_UMODE_SERVER_OPERATOR) ? - "Server Operator" : - (mode & SILC_UMODE_ROUTER_OPERATOR) ? - "SILC Operator" : "[Unknown mode]"); + if (mode) { + if ((mode & SILC_UMODE_SERVER_OPERATOR) || + (mode & SILC_UMODE_ROUTER_OPERATOR)) + client->ops->say(client, conn, "%s is %s", nickname, + (mode & SILC_UMODE_SERVER_OPERATOR) ? + "Server Operator" : + (mode & SILC_UMODE_ROUTER_OPERATOR) ? + "SILC Operator" : "[Unknown mode]"); + + if (mode & SILC_UMODE_GONE) + client->ops->say(client, conn, "%s is gone", nickname); + } if (idle && nickname) client->ops->say(client, conn, "%s has been idle %d %s", diff --git a/apps/silc/local_command.c b/apps/silc/local_command.c index ef7a4def..79aa0f04 100644 --- a/apps/silc/local_command.c +++ b/apps/silc/local_command.c @@ -218,6 +218,8 @@ SILC_CLIENT_LCMD_FUNC(away) SilcClientConnection conn = cmd->conn; SilcClient client = cmd->client; SilcClientInternal app = (SilcClientInternal)client->application; + unsigned char modebuf[4]; + SilcBuffer idp, buffer; if (!cmd->conn) { silc_say(client, conn, @@ -226,6 +228,8 @@ SILC_CLIENT_LCMD_FUNC(away) } if (cmd->argc == 1) { + conn->local_entry->mode &= ~SILC_UMODE_GONE; + if (conn->away) { silc_free(conn->away->away); silc_free(conn->away); @@ -236,7 +240,8 @@ SILC_CLIENT_LCMD_FUNC(away) silc_screen_print_bottom_line(app->screen, 0); } } else { - + conn->local_entry->mode |= SILC_UMODE_GONE; + if (conn->away) silc_free(conn->away->away); else @@ -249,6 +254,19 @@ SILC_CLIENT_LCMD_FUNC(away) silc_screen_print_bottom_line(app->screen, 0); } + /* Send the UMODE command to se myself as gone */ + idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT); + SILC_PUT32_MSB(conn->local_entry->mode, modebuf); + buffer = silc_command_payload_encode_va(SILC_COMMAND_UMODE, + ++conn->cmd_ident, 2, + 1, idp->data, idp->len, + 2, modebuf, sizeof(modebuf)); + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, + NULL, 0, NULL, NULL, buffer->data, + buffer->len, TRUE); + silc_buffer_free(buffer); + silc_buffer_free(idp); + out: silc_client_command_free(cmd); } diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 003f0adf..c317a546 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -1508,13 +1508,13 @@ silc_server_command_identify_from_client(SilcServerCommandContext cmd) } } } else { - clients = silc_idlist_get_clients_by_nickname(server->local_list, - nick, server_name, - &clients_count); + clients = silc_idlist_get_clients_by_hash(server->local_list, + nick, server->md5hash, + &clients_count); if (!clients) - clients = silc_idlist_get_clients_by_hash(server->local_list, - nick, server->md5hash, - &clients_count); + clients = silc_idlist_get_clients_by_nickname(server->local_list, + nick, server_name, + &clients_count); } /* Check global list as well */ @@ -1531,13 +1531,13 @@ silc_server_command_identify_from_client(SilcServerCommandContext cmd) } } } else { - clients = silc_idlist_get_clients_by_nickname(server->global_list, - nick, server_name, - &clients_count); + clients = silc_idlist_get_clients_by_hash(server->global_list, + nick, server->md5hash, + &clients_count); if (!clients) - clients = silc_idlist_get_clients_by_hash(server->global_list, - nick, server->md5hash, - &clients_count); + clients = silc_idlist_get_clients_by_nickname(server->global_list, + nick, server_name, + &clients_count); } } @@ -1616,13 +1616,13 @@ silc_server_command_identify_from_server(SilcServerCommandContext cmd) } } } else { - clients = silc_idlist_get_clients_by_nickname(server->local_list, - nick, server_name, - &clients_count); + clients = silc_idlist_get_clients_by_hash(server->local_list, + nick, server->md5hash, + &clients_count); if (!clients) - clients = silc_idlist_get_clients_by_hash(server->local_list, - nick, server->md5hash, - &clients_count); + clients = silc_idlist_get_clients_by_nickname(server->local_list, + nick, server_name, + &clients_count); } /* If we are router we will check our global list as well. */ @@ -1639,13 +1639,13 @@ silc_server_command_identify_from_server(SilcServerCommandContext cmd) } } } else { - clients = silc_idlist_get_clients_by_nickname(server->global_list, - nick, server_name, - &clients_count); + clients = silc_idlist_get_clients_by_hash(server->global_list, + nick, server->md5hash, + &clients_count); if (!clients) - clients = silc_idlist_get_clients_by_hash(server->global_list, - nick, server->md5hash, - &clients_count); + clients = silc_idlist_get_clients_by_nickname(server->global_list, + nick, server_name, + &clients_count); } } @@ -2996,7 +2996,7 @@ SILC_SERVER_CMD_FUNC(join) } } - if (!channel) { + if (!channel || !channel->id) { /* Channel not found */ /* If we are standalone server we don't have a router, we just create @@ -3286,10 +3286,12 @@ SILC_SERVER_CMD_FUNC(umode) */ if (mask & SILC_UMODE_SERVER_OPERATOR) { - /* Cannot operator mode */ - silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE, - SILC_STATUS_ERR_PERM_DENIED); - goto out; + if (!(client->mode & SILC_UMODE_SERVER_OPERATOR)) { + /* Cannot operator mode */ + silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE, + SILC_STATUS_ERR_PERM_DENIED); + goto out; + } } else { if (client->mode & SILC_UMODE_SERVER_OPERATOR) /* Remove the server operator rights */ @@ -3297,16 +3299,26 @@ SILC_SERVER_CMD_FUNC(umode) } if (mask & SILC_UMODE_ROUTER_OPERATOR) { - /* Cannot operator mode */ - silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE, - SILC_STATUS_ERR_PERM_DENIED); - goto out; + if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) { + /* Cannot operator mode */ + silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE, + SILC_STATUS_ERR_PERM_DENIED); + goto out; + } } else { if (client->mode & SILC_UMODE_ROUTER_OPERATOR) /* Remove the router operator rights */ client->mode &= ~SILC_UMODE_ROUTER_OPERATOR; } + if (mask & SILC_UMODE_GONE) { + client->mode |= SILC_UMODE_GONE; + } else { + if (client->mode & SILC_UMODE_GONE) + /* Remove the gone status */ + client->mode &= ~SILC_UMODE_GONE; + } + /* Send UMODE change to primary router */ if (!server->standalone) silc_server_send_notify_umode(server, server->router->connection, TRUE, @@ -3377,6 +3389,16 @@ int silc_server_check_cmode_rights(SilcChannelEntry channel, } } + if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) { + if (is_op && !is_fo) + return FALSE; + } else { + if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) { + if (is_op && !is_fo) + return FALSE; + } + } + return TRUE; } @@ -3387,28 +3409,17 @@ SILC_SERVER_CMD_FUNC(cmode) SilcServerCommandContext cmd = (SilcServerCommandContext)context; SilcServer server = cmd->server; SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; + SilcIDListData idata = (SilcIDListData)client; SilcChannelID *channel_id; SilcChannelEntry channel; 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 int mode_mask, tmp_len, tmp_len2; unsigned short ident = silc_command_get_ident(cmd->payload); - SILC_LOG_DEBUG(("Start")); - - argc = silc_argument_get_arg_num(cmd->args); - if (argc < 2) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, - SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); - goto out; - } - if (argc > 8) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, - SILC_STATUS_ERR_TOO_MANY_PARAMS); - goto out; - } + SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CMODE, cmd, 2, 7); /* Get Channel ID */ tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2); @@ -3652,6 +3663,57 @@ SILC_SERVER_CMD_FUNC(cmode) } } + if (mode_mask & SILC_CHANNEL_MODE_FOUNDER_AUTH) { + if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) { + if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) { + /* Set the founder authentication */ + SilcAuthPayload auth; + + tmp = silc_argument_get_arg_type(cmd->args, 7, &tmp_len); + if (!tmp) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + + auth = silc_auth_payload_parse(tmp, tmp_len); + if (!auth) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + + /* Save the public key */ + tmp = silc_pkcs_public_key_encode(idata->public_key, &tmp_len); + silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key); + silc_free(tmp); + + channel->founder_method = silc_auth_get_method(auth); + + if (channel->founder_method == SILC_AUTH_PASSWORD) { + tmp = silc_auth_get_data(auth, &tmp_len); + channel->founder_passwd = + silc_calloc(tmp_len + 1, sizeof(*channel->founder_passwd)); + memcpy(channel->founder_passwd, tmp, tmp_len); + channel->founder_passwd_len = tmp_len; + } + + silc_auth_payload_free(auth); + } + } + } else { + if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) { + if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) { + if (channel->founder_key) + silc_pkcs_public_key_free(channel->founder_key); + if (channel->founder_passwd) { + silc_free(channel->founder_passwd); + channel->founder_passwd = NULL; + } + } + } + } + /* Finally, set the mode */ channel->mode = mode_mask; @@ -3660,7 +3722,7 @@ SILC_SERVER_CMD_FUNC(cmode) silc_server_send_notify_to_channel(server, NULL, channel, FALSE, SILC_NOTIFY_TYPE_CMODE_CHANGE, 4, cidp->data, cidp->len, - tmp_mask, tmp_len, + tmp_mask, 4, cipher, cipher ? strlen(cipher) : 0, hmac, hmac ? strlen(hmac) : 0); @@ -3695,6 +3757,7 @@ SILC_SERVER_CMD_FUNC(cumode) SilcServerCommandContext cmd = (SilcServerCommandContext)context; SilcServer server = cmd->server; SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; + SilcIDListData idata = (SilcIDListData)client; SilcChannelID *channel_id; SilcClientID *client_id; SilcChannelEntry channel; @@ -3702,11 +3765,11 @@ SILC_SERVER_CMD_FUNC(cumode) SilcChannelClientEntry chl; SilcBuffer packet, idp; unsigned char *tmp_id, *tmp_ch_id, *tmp_mask; - unsigned int target_mask, sender_mask, tmp_len, tmp_ch_len; + unsigned int target_mask, sender_mask = 0, tmp_len, tmp_ch_len; int notify = FALSE; unsigned short ident = silc_command_get_ident(cmd->payload); - SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 3); + SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 4); /* Get Channel ID */ tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len); @@ -3746,13 +3809,6 @@ SILC_SERVER_CMD_FUNC(cumode) silc_list_start(channel->user_list); while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) { if (chl->client == client) { - if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) && - !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, - SILC_STATUS_ERR_NO_CHANNEL_PRIV); - goto out; - } - sender_mask = chl->mode; break; } @@ -3789,18 +3845,28 @@ SILC_SERVER_CMD_FUNC(cumode) client_id, NULL); } - /* Check whether target client is on the channel */ - if (!silc_server_client_on_channel(target_client, channel)) { + if (target_client != client && + !(sender_mask & SILC_CHANNEL_UMODE_CHANFO) && + !(sender_mask & SILC_CHANNEL_UMODE_CHANOP)) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, - SILC_STATUS_ERR_USER_NOT_ON_CHANNEL); + SILC_STATUS_ERR_NO_CHANNEL_PRIV); goto out; } - /* Get entry to the channel user list */ - silc_list_start(channel->user_list); - while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) - if (chl->client == target_client) - break; + /* Check whether target client is on the channel */ + if (target_client != client) { + if (!silc_server_client_on_channel(target_client, channel)) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, + SILC_STATUS_ERR_USER_NOT_ON_CHANNEL); + goto out; + } + + /* Get entry to the channel user list */ + silc_list_start(channel->user_list); + while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) + if (chl->client == target_client) + break; + } /* * Change the mode @@ -3815,10 +3881,46 @@ SILC_SERVER_CMD_FUNC(cumode) } if (target_mask & SILC_CHANNEL_UMODE_CHANFO) { - /* Cannot promote anyone to channel founder */ - silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, - SILC_STATUS_ERR_NOT_YOU); - goto out; + /* The client tries to claim the founder rights. */ + unsigned char *tmp_auth; + unsigned int tmp_auth_len, auth_len; + void *auth; + + if (target_client != client) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, + SILC_STATUS_ERR_NOT_YOU); + goto out; + } + + if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) || + !channel->founder_key) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, + SILC_STATUS_ERR_NOT_YOU); + goto out; + } + + tmp_auth = silc_argument_get_arg_type(cmd->args, 4, &tmp_auth_len); + if (!tmp_auth) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + + auth = (channel->founder_method == SILC_AUTH_PASSWORD ? + (void *)channel->founder_passwd : (void *)channel->founder_key); + auth_len = (channel->founder_method == SILC_AUTH_PASSWORD ? + channel->founder_passwd_len : 0); + + if (!silc_auth_verify_data(tmp_auth, tmp_auth_len, + channel->founder_method, auth, auth_len, + idata->hash, client->id, SILC_ID_CLIENT)) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, + SILC_STATUS_ERR_AUTH_FAILED); + goto out; + } + + chl->mode |= SILC_CHANNEL_UMODE_CHANFO; + notify = TRUE; } else { if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) { if (target_client == client) { @@ -3836,11 +3938,25 @@ SILC_SERVER_CMD_FUNC(cumode) if (target_mask & SILC_CHANNEL_UMODE_CHANOP) { /* Promote to operator */ if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) { + if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) && + !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, + SILC_STATUS_ERR_NO_CHANNEL_PRIV); + goto out; + } + chl->mode |= SILC_CHANNEL_UMODE_CHANOP; notify = TRUE; } } else { if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) { + if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) && + !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, + SILC_STATUS_ERR_NO_CHANNEL_PRIV); + goto out; + } + /* Demote to normal user */ chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP; notify = TRUE; @@ -3848,6 +3964,7 @@ SILC_SERVER_CMD_FUNC(cumode) } idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); + tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len); /* Send notify to channel, notify only if mode was actually changed. */ if (notify) { diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index 53124d40..79eb2bbe 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -613,6 +613,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join) { SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context; SilcServer server = cmd->server; + SilcIDCacheEntry cache = NULL; SilcCommandStatus status; SilcChannelID *id; SilcClientID *client_id = NULL; @@ -702,7 +703,8 @@ SILC_SERVER_CMD_REPLY_FUNC(join) silc_buffer_put(client_mode_list, tmp, len); /* See whether we already have the channel. */ - entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL); + entry = silc_idlist_find_channel_by_name(server->local_list, + channel_name, &cache); if (!entry) { /* Add new channel */ @@ -719,7 +721,21 @@ SILC_SERVER_CMD_REPLY_FUNC(join) goto out; } } else { - silc_free(id); + /* The entry exists. */ + if (entry->id) + silc_free(entry->id); + entry->id = id; + cache->id = entry->id; + + /* Remove the founder auth data if the mode is not set but we have + them in the entry */ + if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) { + silc_pkcs_public_key_free(entry->founder_key); + if (entry->founder_passwd) { + silc_free(entry->founder_passwd); + entry->founder_passwd = NULL; + } + } } if (entry->hmac_name && hmac) { diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h index ae2757d3..93b66dd8 100644 --- a/apps/silcd/idlist.h +++ b/apps/silcd/idlist.h @@ -361,6 +361,16 @@ struct SilcClientEntryStruct { 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. + SilcPublicKey founder_key + SilcAuthMethod founder_method + unsigned char *founder_passwd + unsigned int founder_passwd_len + + If the SILC_CMODE_FOUNDER_AUTH has been set then these will include + the founder's public key, authentication method and the password + if the method is SILC_AUTH_PASSWORD. If it is SILC_AUTH_PUBLIC_KEY + then the `founder_passwd' is NULL. + SilcServerEntry router This is a pointer to the server list. This is the router server @@ -395,6 +405,11 @@ struct SilcChannelEntryStruct { char *cipher; char *hmac_name; + SilcPublicKey founder_key; + SilcAuthMethod founder_method; + unsigned char *founder_passwd; + unsigned int founder_passwd_len; + unsigned int user_limit; unsigned char *passphrase; char *invite_list; diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 0b7b0bfd..8e50b857 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -1766,6 +1766,9 @@ void silc_server_new_channel(SilcServer server, We also create a new key for the channel. */ SilcBuffer users = NULL; + if (!channel->id) + channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL); + if (SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) { /* They don't match, send CHANNEL_CHANGE notify to the server to force the ID change. */ diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c index 43580638..cea428ca 100644 --- a/apps/silcd/protocol.c +++ b/apps/silcd/protocol.c @@ -102,6 +102,10 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske, idata->receive_key->set_iv(idata->receive_key, keymat->receive_iv); } + /* Save the remote host's public key */ + silc_pkcs_public_key_decode(ske->ke1_payload->pk_data, + ske->ke1_payload->pk_len, &idata->public_key); + /* Save the hash */ if (!silc_hash_alloc(hash->hash->name, &idata->hash)) { silc_cipher_free(idata->send_key); @@ -187,7 +191,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) properties packet from initiator. */ status = silc_ske_responder_start(ske, ctx->rng, ctx->sock, silc_version_string, - ctx->packet->buffer, NULL, NULL); + ctx->packet->buffer, FALSE, + NULL, NULL); } else { SilcSKEStartPayload *start_payload; @@ -269,7 +274,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) the initiator. This also creates our parts of the Diffie Hellman algorithm. */ status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer, - NULL, NULL); + NULL, NULL, NULL, NULL); } else { /* Call the Phase-2 function. This creates Diffie Hellman key exchange parameters and sends our public part inside @@ -277,6 +282,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) status = silc_ske_initiator_phase_2(ctx->ske, server->public_key, + server->private_key, silc_server_protocol_ke_send_packet, context); } diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 1e63e429..64e70fd1 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -715,7 +715,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) SILC_LOG_DEBUG(("Start")); - if (protocol->state == SILC_PROTOCOL_STATE_ERROR) { + if (protocol->state == SILC_PROTOCOL_STATE_ERROR || + protocol->state == SILC_PROTOCOL_STATE_FAILURE) { /* Error occured during protocol */ silc_protocol_free(protocol); silc_ske_free_key_material(ctx->keymat); @@ -847,7 +848,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) SILC_LOG_DEBUG(("Start")); - if (protocol->state == SILC_PROTOCOL_STATE_ERROR) { + if (protocol->state == SILC_PROTOCOL_STATE_ERROR || + protocol->state == SILC_PROTOCOL_STATE_FAILURE) { /* Error occured during protocol */ if (ctx->dest_id) silc_free(ctx->dest_id); @@ -1710,8 +1712,8 @@ void silc_server_packet_parse_type(SilcServer server, if (packet->flags & SILC_PACKET_FLAG_LIST) break; - if (sock->protocol && sock->protocol->protocol->type - == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) { + if (sock->protocol && sock->protocol->protocol && + sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) { SilcServerKEInternalContext *proto_ctx = (SilcServerKEInternalContext *)sock->protocol->context; @@ -1734,8 +1736,8 @@ void silc_server_packet_parse_type(SilcServer server, if (packet->flags & SILC_PACKET_FLAG_LIST) break; - if (sock->protocol && sock->protocol->protocol->type - == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) { + if (sock->protocol && sock->protocol->protocol && + sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) { SilcServerKEInternalContext *proto_ctx = (SilcServerKEInternalContext *)sock->protocol->context; @@ -1765,8 +1767,8 @@ void silc_server_packet_parse_type(SilcServer server, if (packet->flags & SILC_PACKET_FLAG_LIST) break; - if (sock->protocol && sock->protocol->protocol->type - == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) { + if (sock->protocol && sock->protocol->protocol && + sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) { SilcServerKEInternalContext *proto_ctx = (SilcServerKEInternalContext *)sock->protocol->context; @@ -2262,9 +2264,26 @@ void silc_server_remove_from_channels(SilcServer server, /* Remove channel if there is no users anymore */ if (server->server_type == SILC_ROUTER && silc_list_count(channel->user_list) < 2) { + server->stat.my_channels--; + + if (channel->founder_key) { + /* The founder auth data exists, do not remove the channel entry */ + SilcChannelClientEntry chl2; + + silc_free(channel->id); + channel->id = NULL; + + silc_list_start(channel->user_list); + while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) { + silc_list_del(chl2->client->channels, chl2); + silc_list_del(channel->user_list, chl2); + silc_free(chl2); + } + continue; + } + if (!silc_idlist_del_channel(server->local_list, channel)) silc_idlist_del_channel(server->global_list, channel); - server->stat.my_channels--; continue; } @@ -2292,9 +2311,26 @@ void silc_server_remove_from_channels(SilcServer server, signoff_message, signoff_message ? strlen(signoff_message) : 0); + server->stat.my_channels--; + + if (channel->founder_key) { + /* The founder auth data exists, do not remove the channel entry */ + SilcChannelClientEntry chl2; + + silc_free(channel->id); + channel->id = NULL; + + silc_list_start(channel->user_list); + while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) { + silc_list_del(chl2->client->channels, chl2); + silc_list_del(channel->user_list, chl2); + silc_free(chl2); + } + continue; + } + if (!silc_idlist_del_channel(server->local_list, channel)) silc_idlist_del_channel(server->global_list, channel); - server->stat.my_channels--; continue; } @@ -2386,10 +2422,27 @@ int silc_server_remove_from_one_channel(SilcServer server, SILC_NOTIFY_TYPE_LEAVE, 1, clidp->data, clidp->len); + server->stat.my_channels--; + silc_buffer_free(clidp); + + if (channel->founder_key) { + /* The founder auth data exists, do not remove the channel entry */ + SilcChannelClientEntry chl2; + + silc_free(channel->id); + channel->id = NULL; + + silc_list_start(channel->user_list); + while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) { + silc_list_del(chl2->client->channels, chl2); + silc_list_del(channel->user_list, chl2); + silc_free(chl2); + } + return FALSE; + } + if (!silc_idlist_del_channel(server->local_list, channel)) silc_idlist_del_channel(server->global_list, channel); - silc_buffer_free(clidp); - server->stat.my_channels--; return FALSE; } diff --git a/doc/draft-riikonen-silc-ke-auth-02.nroff b/doc/draft-riikonen-silc-ke-auth-02.nroff index ea28e0f0..34dbe96c 100644 --- a/doc/draft-riikonen-silc-ke-auth-02.nroff +++ b/doc/draft-riikonen-silc-ke-auth-02.nroff @@ -77,8 +77,7 @@ Table of Contents 2 SILC Key Exchange Protocol .................................... 3 2.1 Key Exchange Payloads ..................................... 3 2.1.1 Key Exchange Start Payload .......................... 4 - 2.1.2 Key Exchange 1 Payload .............................. 7 - 2.1.3 Key Exchange 2 Payload .............................. 9 + 2.1.2 Key Exchange Payload ................................ 7 2.2 Key Exchange Procedure .................................... 10 2.3 Processing the Key Material ............................... 12 2.4 SILC Key Exchange Groups .................................. 13 @@ -101,9 +100,8 @@ List of Figures .nf Figure 1: Key Exchange Start Payload -Figure 2: Key Exchange 1 Payload -Figure 3: Key Exchange 2 Payload -Figure 4: Connection Auth Payload +Figure 2: Key Exchange Payload +Figure 3: Connection Auth Payload .ti 0 @@ -185,7 +183,7 @@ Following descriptions of these payloads. .ti 0 2.1.1 Key Exchange Start Payload -Key exchange between two entities always begins with a +Key exchange between two entities always begins with the SILC_PACKET_KEY_EXCHANGE packet containing Key Exchange Start Payload. Initiator sends the Key Exchange Start Payload to the responder filled with all security properties it supports. The responders then checks whether @@ -296,16 +294,16 @@ o Flags (1 byte) - Indicates flags to be used in the key exchange. Several flags can be set at once by ORing the flags together. Following flags are reserved for this field. - No flags 0x00 + No flags 0x00 In this case the field is ignored. - No Reply 0x01 + No Reply 0x01 If set the receiver of the payload does not reply to the packet. - PFS 0x02 + PFS 0x02 Perfect Forward Secrecy (PFS) to be used in the key exchange protocol. If not set, re-keying @@ -316,6 +314,16 @@ o Flags (1 byte) - Indicates flags to be used in the key Rest of the flags are reserved for the future and must not be set. + Mutual Authentication 0x04 + + Both of the parties will perform authenetication + by providing signed data for the other party to + verify. By default, only responder will provide + the signature data. If this is set then the + inititator must also provide it. Initiator may + set this but also responder may set this even if + initiator did not set it. + o Payload Length (2 bytes) - Length of the entire Key Exchange Start payload, not including any other field. @@ -374,35 +382,27 @@ o Compression Algorithms (variable length) - The list of .ti 0 -2.1.2 Key Exchange 1 Payload - -Key Exchange 1 Payload is used to deliver computed public data from -initiator to responder. This data is used to compute the shared secret, -later by all parties. Key Exchange 1 Payload is only sent after the -SILC_PACKET_KEY_EXCHANGE packet and the Key Exchange Start Payload has -been processed by all the parties. - -This payload sends the initiator's public key to the responder. Responder -may need the public key in which case it should be checked to be trusted -by the responder. - -The payload may only be sent with SILC_PACKET_KEY_EXCHANGE_1 packet. -It must not be sent in any other packet type. Following diagram -represent the Key Exchange 1 Payload. - - - - - - - - - - +2.1.2 Key Exchange Payload +Key Exchange payload is used to deliver the public key (or certificate), +the computed Diffie-Hellman public value and possibly signature data +from one party to the other. When initiator is using this payload +and the Mutual Authentication flag is not set then the initiator must +not provide the signature data. If the flag is set then the initiator +must provide the signature data so that the responder may verify it. +The Mutual Authentication flag is usually used only if a separate +authentication protocol will not be executed for the initiator of the +prtocool. This is case for example when the SKE is performed between +two SILC clients. In normal case, where client is connecting to the +server or server is connecting to the router the Mutual Authentication +flag is not necessary. +This payload is sent inside SILC_PACKET_KEY_EXCHANGE_1 and inside +SILC_PACKET_KEY_EXCHANGE_2 packet types. The initiator uses the +SILC_PACKET_KEY_EXCHANGE_1 and the responder the latter. +The following diagram represent the Key Exchange 1 Payload. .in 5 @@ -413,19 +413,25 @@ represent the Key Exchange 1 Payload. | Public Key Length | Public Key Type | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | -~ Public Key of the Host (or certificate) ~ +~ Public Key of the party (or certificate) ~ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Public Data Length | | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +| | +~ Public Data ~ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Public Data Length | | +| Signature Length | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | -~ Public Data (e = g ^ x mod p) ~ +~ Signature Data ~ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ .in 3 .ce -Figure 2: Key Exchange 1 Payload +Figure 2: Key Exchange Payload .in 6 @@ -452,92 +458,29 @@ o Public Key Type (2 bytes) - The public key (or certificate) sending SILC_PACKET_FAILURE message and the connection should be closed immediately. -o Public Data Length (2 bytes) - The length of the public - data computed by the responder, not including any other - field. +o Public Data Length (2 bytes) - The length of the Public Data + field, not including any other field. o Public Data (variable length) - The public data to be - sent to the responder. See section 2.2 Key Exchange + sent to the receiver. See section 2.2 Key Exchange Procedure for detailed description how this field is computed. This value is binary encoded. -.in 3 - - -.ti 0 -2.1.3 Key Exchange 2 Payload - -Key Exchange 2 Payload is used to deliver public key, computed public -data and signature from responder to initiator. Initiator uses these -public parts of the key exchange protocol to compute the shared secret. - -The payload may only be sent with SILC_PACKET_KEY_EXCHANGE_2 packet. -It must not be sent in any other packet type. Following diagram -represent the Key Exchange 2 Payload. - - - -.in 5 -.nf - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Public Key Length | Public Key Type | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| | -~ Public Key of the Host (or certificate) ~ -| | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Public Data Length | | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + -| | -~ Public Data (f = g ^ y mod p) ~ -| | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Signature Length | | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + -| | -~ Signature Data ~ -| | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -.in 3 - -.ce -Figure 3: Key Exchange 2 Payload - - - -.in 6 -o Public Key Length (2 bytes) - The length of the Public Key - (or certificate) field, not including any other field. - -o Public Key Type (2 bytes) - The public key (or certificate) - type. This field indicates the type of the public key in - the packet. See previous sections for defined public key - types. - -o Public Key of the host (variable length) - The public - key of the sender (or its certificate). This is verified - by the receiver of the packet. The type of this field - is indicated by previous Public Key Type field. - -o Public Data Length (2 bytes) - The length of the public - data computed by the responder, not including any other - field. - -o Public Data (variable length) - The public data computed - by the responder. See section 2.2 Key Exchange Procedure - for detailed description how this field is computed. This - value is binary encoded. o Signature Length (2 bytes) - The length of the signature, not including any other field. o Signature Data (variable length) - The signature signed - by the responder. The receiver of this signature must + by the sender. The receiver of this signature must verify it. The verification is done using the public key received in this same payload. See section 2.2 Key Exchange Procedure for detailed description how - to produce the signature. + to produce the signature. If the Mutual Authentication + flag is not set then initiator must not provide this + field and the Signature Length field must be set to zero (0) + value. If the flag is set then also the initiator must + provide this field. The responder always provides this + field. +.in 3 .ti 0 @@ -558,26 +501,45 @@ Setup: p is a large and public safe prime. This is one of the 1. Initiator generates a random number x, where 1 < x < q, and computes e = g ^ x mod p. The result e is then - encoded into Key Exchange 1 Payload and sent - to the responder. + encoded into Key Exchange Payload and sent to the + responder. + If the Mutual Authentication flag is set then initiator + must also produce signature data SIGN_i which the responder + will verify. The initiator must compute a hash value + HASH_i = hash(Key Exchange Start Payload | public key + (or certificate) | e). It then signs the HASH_i value with + its private key resulting a signature SIGN_i. 2. Responder generates a random number y, where 1 < y < q, and computes f = g ^ y mod p. It then computes the shared secret KEY = e ^ y mod p, and, a hash value - HASH = hash(Key Exchange Start Payload data | Host public + HASH = hash(Key Exchange Start Payload data | public key (or certificate) | e | f | KEY). It then signs the HASH value with its private key resulting a signature SIGN. It then encodes its public key (or certificate), f and - SIGN into Key Exchange 2 Payload and sends it to the + SIGN into Key Exchange Payload and sends it to the initiator. + If the Mutual Authentication flag is set then the responder + should verify that the public key provided in the payload + is authentic, or if certificates are used it verifies the + certificate. The responder may accept the public key without + verifying it, however, doing so may result to insecure key + exchange (accepting the public key without verifying may be + desirable for practical reasons on many environments. For + long term use this is never desirable, in which case + certificates would be the preferred method to use). It then + computes the HASH_i value the same way initiator did in the + phase 1. It then verifies the signature SIGN_i from the + payload with the hash value HASH_i using the received public + key. 3. Initiator verifies that the public key provided in the payload is authentic, or if certificates are used - it verifies the certificate. Initiator may accept + it verifies the certificate. The initiator may accept the public key without verifying it, however, doing so may result to insecure key exchange (accepting the public key without verifying may be desirable for @@ -605,6 +567,9 @@ used. The key material is also used to produce other security parameters later used in the communication. See section 2.3 Processing the Key Material for detailed description how to process the key material. +If the Mutual Authentication flag was set the protocol produces also +a hash value HASH_i. This value, however, must be discarded. + After the keys are processed the protocol is ended by sending the SILC_PACKET_SUCCESS packet. Both entities send this packet to each other. After this both parties will start using the new keys. @@ -619,8 +584,7 @@ Key Exchange protocol produces secret shared key material KEY. This key material is used to derive the actual keys used in the encryption of the communication channel. The key material is also used to derive other security parameters used in the communication. Key Exchange -protocol produces a hash value HASH as well. This is used in the key -deriving process as a session identifier. +protocol produces a hash value HASH as well. Keys are derived from the key material as follows: @@ -925,7 +889,7 @@ represent the Connection Auth Payload. .in 3 .ce -Figure 4: Connection Auth Payload +Figure 3: Connection Auth Payload .in 6 diff --git a/doc/draft-riikonen-silc-spec-01.nroff b/doc/draft-riikonen-silc-spec-01.nroff index 09e03cee..854a0376 100644 --- a/doc/draft-riikonen-silc-spec-01.nroff +++ b/doc/draft-riikonen-silc-spec-01.nroff @@ -2661,6 +2661,7 @@ List of all defined commands in SILC follows. privileges by SILC_COMMAND_SILCOPER command. Client may unset the mode itself. + Reply messages to the command: Max Arguments: 2 diff --git a/doc/draft-riikonen-silc-spec-02.nroff b/doc/draft-riikonen-silc-spec-02.nroff index dd4e6472..40508c30 100644 --- a/doc/draft-riikonen-silc-spec-02.nroff +++ b/doc/draft-riikonen-silc-spec-02.nroff @@ -2661,6 +2661,11 @@ List of all defined commands in SILC follows. privileges by SILC_COMMAND_SILCOPER command. Client may unset the mode itself. + 0x0004 SILC_UMODE_GONE + + Marks that the user is not currently present in the + SILC Network. Client may set and unset this mode. + Reply messages to the command: Max Arguments: 2 @@ -2686,10 +2691,11 @@ List of all defined commands in SILC follows. 17 SILC_COMMAND_CMODE - Max Arguments: 6 - Arguments: (1) (2) - (3) [] (4) [] - (5) [] (6) [] + Max Arguments: 7 + Arguments: (1) (2) + (3) [] (4) [] + (5) [] (6) [] + (7) [] This command is used by client to set or change channel flags on a channel. Channel has several modes that set various properties @@ -2840,6 +2846,33 @@ List of all defined commands in SILC follows. to set/unset this mode. + 0x0200 SILC_CMODE_FOUNDER_AUTH + + Channel founder can set this mode to be able to regain + channel founder rights even if the client leaves the + channel. The is the Authentication Payload + consisting of the authentication method and authentication + data to be used in the authentication. The server must + not accept NONE authentication method. Also, if the + method is public key authentication the server must not + save the authentication data from the payload as the + data is different on all authentications. In this case the + server only saves the authentication method. + + Note, that this mode is effective only in the current server. + The client must connect to the same server later to be able + to regain the channel founder rights. The server must save + the public key of the channel founder and use that to identify + the client who is claiming the channel founder rights. + The rights may be claimed by the SILC_CUMODE_FOUNDER + channel user mode using SILC_COMMAND_CUMODE command. The + set authentication data remains valid as long as the channel + exists or until the founder unsets this mode. + + Typical implementation would use [+|-]f on user interface + to set/unset this mode. + + To make the mode system work, client must keep the channel mode mask locally so that the mode setting and unsetting would work without problems. The client receives the initial channel mode @@ -2873,9 +2906,9 @@ List of all defined commands in SILC follows. 18 SILC_COMMAND_CUMODE - Max Arguments: 3 - Arguments: (1) (2) - (3) + Max Arguments: 4 + Arguments: (1) (2) + (3) (4) [] This command is used by client to change channel user modes on channel. Users on channel may have some special modes and this @@ -2899,10 +2932,13 @@ List of all defined commands in SILC follows. 0x0001 SILC_CUMODE_FOUNDER - The client is channel founder of the channel. This mode - cannot be set by other client, it is set by the server when - the channel was founded (created). The mode is provided - because client may remove the founder rights from itself. + The client is channel founder of the channel. Usually this + mode is set only by the server when the channel was created. + However, if the SILC_CMODE_FOUNDER_AUTH channel mode has + been set, the client can claim channel founder privileges + by providing the that the server will use + to authenticate the client. The client can remove this + mode at any time. 0x0002 SILC_CUMODE_OPERATOR @@ -2934,6 +2970,7 @@ List of all defined commands in SILC follows. SILC_STATUS_ERR_NO_CHANNEL_PRIV SILC_STATUS_ERR_UNKNOWN_MODE SILC_STATUS_ERR_NO_SUCH_CLIENT_ID + SILC_STATUS_ERR_AUTH_FAILED 19 SILC_COMMAND_KICK diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 674c8ce0..458a2fcd 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -653,14 +653,16 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process) /* If connection is disconnecting already we will finally close the connection */ if (SILC_IS_DISCONNECTING(sock)) { - client->ops->disconnect(client, conn); - silc_client_close_connection(client, conn); + if (sock == conn->sock) + client->ops->disconnect(client, conn); + silc_client_close_connection(client, sock, conn); return; } SILC_LOG_DEBUG(("EOF from connection %d", sock->sock)); - client->ops->disconnect(client, conn); - silc_client_close_connection(client, conn); + if (sock == conn->sock) + client->ops->disconnect(client, conn); + silc_client_close_connection(client, sock, conn); return; } @@ -852,8 +854,8 @@ void silc_client_packet_parse_type(SilcClient client, break; case SILC_PACKET_KEY_EXCHANGE: - if (sock->protocol && sock->protocol->protocol->type - == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) { + if (sock->protocol && sock->protocol->protocol && + sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) { SilcClientKEInternalContext *proto_ctx = (SilcClientKEInternalContext *)sock->protocol->context; @@ -876,8 +878,8 @@ void silc_client_packet_parse_type(SilcClient client, break; case SILC_PACKET_KEY_EXCHANGE_1: - if (sock->protocol && sock->protocol->protocol->type - == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) { + if (sock->protocol && sock->protocol->protocol && + sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) { SilcClientKEInternalContext *proto_ctx = (SilcClientKEInternalContext *)sock->protocol->context; @@ -900,8 +902,8 @@ void silc_client_packet_parse_type(SilcClient client, } break; case SILC_PACKET_KEY_EXCHANGE_2: - if (sock->protocol && sock->protocol->protocol->type - == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) { + if (sock->protocol && sock->protocol->protocol && + sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) { SilcClientKEInternalContext *proto_ctx = (SilcClientKEInternalContext *)sock->protocol->context; @@ -1055,12 +1057,23 @@ void silc_client_packet_send(SilcClient client, } /* Closes connection to remote end. Free's all allocated data except - for some information such as nickname etc. that are valid at all time. */ + for some information such as nickname etc. that are valid at all time. + If the `sock' is NULL then the conn->sock will be used. If `sock' is + provided it will be checked whether the sock and `conn->sock' are the + same (they can be different, ie. a socket can use `conn' as its + connection but `conn->sock' might be actually a different connection + than the `sock'). */ void silc_client_close_connection(SilcClient client, + SilcSocketConnection sock, SilcClientConnection conn) { - SilcSocketConnection sock = conn->sock; + int del = FALSE; + + if (!sock || (sock && conn->sock == sock)) + del = TRUE; + if (!sock) + sock = conn->sock; /* We won't listen for this connection anymore */ silc_schedule_unset_listen_fd(sock->sock); @@ -1072,13 +1085,13 @@ void silc_client_close_connection(SilcClient client, /* Close the actual connection */ silc_net_close_connection(sock->sock); - client->ops->say(client, sock->user_data, - "Closed connection to host %s", sock->hostname); - /* Free everything */ - if (sock->user_data) { + if (del && sock->user_data) { /* XXX Free all client entries and channel entries. */ + client->ops->say(client, sock->user_data, + "Closed connection to host %s", sock->hostname); + /* Clear ID caches */ silc_idcache_del_all(conn->client_cache); silc_idcache_del_all(conn->channel_cache); @@ -1145,7 +1158,7 @@ void silc_client_disconnected_by_server(SilcClient client, silc_free(msg); SILC_SET_DISCONNECTED(sock); - silc_client_close_connection(client, sock->user_data); + silc_client_close_connection(client, sock, sock->user_data); } /* Received error message from server. Display it on the screen. @@ -1360,6 +1373,9 @@ char *silc_client_chmode(unsigned int mode, SilcChannelEntry channel) if (mode & SILC_CHANNEL_MODE_PASSPHRASE) strncat(string, "a", 1); + if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) + strncat(string, "f", 1); + if (mode & SILC_CHANNEL_MODE_CIPHER) { char cipher[30]; memset(cipher, 0, sizeof(cipher)); diff --git a/lib/silcclient/client.h b/lib/silcclient/client.h index 150236a7..d9199654 100644 --- a/lib/silcclient/client.h +++ b/lib/silcclient/client.h @@ -70,12 +70,13 @@ struct SilcClientConnectionStruct { /* * Common data */ - /* Keys */ + /* Keys and stuff negotiated in the SKE protocol */ SilcCipher send_key; SilcCipher receive_key; SilcHmac hmac; unsigned char *hmac_key; unsigned int hmac_key_len; + SilcHash hash; /* Client ID and Channel ID cache. Messages transmitted in SILC network are done using different unique ID's. These are the cache for diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index f2296006..a97cdc0d 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -671,7 +671,7 @@ SILC_TASK_CALLBACK(silc_client_command_quit_cb) /* Close connection */ q->client->ops->disconnect(q->client, q->conn); - silc_client_close_connection(q->client, q->conn->sock->user_data); + silc_client_close_connection(q->client, NULL, q->conn->sock->user_data); silc_free(q); } @@ -1071,6 +1071,12 @@ SILC_CLIENT_CMD_FUNC(umode) else mode &= ~SILC_UMODE_ROUTER_OPERATOR; break; + case 'g': + if (add) + mode |= SILC_UMODE_GONE; + else + mode &= ~SILC_UMODE_GONE; + break; default: COMMAND_ERROR; goto out; @@ -1108,7 +1114,7 @@ SILC_CLIENT_CMD_FUNC(cmode) SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; SilcChannelEntry channel; - SilcBuffer buffer, chidp; + SilcBuffer buffer, chidp, auth = NULL; unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL; unsigned int mode, add, type, len, arg_len = 0; int i; @@ -1234,6 +1240,28 @@ SILC_CLIENT_CMD_FUNC(cmode) mode &= ~SILC_CHANNEL_MODE_HMAC; } break; + case 'f': + if (add) { + mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH; + type = 7; + + if (!strcasecmp(cmd->argv[3], "-pubkey")) { + auth = silc_auth_public_key_auth_generate(cmd->client->public_key, + cmd->client->private_key, + conn->hash, + conn->local_id, + SILC_ID_CLIENT); + } else { + auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0, + cmd->argv[3], cmd->argv_lens[3]); + } + + arg = auth->data; + arg_len = auth->len; + } else { + mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH; + } + break; default: COMMAND_ERROR; goto out; @@ -1268,6 +1296,8 @@ SILC_CLIENT_CMD_FUNC(cmode) 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(chidp); + if (auth) + silc_buffer_free(auth); /* Notify application */ COMMAND; @@ -1285,7 +1315,7 @@ SILC_CLIENT_CMD_FUNC(cumode) SilcChannelEntry channel; SilcChannelUser chu; SilcClientEntry client_entry; - SilcBuffer buffer, clidp, chidp; + SilcBuffer buffer, clidp, chidp, auth = NULL; unsigned char *name, *cp, modebuf[4]; unsigned int mode = 0, add, len; char *nickname = NULL, *server = NULL; @@ -1378,10 +1408,23 @@ SILC_CLIENT_CMD_FUNC(cumode) } break; case 'f': - if (add) + if (add) { + if (cmd->argc == 5) { + if (!strcasecmp(cmd->argv[4], "-pubkey")) { + auth = silc_auth_public_key_auth_generate(cmd->client->public_key, + cmd->client->private_key, + conn->hash, + conn->local_id, + SILC_ID_CLIENT); + } else { + auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0, + cmd->argv[4], cmd->argv_lens[4]); + } + } mode |= SILC_CHANNEL_UMODE_CHANFO; - else + } else { mode &= ~SILC_CHANNEL_UMODE_CHANFO; + } break; case 'o': if (add) @@ -1402,16 +1445,20 @@ SILC_CLIENT_CMD_FUNC(cumode) /* Send the command packet. We support sending only one mode at once that requires an argument. */ - buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 3, + buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4, 1, chidp->data, chidp->len, 2, modebuf, 4, - 3, clidp->data, clidp->len); - + 3, clidp->data, clidp->len, + 4, auth ? auth->data : NULL, + auth ? auth->len : 0); + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(chidp); silc_buffer_free(clidp); + if (auth) + silc_buffer_free(auth); /* Notify application */ COMMAND; @@ -1990,7 +2037,10 @@ SILC_CLIENT_CMD_FUNC(users) strcat(line, " "); } - strncat(line, " H", 3); + if (e->mode & SILC_UMODE_GONE) + strcat(line, " G"); + else + strcat(line, " H"); strcat(tmp, m ? m : ""); strncat(line, tmp, strlen(tmp)); diff --git a/lib/silcclient/protocol.c b/lib/silcclient/protocol.c index f719bb57..16124421 100644 --- a/lib/silcclient/protocol.c +++ b/lib/silcclient/protocol.c @@ -117,6 +117,9 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske, /* Save HMAC key to be used in the communication. */ silc_hmac_alloc(hmac->hmac->name, NULL, &conn->hmac); silc_hmac_set_key(conn->hmac, keymat->hmac_key, keymat->hmac_key_len); + + /* Save the HASH function */ + silc_hash_alloc(hash->hash->name, &conn->hash); } /* Checks the version string of the server. */ @@ -183,7 +186,8 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) properties packet from initiator. */ status = silc_ske_responder_start(ske, ctx->rng, ctx->sock, silc_version_string, - ctx->packet->buffer, NULL, NULL); + ctx->packet->buffer, TRUE, + NULL, NULL); } else { SilcSKEStartPayload *start_payload; @@ -265,16 +269,16 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) the initiator. This also creates our parts of the Diffie Hellman algorithm. */ status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer, - NULL, NULL); + ctx->verify, context, NULL, NULL); } else { /* Call the Phase-2 function. This creates Diffie Hellman key exchange parameters and sends our public part inside Key Exhange 1 Payload to the responder. */ - status = - silc_ske_initiator_phase_2(ctx->ske, - client->public_key, - ctx->send_packet, - context); + status = silc_ske_initiator_phase_2(ctx->ske, + client->public_key, + client->private_key, + ctx->send_packet, + context); } if (status != SILC_SKE_STATUS_OK) { diff --git a/lib/silcclient/silcapi.h b/lib/silcclient/silcapi.h index bdf210bb..4dc56d03 100644 --- a/lib/silcclient/silcapi.h +++ b/lib/silcclient/silcapi.h @@ -285,8 +285,14 @@ int silc_client_start_key_exchange(SilcClient client, int fd); /* Closes connection to remote end. Free's all allocated data except - for some information such as nickname etc. that are valid at all time. */ + for some information such as nickname etc. that are valid at all time. + If the `sock' is NULL then the conn->sock will be used. If `sock' is + provided it will be checked whether the sock and `conn->sock' are the + same (they can be different, ie. a socket can use `conn' as its + connection but `conn->sock' might be actually a different connection + than the `sock'). */ void silc_client_close_connection(SilcClient client, + SilcSocketConnection sock, SilcClientConnection conn); diff --git a/lib/silccore/silcauth.c b/lib/silccore/silcauth.c index a7a43c41..0b8f8c87 100644 --- a/lib/silccore/silcauth.c +++ b/lib/silccore/silcauth.c @@ -40,13 +40,19 @@ struct SilcAuthPayloadStruct { /* Parses and returns Authentication Payload */ -SilcAuthPayload silc_auth_payload_parse(SilcBuffer buffer) +SilcAuthPayload silc_auth_payload_parse(unsigned char *data, + unsigned int data_len) { + SilcBuffer buffer; SilcAuthPayload new; int ret; SILC_LOG_DEBUG(("Parsing Authentication Payload")); + buffer = silc_buffer_alloc(data_len); + silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + silc_buffer_put(buffer, data, data_len); + new = silc_calloc(1, sizeof(*new)); /* Parse the payload */ @@ -60,14 +66,18 @@ SilcAuthPayload silc_auth_payload_parse(SilcBuffer buffer) SILC_STR_END); if (ret == -1) { silc_free(new); + silc_buffer_free(buffer); return NULL; } if (new->len != buffer->len) { silc_auth_payload_free(new); + silc_buffer_free(buffer); return NULL; } + silc_buffer_free(buffer); + /* If password authentication, random data must not be set */ if (new->auth_method == SILC_AUTH_PASSWORD && new->random_len) { silc_auth_payload_free(new); @@ -90,7 +100,7 @@ SilcBuffer silc_auth_payload_encode(SilcAuthMethod method, SILC_LOG_DEBUG(("Encoding Authentication Payload")); - len = 4 + 4 + random_len + auth_len; + len = 2 + 2 + 2 + random_len + 2 + auth_len; buffer = silc_buffer_alloc(len); silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); silc_buffer_format(buffer, @@ -122,6 +132,24 @@ void silc_auth_payload_free(SilcAuthPayload payload) } } +/* Get authentication method */ + +SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload) +{ + return payload->auth_method; +} + +/* Get the authentication data */ + +unsigned char *silc_auth_get_data(SilcAuthPayload payload, + unsigned int *auth_len) +{ + if (auth_len) + *auth_len = payload->auth_len; + + return payload->auth_data; +} + /****************************************************************************** Authentication Routines @@ -152,7 +180,7 @@ silc_auth_public_key_encode_data(SilcPublicKey public_key, } id_len = silc_id_get_len(type); - buf = silc_buffer_alloc(random_len + pk_len); + buf = silc_buffer_alloc(random_len + id_len + pk_len); silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf)); silc_buffer_format(buf, SILC_STR_UI_XNSTRING(random, random_len), @@ -160,7 +188,7 @@ silc_auth_public_key_encode_data(SilcPublicKey public_key, SILC_STR_UI_XNSTRING(pk, pk_len), SILC_STR_END); - ret = silc_calloc(buf->len, sizeof(*ret)); + ret = silc_calloc(buf->len + 1, sizeof(*ret)); memcpy(ret, buf->data, buf->len); if (ret_len) @@ -178,11 +206,12 @@ silc_auth_public_key_encode_data(SilcPublicKey public_key, and the actual authentication data. Returns NULL on error. */ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key, + SilcPrivateKey private_key, SilcHash hash, void *id, SilcIdType type) { unsigned char *random; - unsigned char auth_data[32]; + unsigned char auth_data[1024]; unsigned int auth_len; unsigned char *tmp; unsigned int tmp_len; @@ -208,6 +237,8 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key, silc_free(tmp); return NULL; } + silc_pkcs_public_key_set(pkcs, public_key); + silc_pkcs_private_key_set(pkcs, private_key); /* Compute the hash and the signature. */ if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data, @@ -235,7 +266,7 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key, } /* Verifies the authentication data. Returns TRUE if authentication was - successfull. */ + successful. */ int silc_auth_public_key_auth_verify(SilcAuthPayload payload, SilcPublicKey public_key, SilcHash hash, @@ -262,6 +293,7 @@ int silc_auth_public_key_auth_verify(SilcAuthPayload payload, silc_free(tmp); return FALSE; } + silc_pkcs_public_key_set(pkcs, public_key); /* Verify the authentication data */ if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data, @@ -278,7 +310,7 @@ int silc_auth_public_key_auth_verify(SilcAuthPayload payload, silc_free(tmp); silc_pkcs_free(pkcs); - SILC_LOG_DEBUG(("Authentication successfull")); + SILC_LOG_DEBUG(("Authentication successful")); return TRUE; } @@ -293,7 +325,7 @@ int silc_auth_public_key_auth_verify_data(SilcBuffer payload, SilcAuthPayload auth_payload; int ret; - auth_payload = silc_auth_payload_parse(payload); + auth_payload = silc_auth_payload_parse(payload->data, payload->len); if (!auth_payload) { SILC_LOG_DEBUG(("Authentication failed")); return FALSE; @@ -333,7 +365,7 @@ int silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method, /* Passphrase based authentication. The `pkcs', `hash', `id' and `type' arguments are not needed. */ if (!memcmp(payload->auth_data, auth_data, payload->auth_len)) { - SILC_LOG_DEBUG(("Authentication successfull")); + SILC_LOG_DEBUG(("Authentication successful")); return TRUE; } break; @@ -361,23 +393,16 @@ int silc_auth_verify_data(unsigned char *payload, unsigned int payload_len, void *id, SilcIdType type) { SilcAuthPayload auth_payload; - SilcBuffer buffer; int ret; - buffer = silc_buffer_alloc(payload_len); - silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); - silc_buffer_put(buffer, payload, payload_len); - auth_payload = silc_auth_payload_parse(buffer); - if (!auth_payload) { - silc_buffer_free(buffer); + auth_payload = silc_auth_payload_parse(payload, payload_len); + if (!auth_payload) return FALSE; - } ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len, hash, id, type); silc_auth_payload_free(auth_payload); - silc_buffer_free(buffer); return ret; } diff --git a/lib/silccore/silcauth.h b/lib/silccore/silcauth.h index 1e55d264..3181a0eb 100644 --- a/lib/silccore/silcauth.h +++ b/lib/silccore/silcauth.h @@ -41,14 +41,19 @@ typedef unsigned short SilcAuthMethod; #define SILC_AUTH_FAILED 1 /* Prototypes */ -SilcAuthPayload silc_auth_payload_parse(SilcBuffer buffer); +SilcAuthPayload silc_auth_payload_parse(unsigned char *data, + unsigned int data_len); SilcBuffer silc_auth_payload_encode(SilcAuthMethod method, unsigned char *random_data, unsigned short random_len, unsigned char *auth_data, unsigned short auth_len); void silc_auth_payload_free(SilcAuthPayload payload); +SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload); +unsigned char *silc_auth_get_data(SilcAuthPayload payload, + unsigned int *auth_len); SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key, + SilcPrivateKey private_key, SilcHash hash, void *id, SilcIdType type); int silc_auth_public_key_auth_verify(SilcAuthPayload payload, diff --git a/lib/silccore/silcmode.h b/lib/silccore/silcmode.h index 9a5c4a08..ab42a12f 100644 --- a/lib/silccore/silcmode.h +++ b/lib/silccore/silcmode.h @@ -22,25 +22,27 @@ #define SILCMODE_H /* Channel modes */ -#define SILC_CHANNEL_MODE_NONE 0x0000 -#define SILC_CHANNEL_MODE_PRIVATE 0x0001 /* private channel */ -#define SILC_CHANNEL_MODE_SECRET 0x0002 /* secret channel */ -#define SILC_CHANNEL_MODE_PRIVKEY 0x0004 /* channel has private key */ -#define SILC_CHANNEL_MODE_INVITE 0x0008 /* invite only channel */ -#define SILC_CHANNEL_MODE_TOPIC 0x0010 /* topic setting by operator */ -#define SILC_CHANNEL_MODE_ULIMIT 0x0020 /* user limit set */ -#define SILC_CHANNEL_MODE_PASSPHRASE 0x0040 /* passphrase set */ -#define SILC_CHANNEL_MODE_CIPHER 0x0080 /* sets cipher of the channel */ -#define SILC_CHANNEL_MODE_HMAC 0x0100 /* sets hmac of the channel */ +#define SILC_CHANNEL_MODE_NONE 0x0000 +#define SILC_CHANNEL_MODE_PRIVATE 0x0001 /* private channel */ +#define SILC_CHANNEL_MODE_SECRET 0x0002 /* secret channel */ +#define SILC_CHANNEL_MODE_PRIVKEY 0x0004 /* channel has private key */ +#define SILC_CHANNEL_MODE_INVITE 0x0008 /* invite only channel */ +#define SILC_CHANNEL_MODE_TOPIC 0x0010 /* topic setting by operator */ +#define SILC_CHANNEL_MODE_ULIMIT 0x0020 /* user limit set */ +#define SILC_CHANNEL_MODE_PASSPHRASE 0x0040 /* passphrase set */ +#define SILC_CHANNEL_MODE_CIPHER 0x0080 /* sets cipher of the channel */ +#define SILC_CHANNEL_MODE_HMAC 0x0100 /* sets hmac of the channel */ +#define SILC_CHANNEL_MODE_FOUNDER_AUTH 0x0200 /* sets founder auth data */ /* User modes on channel */ -#define SILC_CHANNEL_UMODE_NONE 0x0000 /* Normal user */ -#define SILC_CHANNEL_UMODE_CHANFO 0x0001 /* channel founder */ -#define SILC_CHANNEL_UMODE_CHANOP 0x0002 /* channel operator */ +#define SILC_CHANNEL_UMODE_NONE 0x0000 /* Normal user */ +#define SILC_CHANNEL_UMODE_CHANFO 0x0001 /* channel founder */ +#define SILC_CHANNEL_UMODE_CHANOP 0x0002 /* channel operator */ /* SILC modes */ -#define SILC_UMODE_NONE 0x0000 /* Normal SILC user */ -#define SILC_UMODE_SERVER_OPERATOR 0x0001 /* Server operator */ -#define SILC_UMODE_ROUTER_OPERATOR 0x0002 /* Router (SILC) operator */ +#define SILC_UMODE_NONE 0x0000 /* Normal SILC user */ +#define SILC_UMODE_SERVER_OPERATOR 0x0001 /* Server operator */ +#define SILC_UMODE_ROUTER_OPERATOR 0x0002 /* Router (SILC) operator */ +#define SILC_UMODE_GONE 0x0004 /* Client is gone */ #endif diff --git a/lib/silccrypt/silcpkcs.c b/lib/silccrypt/silcpkcs.c index 3fc2d4c7..a5ebf6be 100644 --- a/lib/silccrypt/silcpkcs.c +++ b/lib/silccrypt/silcpkcs.c @@ -230,6 +230,8 @@ int silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash, silc_hash_make(hash, src, src_len, hashr); hash_len = hash->hash->hash_len; + SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len); + ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len); memset(hashr, 0, sizeof(hashr)); @@ -252,6 +254,8 @@ int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, silc_hash_make(hash, data, data_len, hashr); hash_len = hash->hash->hash_len; + SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len); + ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len, hashr, hash_len); memset(hashr, 0, sizeof(hashr)); diff --git a/lib/silcske/payload.c b/lib/silcske/payload.c index acb4d277..ea9313f1 100644 --- a/lib/silcske/payload.c +++ b/lib/silcske/payload.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2000 Pekka Riikonen + Copyright (C) 2000 - 2001 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 @@ -93,7 +93,7 @@ silc_ske_payload_start_decode(SilcSKE ske, SilcSKEStartPayload *payload; SilcSKEStatus status = SILC_SKE_STATUS_ERROR; unsigned char tmp; - int ret, len, len2; + int ret; SILC_LOG_DEBUG(("Decoding Key Exchange Start Payload")); @@ -112,7 +112,18 @@ silc_ske_payload_start_decode(SilcSKE ske, payload->cookie_len), SILC_STR_UI16_NSTRING_ALLOC(&payload->version, &payload->version_len), - SILC_STR_UI_SHORT(&payload->ke_grp_len), + SILC_STR_UI16_NSTRING_ALLOC(&payload->ke_grp_list, + &payload->ke_grp_len), + SILC_STR_UI16_NSTRING_ALLOC(&payload->pkcs_alg_list, + &payload->pkcs_alg_len), + SILC_STR_UI16_NSTRING_ALLOC(&payload->enc_alg_list, + &payload->enc_alg_len), + SILC_STR_UI16_NSTRING_ALLOC(&payload->hash_alg_list, + &payload->hash_alg_len), + SILC_STR_UI16_NSTRING_ALLOC(&payload->hmac_alg_list, + &payload->hmac_alg_len), + SILC_STR_UI16_NSTRING_ALLOC(&payload->comp_alg_list, + &payload->comp_alg_len), SILC_STR_END); if (ret == -1) { status = SILC_SKE_STATUS_ERROR; @@ -131,122 +142,6 @@ silc_ske_payload_start_decode(SilcSKE ske, goto err; } - if (payload->ke_grp_len < 1) { - SILC_LOG_DEBUG(("Bad payload length")); - status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH; - goto err; - } - - len2 = len = 1 + 1 + 2 + payload->cookie_len + 2 + payload->version_len + 2; - silc_buffer_pull(buffer, len); - - /* Parse group list */ - ret = silc_buffer_unformat(buffer, - SILC_STR_UI_XNSTRING_ALLOC(&payload->ke_grp_list, - payload->ke_grp_len), - SILC_STR_UI_SHORT(&payload->pkcs_alg_len), - SILC_STR_END); - if (ret == -1) { - status = SILC_SKE_STATUS_ERROR; - goto err; - } - - if (payload->pkcs_alg_len < 1) { - SILC_LOG_DEBUG(("Bad payload length")); - status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH; - goto err; - } - - len2 += len = payload->ke_grp_len + 2; - silc_buffer_pull(buffer, len); - - /* Parse PKCS alg list */ - ret = - silc_buffer_unformat(buffer, - SILC_STR_UI_XNSTRING_ALLOC(&payload->pkcs_alg_list, - payload->pkcs_alg_len), - SILC_STR_UI_SHORT(&payload->enc_alg_len), - SILC_STR_END); - if (ret == -1) { - status = SILC_SKE_STATUS_ERROR; - goto err; - } - - if (payload->enc_alg_len < 1) { - SILC_LOG_DEBUG(("Bad payload length")); - status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH; - goto err; - } - - len2 += len = payload->pkcs_alg_len + 2; - silc_buffer_pull(buffer, len); - - /* Parse encryption alg list */ - ret = - silc_buffer_unformat(buffer, - SILC_STR_UI_XNSTRING_ALLOC(&payload->enc_alg_list, - payload->enc_alg_len), - SILC_STR_UI_SHORT(&payload->hash_alg_len), - SILC_STR_END); - if (ret == -1) { - status = SILC_SKE_STATUS_ERROR; - goto err; - } - - if (payload->hash_alg_len < 1) { - SILC_LOG_DEBUG(("Bad payload length")); - status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH; - goto err; - } - - len2 += len = payload->enc_alg_len + 2; - silc_buffer_pull(buffer, len); - - /* Parse hash alg list */ - ret = - silc_buffer_unformat(buffer, - SILC_STR_UI_XNSTRING_ALLOC(&payload->hash_alg_list, - payload->hash_alg_len), - SILC_STR_UI_SHORT(&payload->hmac_alg_len), - SILC_STR_END); - if (ret == -1) { - status = SILC_SKE_STATUS_ERROR; - goto err; - } - - len2 += len = payload->hash_alg_len + 2; - silc_buffer_pull(buffer, len); - - /* Parse HMAC list */ - ret = - silc_buffer_unformat(buffer, - SILC_STR_UI_XNSTRING_ALLOC(&payload->hmac_alg_list, - payload->hmac_alg_len), - SILC_STR_UI_SHORT(&payload->comp_alg_len), - SILC_STR_END); - if (ret == -1) { - status = SILC_SKE_STATUS_ERROR; - goto err; - } - - len2 += len = payload->hmac_alg_len + 2; - silc_buffer_pull(buffer, len); - - /* Parse compression alg list */ - if (payload->comp_alg_len) { - ret = - silc_buffer_unformat(buffer, - SILC_STR_UI_XNSTRING_ALLOC(&payload->comp_alg_list, - payload->comp_alg_len), - SILC_STR_END); - if (ret == -1) { - status = SILC_SKE_STATUS_ERROR; - goto err; - } - } - - silc_buffer_push(buffer, len2); - /* Return the payload */ *return_payload = payload; @@ -284,169 +179,36 @@ void silc_ske_payload_start_free(SilcSKEStartPayload *payload) } } -/* Encodes Key Exchange 1 Payload into a SILC Buffer to be sent - to the other end. */ +/* Encodes Key Exchange Payload into a SILC Buffer to be sent to the other + end. */ -SilcSKEStatus silc_ske_payload_one_encode(SilcSKE ske, - SilcSKEOnePayload *payload, - SilcBuffer *return_buffer) +SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske, + SilcSKEKEPayload *payload, + SilcBuffer *return_buffer) { SilcBuffer buf; - unsigned char *e_str; - unsigned int e_len; + unsigned char *x_str; + unsigned int x_len; int ret; - SILC_LOG_DEBUG(("Encoding KE 1 Payload")); + SILC_LOG_DEBUG(("Encoding KE Payload")); if (!payload) return SILC_SKE_STATUS_ERROR; - /* Encode the integer into binary data */ - e_str = silc_mp_mp2bin(&payload->e, 0, &e_len); - if (!e_str) + if (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL && + !payload->sign_data) { + SILC_LOG_DEBUG(("Signature data is missing")); return SILC_SKE_STATUS_ERROR; - - /* Allocate channel payload buffer. The length of the buffer - is 2 + e. */ - buf = silc_buffer_alloc(e_len + 2 + payload->pk_len + 2 + 2); - silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf)); - - /* Encode the payload */ - ret = silc_buffer_format(buf, - SILC_STR_UI_SHORT(payload->pk_len), - SILC_STR_UI_SHORT(payload->pk_type), - SILC_STR_UI_XNSTRING(payload->pk_data, - payload->pk_len), - SILC_STR_UI_SHORT(e_len), - SILC_STR_UI_XNSTRING(e_str, e_len), - SILC_STR_END); - if (ret == -1) { - memset(e_str, 'F', e_len); - silc_free(e_str); - silc_buffer_free(buf); - return SILC_SKE_STATUS_ERROR; - } - - /* Return encoded buffer */ - *return_buffer = buf; - - memset(e_str, 'F', e_len); - silc_free(e_str); - - return SILC_SKE_STATUS_OK; -} - -/* Parses the Key Exchange 1 Payload. Parsed data is returned - to allocated payload structure. */ - -SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske, - SilcBuffer buffer, - SilcSKEOnePayload **return_payload) -{ - SilcSKEOnePayload *payload; - SilcSKEStatus status = SILC_SKE_STATUS_ERROR; - unsigned char *e; - unsigned short e_len; - int ret; - - SILC_LOG_DEBUG(("Decoding Key Exchange 1 Payload")); - - SILC_LOG_HEXDUMP(("KE 1 Payload"), buffer->data, buffer->len); - - payload = silc_calloc(1, sizeof(*payload)); - - /* Parse start of the payload */ - ret = silc_buffer_unformat(buffer, - SILC_STR_UI_SHORT(&payload->pk_len), - SILC_STR_UI_SHORT(&payload->pk_type), - SILC_STR_END); - if (ret == -1) { - status = SILC_SKE_STATUS_ERROR; - goto err; - } - - if (payload->pk_len < 5) { - status = SILC_SKE_STATUS_BAD_PAYLOAD; - goto err; - } - - /* Parse public key data */ - silc_buffer_pull(buffer, 2 + 2); - ret = silc_buffer_unformat(buffer, - SILC_STR_UI_XNSTRING_ALLOC(&payload->pk_data, - payload->pk_len), - SILC_STR_UI16_NSTRING_ALLOC(&e, &e_len), - SILC_STR_END); - if (ret == -1) { - status = SILC_SKE_STATUS_ERROR; - goto err; - } - - if (e_len < 3) { - status = SILC_SKE_STATUS_BAD_PAYLOAD; - goto err; - } - - silc_buffer_push(buffer, 2 + 2); - - if (payload->pk_len + 2 + 2 + 2 + e_len != buffer->len) { - status = SILC_SKE_STATUS_BAD_PAYLOAD; - goto err; - } - - /* Decode the HEX string to integer */ - silc_mp_init(&payload->e); - silc_mp_bin2mp(e, e_len, &payload->e); - memset(e, 0, sizeof(e_len)); - silc_free(e); - - /* Return the payload */ - *return_payload = payload; - - return SILC_SKE_STATUS_OK; - - err: - silc_free(payload); - ske->status = status; - return status; -} - -/* Free's KE1 Payload */ - -void silc_ske_payload_one_free(SilcSKEOnePayload *payload) -{ - if (payload) { - if (payload->pk_data) - silc_free(payload->pk_data); - silc_free(payload); } -} -/* Encodes Key Exchange 2 Payload into a SILC Buffer to be sent - to the other end. */ - -SilcSKEStatus silc_ske_payload_two_encode(SilcSKE ske, - SilcSKETwoPayload *payload, - SilcBuffer *return_buffer) -{ - SilcBuffer buf; - unsigned char *f_str; - unsigned int f_len; - unsigned int len; - int ret; - - SILC_LOG_DEBUG(("Encoding KE 2 Payload")); - - if (!payload) - return SILC_SKE_STATUS_ERROR; - - /* Encode the integer into HEX string */ - f_str = silc_mp_mp2bin(&payload->f, 0, &f_len); + /* Encode the integer into binary data */ + x_str = silc_mp_mp2bin(&payload->x, 0, &x_len); /* Allocate channel payload buffer. The length of the buffer - is 2 + 2 + public key + 2 + f + 2 + signature. */ - len = payload->pk_len + 2 + 2 + f_len + 2 + payload->sign_len + 2; - buf = silc_buffer_alloc(len); + is 4 + public key + 2 + x + 2 + signature. */ + buf = silc_buffer_alloc(4 + payload->pk_len + 2 + x_len + + 2 + payload->sign_len); silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf)); /* Encode the payload */ @@ -455,15 +217,15 @@ SilcSKEStatus silc_ske_payload_two_encode(SilcSKE ske, SILC_STR_UI_SHORT(payload->pk_type), SILC_STR_UI_XNSTRING(payload->pk_data, payload->pk_len), - SILC_STR_UI_SHORT(f_len), - SILC_STR_UI_XNSTRING(f_str, f_len), + SILC_STR_UI_SHORT(x_len), + SILC_STR_UI_XNSTRING(x_str, x_len), SILC_STR_UI_SHORT(payload->sign_len), SILC_STR_UI_XNSTRING(payload->sign_data, payload->sign_len), SILC_STR_END); if (ret == -1) { - memset(f_str, 'F', f_len); - silc_free(f_str); + memset(x_str, 'F', x_len); + silc_free(x_str); silc_buffer_free(buf); return SILC_SKE_STATUS_ERROR; } @@ -471,29 +233,31 @@ SilcSKEStatus silc_ske_payload_two_encode(SilcSKE ske, /* Return encoded buffer */ *return_buffer = buf; - memset(f_str, 'F', f_len); - silc_free(f_str); + SILC_LOG_HEXDUMP(("KE Payload"), buf->data, buf->len); + + memset(x_str, 'F', x_len); + silc_free(x_str); return SILC_SKE_STATUS_OK; } -/* Parses the Key Exchange 2 Payload. Parsed data is returned - to allocated payload structure. */ +/* Parses the Key Exchange Payload. Parsed data is returned to allocated + payload structure. */ -SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske, - SilcBuffer buffer, - SilcSKETwoPayload **return_payload) +SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske, + SilcBuffer buffer, + SilcSKEKEPayload **return_payload) { SilcSKEStatus status = SILC_SKE_STATUS_ERROR; - SilcSKETwoPayload *payload; - unsigned char *f; - unsigned short f_len; + SilcSKEKEPayload *payload; + unsigned char *x; + unsigned short x_len; unsigned int tot_len = 0, len2; int ret; - SILC_LOG_DEBUG(("Decoding Key Exchange 2 Payload")); + SILC_LOG_DEBUG(("Decoding Key Exchange Payload")); - SILC_LOG_HEXDUMP(("KE 2 Payload"), buffer->data, buffer->len); + SILC_LOG_HEXDUMP(("KE Payload"), buffer->data, buffer->len); payload = silc_calloc(1, sizeof(*payload)); @@ -521,7 +285,7 @@ SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske, ret = silc_buffer_unformat(buffer, SILC_STR_UI_XNSTRING_ALLOC(&payload->pk_data, payload->pk_len), - SILC_STR_UI16_NSTRING_ALLOC(&f, &f_len), + SILC_STR_UI16_NSTRING_ALLOC(&x, &x_len), SILC_STR_UI16_NSTRING_ALLOC(&payload->sign_data, &payload->sign_len), SILC_STR_END); @@ -530,15 +294,18 @@ SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske, goto err; } - tot_len += f_len + 2; + tot_len += x_len + 2; tot_len += payload->sign_len + 2; - if (f_len < 3) { + if (x_len < 3) { status = SILC_SKE_STATUS_BAD_PAYLOAD; goto err; } - if (payload->sign_len < 3) { + if ((ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) && + (payload->sign_len < 3 || !payload->sign_data)) { + SILC_LOG_DEBUG(("The signature data is missing - both parties are " + "required to do authentication")); status = SILC_SKE_STATUS_BAD_PAYLOAD; goto err; } @@ -548,11 +315,11 @@ SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske, goto err; } - /* Decode the HEX string to integer */ - silc_mp_init(&payload->f); - silc_mp_bin2mp(f, f_len, &payload->f); - memset(f, 0, sizeof(f_len)); - silc_free(f); + /* Decode the binary data to integer */ + silc_mp_init(&payload->x); + silc_mp_bin2mp(x, x_len, &payload->x); + memset(x, 0, sizeof(x_len)); + silc_free(x); /* Return the payload */ *return_payload = payload; @@ -569,13 +336,14 @@ SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske, return status; } -/* Free's KE2 Payload */ +/* Free's KE Payload */ -void silc_ske_payload_two_free(SilcSKETwoPayload *payload) +void silc_ske_payload_ke_free(SilcSKEKEPayload *payload) { if (payload) { if (payload->pk_data) silc_free(payload->pk_data); + silc_mp_clear(&payload->x); if (payload->sign_data) silc_free(payload->sign_data); silc_free(payload); diff --git a/lib/silcske/payload.h b/lib/silcske/payload.h index fa88e415..df982a7b 100644 --- a/lib/silcske/payload.h +++ b/lib/silcske/payload.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2000 Pekka Riikonen + Copyright (C) 2000 - 2001 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 @@ -33,19 +33,12 @@ silc_ske_payload_start_decode(SilcSKE ske, SilcBuffer buffer, SilcSKEStartPayload **return_payload); void silc_ske_payload_start_free(SilcSKEStartPayload *payload); -SilcSKEStatus silc_ske_payload_one_encode(SilcSKE ske, - SilcSKEOnePayload *payload, - SilcBuffer *return_buffer); -SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske, - SilcBuffer buffer, - SilcSKEOnePayload **return_payload); -void silc_ske_payload_one_free(SilcSKEOnePayload *payload); -SilcSKEStatus silc_ske_payload_two_encode(SilcSKE ske, - SilcSKETwoPayload *payload, - SilcBuffer *return_buffer); -SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske, - SilcBuffer buffer, - SilcSKETwoPayload **return_payload); -void silc_ske_payload_two_free(SilcSKETwoPayload *payload); +SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske, + SilcSKEKEPayload *payload, + SilcBuffer *return_buffer); +SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske, + SilcBuffer buffer, + SilcSKEKEPayload **return_payload); +void silc_ske_payload_ke_free(SilcSKEKEPayload *payload); #endif diff --git a/lib/silcske/payload_internal.h b/lib/silcske/payload_internal.h index 56bf497a..d6cc162e 100644 --- a/lib/silcske/payload_internal.h +++ b/lib/silcske/payload_internal.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2000 Pekka Riikonen + Copyright (C) 2000 - 2001 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 @@ -51,25 +51,16 @@ typedef struct { unsigned char *comp_alg_list; } SilcSKEStartPayload; -/* SILC Key Exchange 1 Payload */ +/* SILC Key Exchange Payload */ typedef struct { unsigned short pk_len; unsigned char *pk_data; unsigned short pk_type; - SilcInt e; -} SilcSKEOnePayload; - -/* SILC Key Exchange 2 Payload */ -typedef struct { - unsigned short pk_len; - unsigned char *pk_data; - unsigned short pk_type; - - SilcInt f; + SilcInt x; unsigned short sign_len; unsigned char *sign_data; -} SilcSKETwoPayload; +} SilcSKEKEPayload; #endif diff --git a/lib/silcske/silcske.c b/lib/silcske/silcske.c index e8e777a4..97873922 100644 --- a/lib/silcske/silcske.c +++ b/lib/silcske/silcske.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2000 Pekka Riikonen + Copyright (C) 2000 - 2001 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 @@ -48,13 +48,9 @@ void silc_ske_free(SilcSKE ske) if (ske->start_payload) silc_ske_payload_start_free(ske->start_payload); - /* Free KE1 payload */ + /* Free KE payload */ if (ske->ke1_payload) - silc_ske_payload_one_free(ske->ke1_payload); - - /* Free KE2 payload */ - if (ske->ke2_payload) - silc_ske_payload_two_free(ske->ke2_payload); + silc_ske_payload_ke_free(ske->ke1_payload); /* Free rest */ if (ske->prop) { @@ -222,17 +218,18 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, /* This function creates random number x, such that 1 < x < q and computes e = g ^ x mod p and sends the result to the remote end in - Key Exchange 1 Payload. */ + Key Exchange Payload. */ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, SilcPublicKey public_key, + SilcPrivateKey private_key, SilcSKESendPacketCb send_packet, void *context) { SilcSKEStatus status = SILC_SKE_STATUS_OK; SilcBuffer payload_buf; SilcInt *x, e; - SilcSKEOnePayload *payload; + SilcSKEKEPayload *payload; unsigned int pk_len; SILC_LOG_DEBUG(("Start")); @@ -257,10 +254,15 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, silc_mp_init(&e); silc_mp_powm(&e, &ske->prop->group->generator, x, &ske->prop->group->group); - - /* Encode the result to Key Exchange 1 Payload. */ + + /* Encode the result to Key Exchange Payload. */ + payload = silc_calloc(1, sizeof(*payload)); - payload->e = e; + ske->ke1_payload = payload; + + payload->x = e; + + /* Get public key */ payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len); if (!payload->pk_data) { silc_mp_clear(x); @@ -272,7 +274,32 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, } payload->pk_len = pk_len; payload->pk_type = SILC_SKE_PK_TYPE_SILC; - status = silc_ske_payload_one_encode(ske, payload, &payload_buf); + + /* Compute signature data if we are doing mutual authentication */ + if (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) { + unsigned char hash[32], sign[1024]; + unsigned int hash_len, sign_len; + + SILC_LOG_DEBUG(("We are doing mutual authentication")); + SILC_LOG_DEBUG(("Computing HASH value")); + + /* Compute the hash value */ + memset(hash, 0, sizeof(hash)); + silc_ske_make_hash(ske, hash, &hash_len, TRUE); + + SILC_LOG_DEBUG(("Signing HASH_i value")); + + /* Sign the hash value */ + silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, + private_key->prv_len); + silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len); + payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char)); + memcpy(payload->sign_data, sign, sign_len); + memset(sign, 0, sizeof(sign)); + payload->sign_len = sign_len; + } + + status = silc_ske_payload_ke_encode(ske, payload, &payload_buf); if (status != SILC_SKE_STATUS_OK) { silc_mp_clear(x); silc_free(x); @@ -283,7 +310,6 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, return status; } - ske->ke1_payload = payload; ske->x = x; /* Send the packet. */ @@ -295,19 +321,19 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, return status; } -/* Receives Key Exchange 2 Payload from responder consisting responders +/* Receives Key Exchange Payload from responder consisting responders public key, f, and signature. This function verifies the public key, computes the secret shared key and verifies the signature. */ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske, - SilcBuffer ke2_payload, + SilcBuffer ke_payload, SilcSKEVerifyCb verify_key, void *verify_context, SilcSKECb callback, void *context) { SilcSKEStatus status = SILC_SKE_STATUS_OK; - SilcSKETwoPayload *payload; + SilcSKEKEPayload *payload; SilcPublicKey public_key = NULL; SilcInt *KEY; unsigned char hash[32]; @@ -316,7 +342,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske, SILC_LOG_DEBUG(("Start")); /* Decode the payload */ - status = silc_ske_payload_two_decode(ske, ke2_payload, &payload); + status = silc_ske_payload_ke_decode(ske, ke_payload, &payload); if (status != SILC_SKE_STATUS_OK) { ske->status = status; return status; @@ -328,7 +354,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske, /* Compute the shared secret key */ KEY = silc_calloc(1, sizeof(*KEY)); silc_mp_init(KEY); - silc_mp_powm(KEY, &payload->f, ske->x, &ske->prop->group->group); + silc_mp_powm(KEY, &payload->x, ske->x, &ske->prop->group->group); ske->KEY = KEY; SILC_LOG_DEBUG(("Verifying public key")); @@ -349,7 +375,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske, SILC_LOG_DEBUG(("Public key is authentic")); /* Compute the hash value */ - status = silc_ske_make_hash(ske, hash, &hash_len); + status = silc_ske_make_hash(ske, hash, &hash_len, FALSE); if (status != SILC_SKE_STATUS_OK) goto err; @@ -357,7 +383,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske, memcpy(ske->hash, hash, hash_len); ske->hash_len = hash_len; - SILC_LOG_DEBUG(("Verifying signature")); + SILC_LOG_DEBUG(("Verifying signature (HASH_i)")); /* Verify signature */ silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk, @@ -384,7 +410,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske, err: memset(hash, 'F', sizeof(hash)); - silc_ske_payload_two_free(payload); + silc_ske_payload_ke_free(payload); ske->ke2_payload = NULL; silc_mp_clear(ske->KEY); @@ -417,6 +443,7 @@ SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng, SilcSocketConnection sock, char *version, SilcBuffer start_payload, + int mutual_auth, SilcSKECb callback, void *context) { @@ -439,6 +466,12 @@ SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng, compute the HASH value. */ ske->start_payload_copy = silc_buffer_copy(start_payload); + /* Force the mutual authentication flag if we want to do it. */ + if (mutual_auth) { + SILC_LOG_DEBUG(("Force mutual authentication")); + remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL; + } + /* Parse and select the security properties from the payload */ payload = silc_calloc(1, sizeof(*payload)); status = silc_ske_select_security_properties(ske, version, @@ -551,33 +584,87 @@ SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske, return status; } -/* This function receives the Key Exchange 1 Payload from the initiator. +/* This function receives the Key Exchange Payload from the initiator. After processing the payload this then selects random number x, such that 1 < x < q and computes f = g ^ x mod p. This then puts - the result f to a Key Exchange 2 Payload which is later processed + the result f to a Key Exchange Payload which is later processed in ske_responder_finish function. The callback function should not touch the payload (it should merely call the ske_responder_finish function). */ SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske, - SilcBuffer ke1_payload, + SilcBuffer ke_payload, + SilcSKEVerifyCb verify_key, + void *verify_context, SilcSKECb callback, void *context) { SilcSKEStatus status = SILC_SKE_STATUS_OK; - SilcSKEOnePayload *one_payload; - SilcSKETwoPayload *two_payload; + SilcSKEKEPayload *recv_payload, *send_payload; SilcInt *x, f; SILC_LOG_DEBUG(("Start")); - /* Decode Key Exchange 1 Payload */ - status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload); + /* Decode Key Exchange Payload */ + status = silc_ske_payload_ke_decode(ske, ke_payload, &recv_payload); if (status != SILC_SKE_STATUS_OK) { ske->status = status; return status; } + ske->ke1_payload = recv_payload; + + /* Verify the received public key and verify the signature if we are + doing mutual authentication. */ + if (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) { + SilcPublicKey public_key = NULL; + unsigned char hash[32]; + unsigned int hash_len; + + SILC_LOG_DEBUG(("We are doing mutual authentication")); + SILC_LOG_DEBUG(("Verifying public key")); + + if (!silc_pkcs_public_key_decode(recv_payload->pk_data, + recv_payload->pk_len, + &public_key)) { + status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY; + return status; + } + + if (verify_key) { + status = (*verify_key)(ske, recv_payload->pk_data, recv_payload->pk_len, + recv_payload->pk_type, verify_context); + if (status != SILC_SKE_STATUS_OK) + return status; + } + + SILC_LOG_DEBUG(("Public key is authentic")); + + /* Compute the hash value */ + status = silc_ske_make_hash(ske, hash, &hash_len, TRUE); + if (status != SILC_SKE_STATUS_OK) + return status; + + SILC_LOG_DEBUG(("Verifying signature")); + + /* Verify signature */ + silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk, + public_key->pk_len); + if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data, + recv_payload->sign_len, hash, hash_len) == FALSE) { + + SILC_LOG_DEBUG(("Signature don't match")); + + status = SILC_SKE_STATUS_INCORRECT_SIGNATURE; + return status; + } + + SILC_LOG_DEBUG(("Signature is Ok")); + + silc_pkcs_public_key_free(public_key); + memset(hash, 'F', hash_len); + } + /* Create the random number x, 1 < x < q. */ x = silc_calloc(1, sizeof(*x)); silc_mp_init(x); @@ -599,11 +686,10 @@ SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske, &ske->prop->group->group); /* Save the results for later processing */ - two_payload = silc_calloc(1, sizeof(*two_payload)); - two_payload->f = f; + send_payload = silc_calloc(1, sizeof(*send_payload)); + send_payload->x = f; ske->x = x; - ske->ke1_payload = one_payload; - ske->ke2_payload = two_payload; + ske->ke2_payload = send_payload; /* Call the callback. */ if (callback) @@ -614,7 +700,7 @@ SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske, /* This function computes the secret shared key KEY = e ^ x mod p, and, a hash value to be signed and sent to the other end. This then - encodes Key Exchange 2 Payload and sends it to the other end. */ + encodes Key Exchange Payload and sends it to the other end. */ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske, SilcPublicKey public_key, @@ -641,7 +727,7 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske, /* Compute the shared secret key */ KEY = silc_calloc(1, sizeof(*KEY)); silc_mp_init(KEY); - silc_mp_powm(KEY, &ske->ke1_payload->e, ske->x, + silc_mp_powm(KEY, &ske->ke1_payload->x, ske->x, &ske->prop->group->group); ske->KEY = KEY; @@ -661,7 +747,7 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske, /* Compute the hash value */ memset(hash, 0, sizeof(hash)); - status = silc_ske_make_hash(ske, hash, &hash_len); + status = silc_ske_make_hash(ske, hash, &hash_len, FALSE); if (status != SILC_SKE_STATUS_OK) goto err; @@ -680,9 +766,9 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske, memset(sign, 0, sizeof(sign)); ske->ke2_payload->sign_len = sign_len; - /* Encode the Key Exchange 2 Payload */ - status = silc_ske_payload_two_encode(ske, ske->ke2_payload, - &payload_buf); + /* Encode the Key Exchange Payload */ + status = silc_ske_payload_ke_encode(ske, ske->ke2_payload, + &payload_buf); if (status != SILC_SKE_STATUS_OK) goto err; @@ -698,7 +784,7 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske, silc_mp_clear(ske->KEY); silc_free(ske->KEY); ske->KEY = NULL; - silc_ske_payload_two_free(ske->ke2_payload); + silc_ske_payload_ke_free(ske->ke2_payload); if (status == SILC_SKE_STATUS_OK) return SILC_SKE_STATUS_ERROR; @@ -1223,11 +1309,15 @@ SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n, return status; } -/* Creates a hash value HASH as defined in the SKE protocol. */ +/* Creates a hash value HASH as defined in the SKE protocol. If the + `initiator' is TRUE then this function is used to create the HASH_i + hash value defined in the protocol. If it is FALSE then this is used + to create the HASH value defined by the protocol. */ SilcSKEStatus silc_ske_make_hash(SilcSKE ske, unsigned char *return_hash, - unsigned int *return_hash_len) + unsigned int *return_hash_len, + int initiator) { SilcSKEStatus status = SILC_SKE_STATUS_OK; SilcBuffer buf; @@ -1237,47 +1327,79 @@ SilcSKEStatus silc_ske_make_hash(SilcSKE ske, SILC_LOG_DEBUG(("Start")); - e = silc_mp_mp2bin(&ske->ke1_payload->e, 0, &e_len); - f = silc_mp_mp2bin(&ske->ke2_payload->f, 0, &f_len); - KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len); - - buf = silc_buffer_alloc(ske->start_payload_copy->len + - ske->pk_len + e_len + f_len + KEY_len); - silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf)); + if (initiator == FALSE) { + e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len); + f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len); + KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len); + + buf = silc_buffer_alloc(ske->start_payload_copy->len + + ske->pk_len + e_len + f_len + KEY_len); + silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf)); + + /* Format the buffer used to compute the hash value */ + ret = + silc_buffer_format(buf, + SILC_STR_UI_XNSTRING(ske->start_payload_copy->data, + ske->start_payload_copy->len), + SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len), + SILC_STR_UI_XNSTRING(e, e_len), + SILC_STR_UI_XNSTRING(f, f_len), + SILC_STR_UI_XNSTRING(KEY, KEY_len), + SILC_STR_END); + if (ret == -1) { + silc_buffer_free(buf); + memset(e, 0, e_len); + memset(f, 0, f_len); + memset(KEY, 0, KEY_len); + silc_free(e); + silc_free(f); + silc_free(KEY); + return SILC_SKE_STATUS_ERROR; + } - /* Format the buffer used to compute the hash value */ - ret = silc_buffer_format(buf, - SILC_STR_UI_XNSTRING(ske->start_payload_copy->data, - ske->start_payload_copy->len), - SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len), - SILC_STR_UI_XNSTRING(e, e_len), - SILC_STR_UI_XNSTRING(f, f_len), - SILC_STR_UI_XNSTRING(KEY, KEY_len), - SILC_STR_END); - if (ret == -1) { - silc_buffer_free(buf); memset(e, 0, e_len); memset(f, 0, f_len); memset(KEY, 0, KEY_len); silc_free(e); silc_free(f); silc_free(KEY); - return SILC_SKE_STATUS_ERROR; + } else { + e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len); + + buf = silc_buffer_alloc(ske->start_payload_copy->len + + ske->pk_len + e_len); + silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf)); + + /* Format the buffer used to compute the hash value */ + ret = + silc_buffer_format(buf, + SILC_STR_UI_XNSTRING(ske->start_payload_copy->data, + ske->start_payload_copy->len), + SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len), + SILC_STR_UI_XNSTRING(e, e_len), + SILC_STR_END); + if (ret == -1) { + silc_buffer_free(buf); + memset(e, 0, e_len); + silc_free(e); + return SILC_SKE_STATUS_ERROR; + } + + memset(e, 0, e_len); + silc_free(e); } /* Make the hash */ silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash); *return_hash_len = ske->prop->hash->hash->hash_len; - SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len); + if (initiator == FALSE) { + SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len); + } else { + SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len); + } silc_buffer_free(buf); - memset(e, 0, e_len); - memset(f, 0, f_len); - memset(KEY, 0, KEY_len); - silc_free(e); - silc_free(f); - silc_free(KEY); return status; } diff --git a/lib/silcske/silcske.h b/lib/silcske/silcske.h index 880475e0..13e82eb6 100644 --- a/lib/silcske/silcske.h +++ b/lib/silcske/silcske.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2000 Pekka Riikonen + Copyright (C) 2000 - 2001 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 @@ -77,9 +77,10 @@ typedef struct { /* Security Property Flags. */ typedef enum { - SILC_SKE_SP_FLAG_NONE = (1L << 0), - SILC_SKE_SP_FLAG_NO_REPLY = (1L << 1), - SILC_SKE_SP_FLAG_PFS = (1L << 2), + SILC_SKE_SP_FLAG_NONE = 0x00, + SILC_SKE_SP_FLAG_NO_REPLY = 0x01, + SILC_SKE_SP_FLAG_PFS = 0x02, + SILC_SKE_SP_FLAG_MUTUAL = 0x04, } SilcSKESecurityPropertyFlag; /* Security Properties negotiated between key exchange parties. This @@ -106,8 +107,8 @@ struct SilcSKEStruct { /* Key Exchange payloads filled during key negotiation with remote data. Responder may save local data here as well. */ SilcSKEStartPayload *start_payload; - SilcSKEOnePayload *ke1_payload; - SilcSKETwoPayload *ke2_payload; + SilcSKEKEPayload *ke1_payload; + SilcSKEKEPayload *ke2_payload; /* Temporary copy of the KE Start Payload used in the HASH computation. */ @@ -155,10 +156,11 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, void *context); SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, SilcPublicKey public_key, + SilcPrivateKey private_key, SilcSKESendPacketCb send_packet, void *context); SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske, - SilcBuffer ke2_payload, + SilcBuffer ke_payload, SilcSKEVerifyCb verify_key, void *verify_context, SilcSKECb callback, @@ -167,6 +169,7 @@ SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng, SilcSocketConnection sock, char *version, SilcBuffer start_payload, + int mutual_auth, SilcSKECb callback, void *context); SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske, @@ -174,7 +177,9 @@ SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske, SilcSKESendPacketCb send_packet, void *context); SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske, - SilcBuffer ke1_payload, + SilcBuffer ke_payload, + SilcSKEVerifyCb verify_key, + void *verify_context, SilcSKECb callback, void *context); SilcSKEStatus silc_ske_responder_finish(SilcSKE ske, @@ -204,7 +209,8 @@ SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n, SilcInt *rnd); SilcSKEStatus silc_ske_make_hash(SilcSKE ske, unsigned char *return_hash, - unsigned int *return_hash_len); + unsigned int *return_hash_len, + int initiator); SilcSKEStatus silc_ske_process_key_material_data(unsigned char *data, unsigned int data_len, -- 2.24.0