+Sun Apr 1 19:49:34 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * 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 <priikone@poseidon.pspt.fi>
* Fixed packet processing on slow links. Partial packets were
be provided when joining to the channel.
c <cipher> Set/unset channel's cipher
h <hmac> Set/unset channel's hmac
+ f <-pubkey|<password>
+ 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 <channel> +|-<modes> <nickname>[@<server>]
+ /CUMODE <channel> +|-<modes> <nickname>[@<server>] [-pubkey|<passwd>]
Changes/set user's mode on a channel. Most of the modes
require that the client who changes some client's mode must
user modes are available:
a <nickname>[@<server>]
+
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 <nickname>[@<server>]
- 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 <nickname>[@<server>] [-pubkey|<password>]
+
+ Set/Unset channel founder. If the -pubkey
+ option or <password> 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 <nickname>[@<server>]
+
Set/unset channel operator. Requires that
you are channel operator or channel founder.
/UMODE +|-<modes>
- 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 <nickname> <message>
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.
}
}
- 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",
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,
}
if (cmd->argc == 1) {
+ conn->local_entry->mode &= ~SILC_UMODE_GONE;
+
if (conn->away) {
silc_free(conn->away->away);
silc_free(conn->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
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);
}
}
}
} 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 */
}
}
} 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);
}
}
}
}
} 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. */
}
}
} 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);
}
}
}
}
- if (!channel) {
+ if (!channel || !channel->id) {
/* Channel not found */
/* If we are standalone server we don't have a router, we just create
*/
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 */
}
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,
}
}
+ 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;
}
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);
}
}
+ 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;
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);
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;
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);
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;
}
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
}
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) {
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;
}
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) {
{
SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
SilcServer server = cmd->server;
+ SilcIDCacheEntry cache = NULL;
SilcCommandStatus status;
SilcChannelID *id;
SilcClientID *client_id = NULL;
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 */
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) {
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
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;
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. */
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);
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;
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
status =
silc_ske_initiator_phase_2(ctx->ske,
server->public_key,
+ server->private_key,
silc_server_protocol_ke_send_packet,
context);
}
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);
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);
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;
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;
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;
/* 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;
}
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;
}
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;
}
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
.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
.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
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
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.
.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
| 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
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
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
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.
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:
.in 3
.ce
-Figure 4: Connection Auth Payload
+Figure 3: Connection Auth Payload
.in 6
privileges by SILC_COMMAND_SILCOPER command. Client
may unset the mode itself.
+
Reply messages to the command:
Max Arguments: 2
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
17 SILC_COMMAND_CMODE
- Max Arguments: 6
- Arguments: (1) <Channel ID> (2) <channel mode mask>
- (3) [<user limit>] (4) [<passphrase>]
- (5) [<cipher>] (6) [<hmac>]
+ Max Arguments: 7
+ Arguments: (1) <Channel ID> (2) <channel mode mask>
+ (3) [<user limit>] (4) [<passphrase>]
+ (5) [<cipher>] (6) [<hmac>]
+ (7) [<auth payload>]
This command is used by client to set or change channel flags on
a channel. Channel has several modes that set various properties
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 <auth payload> 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
18 SILC_COMMAND_CUMODE
- Max Arguments: 3
- Arguments: (1) <Channel ID> (2) <mode mask>
- (3) <Client ID>
+ Max Arguments: 4
+ Arguments: (1) <Channel ID> (2) <mode mask>
+ (3) <Client ID> (4) [<auth payload>]
This command is used by client to change channel user modes on
channel. Users on channel may have some special modes and this
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 <auth payload> that the server will use
+ to authenticate the client. The client can remove this
+ mode at any time.
0x0002 SILC_CUMODE_OPERATOR
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
/* 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;
}
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;
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;
}
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;
}
/* 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);
/* 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);
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.
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));
/*
* 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
/* 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);
}
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;
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;
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;
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;
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;
}
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)
/* 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;
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));
/* 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. */
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;
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) {
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);
/* 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 */
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);
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,
}
}
+/* 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
}
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),
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)
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;
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,
}
/* 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,
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,
silc_free(tmp);
silc_pkcs_free(pkcs);
- SILC_LOG_DEBUG(("Authentication successfull"));
+ SILC_LOG_DEBUG(("Authentication successful"));
return TRUE;
}
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;
/* 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;
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;
}
#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,
#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
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));
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));
Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- 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
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"));
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;
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;
}
}
-/* 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 */
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;
}
/* 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));
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);
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;
}
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;
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);
Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- 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
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
Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- 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
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
Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- 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
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) {
/* 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"));
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);
}
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);
return status;
}
- ske->ke1_payload = payload;
ske->x = x;
/* Send the packet. */
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];
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;
/* 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"));
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;
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,
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);
SilcSocketConnection sock,
char *version,
SilcBuffer start_payload,
+ int mutual_auth,
SilcSKECb callback,
void *context)
{
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,
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);
&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)
/* 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,
/* 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;
/* 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;
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;
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;
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;
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;
}
Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- 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
/* 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
/* 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. */
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,
SilcSocketConnection sock,
char *version,
SilcBuffer start_payload,
+ int mutual_auth,
SilcSKECb callback,
void *context);
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,
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,