file.
+Tue Mar 12 17:58:59 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added silc_hash_public_key and silc_hash_public_key_compare
+ functions to be used with SilcHashTable. They can be used to
+ hash public keys and compare public keys in hash table. Affected
+ file lib/silcutil/silcutil.[ch].
+
+ * Added support for specifying multiple public keys for Client
+ connection section in server configuration file. This makes it
+ possible to accept multiple public keys from same host, or to
+ make a section that accepts any incoming host, and have the
+ accepted public keys listed in the section.
+
+ Added functions silc_sever_[find/get]_public_key, added the
+ support for this actually to all connection sections but only
+ the Client section is currently allowed to specify multiple
+ public keys.
+
+ Affected files are silcd/server.c, server_internal.h,
+ command.c, protocol.c, server_util.[ch], packet_receive.c.
+
Mon Mar 11 23:37:38 EET 2002 Pekka Riikonen <priikone@silcnet.org>
* Merged Irssi 0.8.2 from irssi.org CVS.
o Configuration file additions:
- o Add support for multipe PublicKey params in connections
- sections. For now, add this support only in Client and not
- in ServerConnection nor RouterConnection.
-
o Add version handling, to allow, disallow certain versions to
connect.
SilcServerConfigAdmin *admin;
SilcIDListData idata = (SilcIDListData)client;
bool result = FALSE;
+ SilcPublicKey cached_key;
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2);
result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PASSWORD,
admin->passphrase, admin->passphrase_len,
idata->hash, client->id, SILC_ID_CLIENT);
- if (!result && admin->publickey)
+ if (!result && admin->publickeys) {
+ cached_key = silc_server_get_public_key(server, admin->publickeys);
+ if (!cached_key)
+ goto out;
result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PUBLIC_KEY,
- admin->publickey, 0,
- idata->hash, client->id, SILC_ID_CLIENT);
+ cached_key, 0, idata->hash,
+ client->id, SILC_ID_CLIENT);
+ }
if (!result) {
/* Authentication failed */
silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
SilcServerConfigAdmin *admin;
SilcIDListData idata = (SilcIDListData)client;
bool result = FALSE;
+ SilcPublicKey cached_key;
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PASSWORD,
admin->passphrase, admin->passphrase_len,
idata->hash, client->id, SILC_ID_CLIENT);
- if (!result && admin->publickey)
+ if (!result && admin->publickeys) {
+ cached_key = silc_server_get_public_key(server, admin->publickeys);
+ if (!cached_key)
+ goto out;
result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PUBLIC_KEY,
- admin->publickey, 0,
- idata->hash, client->id, SILC_ID_CLIENT);
+ cached_key, 0, idata->hash,
+ client->id, SILC_ID_CLIENT);
+ }
if (!result) {
/* Authentication failed */
silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
client = silc_server_config_find_client(server, sock->hostname);
if (client) {
if (client->passphrase) {
- if (client->publickey && !server->config->prefer_passphrase_auth)
+ if (client->publickeys && !server->config->prefer_passphrase_auth)
auth_meth = SILC_AUTH_PUBLIC_KEY;
else
auth_meth = SILC_AUTH_PASSWORD;
- } else if (client->publickey)
+ } else if (client->publickeys)
auth_meth = SILC_AUTH_PUBLIC_KEY;
}
if (ske->status != SILC_SKE_STATUS_OK) {
SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol",
silc_ske_map_status(ske->status)));
- SILC_LOG_DEBUG(("Error (%s) during Key Exchange protocol",
- silc_ske_map_status(ske->status)));
-
+
protocol->state = SILC_PROTOCOL_STATE_ERROR;
silc_protocol_execute(protocol, server->schedule, 0, 300000);
return;
if (status != SILC_SKE_STATUS_OK) {
SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol",
silc_ske_map_status(status)));
- SILC_LOG_DEBUG(("Error (%s) during Key Exchange protocol",
- silc_ske_map_status(status)));
protocol->state = SILC_PROTOCOL_STATE_ERROR;
silc_protocol_execute(protocol, server->schedule, 0, 300000);
if (status != SILC_SKE_STATUS_OK) {
SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol",
silc_ske_map_status(status)));
- SILC_LOG_DEBUG(("Error (%s) during Key Exchange protocol",
- silc_ske_map_status(status)));
protocol->state = SILC_PROTOCOL_STATE_ERROR;
silc_protocol_execute(protocol, server->schedule, 0, 300000);
if (status != SILC_SKE_STATUS_OK) {
SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol",
silc_ske_map_status(status)));
- SILC_LOG_DEBUG(("Error (%s) during Key Exchange protocol",
- silc_ske_map_status(status)));
protocol->state = SILC_PROTOCOL_STATE_ERROR;
silc_protocol_execute(protocol, server->schedule, 0, 300000);
if (status != SILC_SKE_STATUS_OK) {
SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol",
silc_ske_map_status(status)));
- SILC_LOG_DEBUG(("Error (%s) during Key Exchange protocol",
- silc_ske_map_status(status)));
protocol->state = SILC_PROTOCOL_STATE_ERROR;
silc_protocol_execute(protocol, server->schedule, 0, 300000);
static bool
silc_server_get_authentication(SilcServerConnAuthInternalContext *ctx,
char *local_passphrase,
- void *local_publickey,
+ SilcHashTable local_publickeys,
unsigned char *remote_auth,
SilcUInt32 remote_auth_len)
{
/* If we don't have authentication data set at all we do not require
authentication at all */
- if (!local_passphrase && !local_publickey) {
+ if (!local_passphrase && (!local_publickeys ||
+ !silc_hash_table_count(local_publickeys))) {
SILC_LOG_DEBUG(("No authentication required"));
return TRUE;
}
}
/* Try public key authenetication */
- if (!result && local_publickey) {
+ if (!result && local_publickeys) {
+ SilcPublicKey cached_key;
+ SilcPublicKey remote_key =
+ ((SilcIDListData)ctx->sock->user_data)->public_key;
+
SILC_LOG_DEBUG(("Public key authentication"));
- result = silc_server_public_key_authentication(server,
- local_publickey,
+
+ /* Find the public key to be used in authentication */
+ cached_key = silc_server_find_public_key(server, local_publickeys,
+ remote_key);
+ if (!cached_key)
+ return FALSE;
+
+ result = silc_server_public_key_authentication(server, cached_key,
remote_auth,
- remote_auth_len,
- ske);
+ remote_auth_len, ske);
}
return result;
if (client) {
ret = silc_server_get_authentication(ctx, client->passphrase,
- client->publickey,
+ client->publickeys,
auth_data, payload_len);
if (!ret) {
/* Authentication failed */
SILC_LOG_ERROR(("Authentication failed"));
- SILC_LOG_DEBUG(("Authentication failed"));
silc_free(auth_data);
protocol->state = SILC_PROTOCOL_STATE_ERROR;
silc_protocol_execute(protocol, server->schedule, 0, 300000);
return;
}
} else {
- SILC_LOG_DEBUG(("No configuration for remote client connection"));
SILC_LOG_ERROR(("Remote client connection not configured"));
SILC_LOG_ERROR(("Authentication failed"));
silc_free(auth_data);
if (serv) {
ret = silc_server_get_authentication(ctx, serv->passphrase,
- serv->publickey,
+ serv->publickeys,
auth_data, payload_len);
if (!ret) {
/* Authentication failed */
SILC_LOG_ERROR(("Authentication failed"));
- SILC_LOG_DEBUG(("Authentication failed"));
silc_free(auth_data);
protocol->state = SILC_PROTOCOL_STATE_ERROR;
silc_protocol_execute(protocol, server->schedule, 0, 300000);
return;
}
} else {
- SILC_LOG_DEBUG(("No configuration for remote server connection"));
SILC_LOG_ERROR(("Remote server connection not configured"));
SILC_LOG_ERROR(("Authentication failed"));
protocol->state = SILC_PROTOCOL_STATE_ERROR;
if (serv) {
ret = silc_server_get_authentication(ctx, serv->passphrase,
- serv->publickey,
+ serv->publickeys,
auth_data, payload_len);
if (!ret) {
/* Authentication failed */
SILC_LOG_ERROR(("Authentication failed"));
- SILC_LOG_DEBUG(("Authentication failed"));
silc_free(auth_data);
protocol->state = SILC_PROTOCOL_STATE_ERROR;
silc_protocol_execute(protocol, server->schedule, 0, 300000);
return;
}
} else {
- SILC_LOG_DEBUG(("No configuration for remote router connection"));
SILC_LOG_ERROR(("Remote router connection not configured"));
SILC_LOG_ERROR(("Authentication failed"));
silc_free(auth_data);
conn = sconn->conn;
if (conn) {
- /* Match found. Use the configured authentication method */
+ /* Match found. Use the configured authentication method. Take only
+ the passphrase, since for public key auth we automatically use
+ our local key pair. */
if (conn->passphrase) {
- if (conn->publickey && !server->config->prefer_passphrase_auth) {
- proto_ctx->auth_data = conn->publickey;
- proto_ctx->auth_data_len = 0;
+ if (conn->publickeys && !server->config->prefer_passphrase_auth) {
proto_ctx->auth_meth = SILC_AUTH_PUBLIC_KEY;
} else {
proto_ctx->auth_data = strdup(conn->passphrase);
proto_ctx->auth_data_len = strlen(conn->passphrase);
proto_ctx->auth_meth = SILC_AUTH_PASSWORD;
}
- } else if (conn->publickey) {
- proto_ctx->auth_data = conn->publickey;
- proto_ctx->auth_data_len = 0;
+ } else if (conn->publickeys) {
proto_ctx->auth_meth = SILC_AUTH_PUBLIC_KEY;
} else {
proto_ctx->auth_meth = SILC_AUTH_NONE;
if ((x)) { \
if ((x)->param && (x)->param->key_exchange_pfs) \
(p)->flags |= SILC_SKE_SP_FLAG_PFS; \
- if (!(x)->publickey) \
+ if (!(x)->publickeys) \
(p)->flags |= SILC_SKE_SP_FLAG_MUTUAL; \
}
/* Remove the client from all channels. The client is removed from
the channels' user list. */
silc_hash_table_list(client->channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
channel = chl->channel;
/* Remove channel from client's channel list */
channel->disabled = TRUE;
silc_hash_table_list(channel->user_list, &htl2);
- while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
+ while (silc_hash_table_get(&htl2, NULL, (void **)&chl2)) {
silc_hash_table_del(chl2->client->channels, channel);
silc_hash_table_del(channel->user_list, chl2->client);
channel->user_count--;
this server's client(s) on the channel. As they left the channel we
must re-generate the channel key. */
silc_hash_table_list(channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
+ while (silc_hash_table_get(&htl, NULL, (void **)&channel)) {
if (!silc_server_create_channel_key(server, channel, 0)) {
silc_hash_table_list_reset(&htl);
silc_hash_table_free(channels);
SilcHashTableList htl;
silc_hash_table_list(channel->user_list, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
if (chl->client->router) {
silc_hash_table_list_reset(&htl);
return TRUE;
SilcHashTableList htl;
silc_hash_table_list(channel->user_list, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
if (!chl->client->router) {
silc_hash_table_list_reset(&htl);
return TRUE;
return count;
}
+
+/* Finds locally cached public key by the public key received in the SKE.
+ If we have it locally cached then we trust it and will use it in the
+ authentication protocol. Returns the locally cached public key or NULL
+ if we do not find the public key. */
+
+SilcPublicKey silc_server_find_public_key(SilcServer server,
+ SilcHashTable local_public_keys,
+ SilcPublicKey remote_public_key)
+{
+ SilcPublicKey cached_key;
+
+ SILC_LOG_DEBUG(("Find remote public key (%d keys in local cache)",
+ silc_hash_table_count(local_public_keys)));
+
+ if (!silc_hash_table_find_ext(local_public_keys, remote_public_key,
+ (void **)&cached_key, NULL,
+ silc_hash_public_key, NULL,
+ silc_hash_public_key_compare, NULL)) {
+ SILC_LOG_ERROR(("Public key not found"));
+ return NULL;
+ }
+
+ SILC_LOG_DEBUG(("Found public key"));
+
+ return cached_key;
+}
+
+/* This returns the first public key from the table of public keys. This
+ is used only in cases where single public key exists in the table and
+ we want to get a pointer to it. For public key tables that has multiple
+ keys in it the silc_server_find_public_key must be used. */
+
+SilcPublicKey silc_server_get_public_key(SilcServer server,
+ SilcHashTable local_public_keys)
+{
+ SilcPublicKey cached_key;
+ SilcHashTableList htl;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ assert(silc_hash_table_count(local_public_keys) < 2);
+
+ silc_hash_table_list(local_public_keys, &htl);
+ if (!silc_hash_table_get(&htl, NULL, (void **)&cached_key))
+ return NULL;
+ silc_hash_table_list_reset(&htl);
+
+ return cached_key;
+}
SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip,
SilcSocketType type);
+/* Finds locally cached public key by the public key received in the SKE.
+ If we have it locally cached then we trust it and will use it in the
+ authentication protocol. Returns the locally cached public key or NULL
+ if we do not find the public key. */
+SilcPublicKey silc_server_find_public_key(SilcServer server,
+ SilcHashTable local_public_keys,
+ SilcPublicKey remote_public_key);
+
+/* This returns the first public key from the table of public keys. This
+ is used only in cases where single public key exists in the table and
+ we want to get a pointer to it. For public key tables that has multiple
+ keys in it the silc_server_find_public_key must be used. */
+SilcPublicKey silc_server_get_public_key(SilcServer server,
+ SilcHashTable local_public_keys);
+
#endif /* SERVER_UTIL_H */
/* Free the authentication fields in the specified struct
* Expands to two instructions */
-#define CONFIG_FREE_AUTH(__section__) \
- silc_free(__section__->passphrase); \
- silc_pkcs_public_key_free(__section__->publickey)
+#define CONFIG_FREE_AUTH(__section__) \
+ silc_free(__section__->passphrase); \
+ if (__section__->publickeys) \
+ silc_hash_table_free(__section__->publickeys);
+
+static void my_free_public_key(void *key, void *context, void *user_data)
+{
+ silc_pkcs_public_key_free(context);
+}
/* Set default values to those parameters that have not been defined */
static void
}
/* parse an authdata according to its auth method */
-static bool my_parse_authdata(SilcAuthMethod auth_meth, char *p, SilcUInt32 line,
- void **auth_data, SilcUInt32 *auth_data_len)
+static bool my_parse_authdata(SilcAuthMethod auth_meth, char *p,
+ SilcUInt32 line, void **auth_data,
+ SilcUInt32 *auth_data_len)
{
if (auth_meth == SILC_AUTH_PASSWORD) {
/* p is a plain text password */
if (auth_data_len)
*auth_data_len = (SilcUInt32) strlen(p);
} else if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
- /* p is a public key */
+ /* p is a public key file name */
SilcPublicKey public_key;
if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_PEM))
"Could not load public key file!\n", line);
return FALSE;
}
- if (auth_data)
- *auth_data = (void *) public_key;
- if (auth_data_len)
- *auth_data_len = 0;
+
+ /* The auth_data is a pointer to the hash table of public keys. */
+ if (auth_data) {
+ if (*auth_data == NULL)
+ *auth_data = silc_hash_table_alloc(1, silc_hash_public_key, NULL,
+ NULL, NULL,
+ my_free_public_key, NULL,
+ TRUE);
+ silc_hash_table_add(*auth_data, public_key, public_key);
+ }
} else {
fprintf(stderr, "\nError while parsing config file at line %lu: "
"Unknown authentication method.\n", line);
tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
}
else if (!strcmp(name, "passphrase")) {
+ CONFIG_IS_DOUBLE(tmp->passphrase);
if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
(void **)&tmp->passphrase,
&tmp->passphrase_len)) {
}
else if (!strcmp(name, "publickey")) {
if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
- &tmp->publickey, NULL)) {
+ (void **)&tmp->publickeys, NULL)) {
got_errno = SILC_CONFIG_ESILENT;
goto got_err;
}
tmp->nick = (*(char *)val ? strdup((char *) val) : NULL);
}
else if (!strcmp(name, "passphrase")) {
+ CONFIG_IS_DOUBLE(tmp->passphrase);
if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
(void **)&tmp->passphrase,
&tmp->passphrase_len)) {
}
}
else if (!strcmp(name, "publickey")) {
+ CONFIG_IS_DOUBLE(tmp->publickeys);
if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
- &tmp->publickey, NULL)) {
+ (void **)&tmp->publickeys, NULL)) {
got_errno = SILC_CONFIG_ESILENT;
goto got_err;
}
tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
}
else if (!strcmp(name, "passphrase")) {
+ CONFIG_IS_DOUBLE(tmp->passphrase);
if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
(void **)&tmp->passphrase,
&tmp->passphrase_len)) {
}
}
else if (!strcmp(name, "publickey")) {
+ CONFIG_IS_DOUBLE(tmp->publickeys);
if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
- &tmp->publickey, NULL)) {
+ (void **)&tmp->publickeys, NULL)) {
got_errno = SILC_CONFIG_ESILENT;
goto got_err;
}
tmp->port = (SilcUInt16) port;
}
else if (!strcmp(name, "passphrase")) {
+ CONFIG_IS_DOUBLE(tmp->passphrase);
if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val, line,
(void **)&tmp->passphrase,
&tmp->passphrase_len)) {
}
}
else if (!strcmp(name, "publickey")) {
+ CONFIG_IS_DOUBLE(tmp->publickeys);
if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val, line,
- &tmp->publickey, NULL)) {
+ (void **)&tmp->publickeys, NULL)) {
got_errno = SILC_CONFIG_ESILENT;
goto got_err;
}
char *host;
unsigned char *passphrase;
SilcUInt32 passphrase_len;
- void *publickey;
+ SilcHashTable publickeys;
SilcServerConfigConnParams *param;
struct SilcServerConfigClientStruct *next;
} SilcServerConfigClient;
char *nick;
unsigned char *passphrase;
SilcUInt32 passphrase_len;
- void *publickey;
+ SilcHashTable publickeys;
struct SilcServerConfigAdminStruct *next;
} SilcServerConfigAdmin;
char *host;
unsigned char *passphrase;
SilcUInt32 passphrase_len;
- void *publickey;
+ SilcHashTable publickeys;
char *version;
SilcServerConfigConnParams *param;
bool backup_router;
char *host;
unsigned char *passphrase;
SilcUInt32 passphrase_len;
- void *publickey;
+ SilcHashTable publickeys;
SilcUInt16 port;
char *version;
SilcServerConfigConnParams *param;
# "param" is optional and can be used to set specific connection parameters
# for this connection.
#
-# The authentication data is specified by Passphrase and/or Publickey.
+# The authentication data is specified by Passphrase and/or PublicKey.
# If both are provided then both password and public key based authentication
# is allowed. If the Publickey is used it includes the file path to the
# public key file. If none of them is provided then authentication is not
-# required.
+# required. The PublicKey can be set multiple times to set multiple
+# public keys for one connection.
#
# Next example connection will match to all incoming client connections,
# and no authentication is required.
Client {
#Host = "10.1.*";
#Passphrase = "secret";
- #PublicKey = "/path/to/the/public.key";
+ #PublicKey = "/path/to/the/user_my.key";
+ #PublicKey = "/path/to/the/user_221.key";
+ #PublicKey = "/path/to/the/user_313.key";
Params = "normal";
};
# The fields "Host", "User", and "Nick", are optional but you are encouraged
# in using them to better identify your admins.
#
-# The authentication data is specified by Passphrase and/or Publickey.
+# The authentication data is specified by Passphrase and/or PublicKey.
# If both are provided then both password and public key based authentication
-# is allowed. If the Publickey is used it includes the file path to the
+# is allowed. If the PublicKey is used it includes the file path to the
# public key file. If none of them is provided then authentication is not
# required.
#
User = "priikone";
Nick = "pekka";
Passphrase = "verysecret";
- # Publickey = "/path/to/the/public.key";
+ # PublicKey = "/path/to/the/public.key";
};
#
# Thus, if this server is not router do not configure this section. If
# your server is router, this must be configured.
#
-# The authentication data is specified by Passphrase and/or Publickey.
+# The authentication data is specified by Passphrase and/or PublicKey.
# If both are provided then both password and public key based authentication
-# is allowed. If the Publickey is used it includes the file path to the
+# is allowed. If the PublicKey is used it includes the file path to the
# public key file. If none of them is provided then authentication is not
# required.
#
ServerConnection {
Host = "10.2.1.7";
Passphrase = "verysecret";
- #Publickey = "/path/to/the/public.key";
+ #PublicKey = "/path/to/the/public.key";
Params = "normal";
Backup = false;
};
# this section includes all configured router connections. The first
# configured connection is the primary route.
#
-# The authentication data is specified by Passphrase and/or Publickey.
+# The authentication data is specified by Passphrase and/or PublicKey.
# If both are provided then both password and public key based authentication
-# is allowed. If the Publickey is used it includes the file path to the
+# is allowed. If the PublicKey is used it includes the file path to the
# public key file. If none of them is provided then authentication is not
# required.
#
Host = "10.2.1.100";
Port = 706;
Passphrase = "verysecret";
- #Publickey = "/path/to/the/public.key";
+ #PublicKey = "/path/to/the/public.key";
Params = "normal";
Initiator = true;
#BackupHost = "10.2.1.6";
return h;
}
+/* Hashed SILC Public key. */
+
+SilcUInt32 silc_hash_public_key(void *key, void *user_context)
+{
+ SilcPublicKey pk = (SilcPublicKey)key;
+ return (pk->len + silc_hash_string(pk->name, NULL) +
+ silc_hash_string(pk->identifier, NULL) +
+ silc_hash_data(pk->pk, (void *)pk->pk_len));
+}
+
/* Compares two strings. May be used as SilcHashTable comparison function. */
bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
return !memcmp(key1, key2, len);
}
+/* Compares two SILC Public keys. May be used as SilcHashTable comparison
+ function. */
+
+bool silc_hash_public_key_compare(void *key1, void *key2, void *user_context)
+{
+ return silc_pkcs_public_key_compare(key1, key2);
+}
+
/* Parses mode mask and returns the mode as string. */
char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
SilcUInt32 silc_hash_ptr(void *key, void *user_context);
SilcUInt32 silc_hash_id(void *key, void *user_context);
SilcUInt32 silc_hash_data(void *key, void *user_context);
+SilcUInt32 silc_hash_public_key(void *key, void *user_context);
bool silc_hash_string_compare(void *key1, void *key2, void *user_context);
bool silc_hash_id_compare(void *key1, void *key2, void *user_context);
bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context);
bool silc_hash_data_compare(void *key1, void *key2, void *user_context);
-char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac);
+bool silc_hash_public_key_compare(void *key1, void *key2, void *user_context);
+char *silc_client_chmode(SilcUInt32 mode, const char *cipher,
+ const char *hmac);
char *silc_client_chumode(SilcUInt32 mode);
char *silc_client_chumode_char(SilcUInt32 mode);
int silc_gettimeofday(struct timeval *p);