From: Pekka Riikonen Date: Tue, 12 Mar 2002 17:31:30 +0000 (+0000) Subject: Added support for multiple PublicKey instances in the config X-Git-Tag: silc.toolkit.0.8.1~32 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=c077f32b9139acbbd3f33d1a3c6293b5788337e6 Added support for multiple PublicKey instances in the config file. --- diff --git a/CHANGES b/CHANGES index f3d99036..82b8c68d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,24 @@ +Tue Mar 12 17:58:59 EET 2002 Pekka Riikonen + + * 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 * Merged Irssi 0.8.2 from irssi.org CVS. diff --git a/TODO b/TODO index d32f8bf1..322e71f0 100644 --- a/TODO +++ b/TODO @@ -37,10 +37,6 @@ TODO/bugs In SILC Server 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. diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 02ec6d1d..baddfb18 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -4583,6 +4583,7 @@ SILC_SERVER_CMD_FUNC(oper) SilcServerConfigAdmin *admin; SilcIDListData idata = (SilcIDListData)client; bool result = FALSE; + SilcPublicKey cached_key; SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2); @@ -4624,10 +4625,14 @@ SILC_SERVER_CMD_FUNC(oper) 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, @@ -4670,6 +4675,7 @@ SILC_SERVER_CMD_FUNC(silcoper) SilcServerConfigAdmin *admin; SilcIDListData idata = (SilcIDListData)client; bool result = FALSE; + SilcPublicKey cached_key; SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2); @@ -4717,10 +4723,14 @@ SILC_SERVER_CMD_FUNC(silcoper) 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, diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 1c817358..1bc8b853 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -2535,11 +2535,11 @@ void silc_server_connection_auth_request(SilcServer server, 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; } diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c index a33184d7..2200bfb8 100644 --- a/apps/silcd/protocol.c +++ b/apps/silcd/protocol.c @@ -407,9 +407,7 @@ static void silc_server_protocol_ke_continue(SilcSKE ske, void *context) 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; @@ -495,8 +493,6 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) 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); @@ -532,8 +528,6 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) 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); @@ -575,8 +569,6 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) 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); @@ -613,8 +605,6 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) 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); @@ -827,7 +817,7 @@ silc_server_get_public_key_auth(SilcServer server, 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) { @@ -837,7 +827,8 @@ silc_server_get_authentication(SilcServerConnAuthInternalContext *ctx, /* 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; } @@ -854,13 +845,22 @@ silc_server_get_authentication(SilcServerConnAuthInternalContext *ctx, } /* 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; @@ -963,19 +963,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) 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); @@ -992,19 +990,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) 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; @@ -1021,19 +1017,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) 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); diff --git a/apps/silcd/server.c b/apps/silcd/server.c index b9a09d99..1f468f1d 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -765,20 +765,18 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) 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; diff --git a/apps/silcd/server_internal.h b/apps/silcd/server_internal.h index d35c5d8a..b0d38cb1 100644 --- a/apps/silcd/server_internal.h +++ b/apps/silcd/server_internal.h @@ -179,7 +179,7 @@ do { \ 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; \ } diff --git a/apps/silcd/server_util.c b/apps/silcd/server_util.c index 4425e64d..dc76c481 100644 --- a/apps/silcd/server_util.c +++ b/apps/silcd/server_util.c @@ -46,7 +46,7 @@ static void silc_server_remove_clients_channels(SilcServer server, /* 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 */ @@ -101,7 +101,7 @@ static void silc_server_remove_clients_channels(SilcServer server, 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--; @@ -343,7 +343,7 @@ bool silc_server_remove_clients_by_server(SilcServer server, 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); @@ -706,7 +706,7 @@ bool silc_server_channel_has_global(SilcChannelEntry channel) 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; @@ -726,7 +726,7 @@ bool silc_server_channel_has_local(SilcChannelEntry channel) 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; @@ -806,3 +806,53 @@ SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip, 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; +} diff --git a/apps/silcd/server_util.h b/apps/silcd/server_util.h index 83cd26bd..ca54b1b8 100644 --- a/apps/silcd/server_util.h +++ b/apps/silcd/server_util.h @@ -86,4 +86,19 @@ char *silc_server_name_modify_bad(const char *name, SilcUInt32 name_len); 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 */ diff --git a/apps/silcd/serverconfig.c b/apps/silcd/serverconfig.c index e0f02915..0a0bfe55 100644 --- a/apps/silcd/serverconfig.c +++ b/apps/silcd/serverconfig.c @@ -59,9 +59,15 @@ /* 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 @@ -106,8 +112,9 @@ my_find_param(SilcServerConfig config, const char *name, SilcUInt32 line) } /* 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 */ @@ -116,7 +123,7 @@ static bool my_parse_authdata(SilcAuthMethod auth_meth, char *p, SilcUInt32 line 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)) @@ -125,10 +132,16 @@ static bool my_parse_authdata(SilcAuthMethod auth_meth, char *p, SilcUInt32 line "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); @@ -651,6 +664,7 @@ SILC_CONFIG_CALLBACK(fetch_client) 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)) { @@ -660,7 +674,7 @@ SILC_CONFIG_CALLBACK(fetch_client) } 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; } @@ -722,6 +736,7 @@ SILC_CONFIG_CALLBACK(fetch_admin) 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)) { @@ -730,8 +745,9 @@ SILC_CONFIG_CALLBACK(fetch_admin) } } 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; } @@ -825,6 +841,7 @@ SILC_CONFIG_CALLBACK(fetch_server) 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)) { @@ -833,8 +850,9 @@ SILC_CONFIG_CALLBACK(fetch_server) } } 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; } @@ -905,6 +923,7 @@ SILC_CONFIG_CALLBACK(fetch_router) 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)) { @@ -913,8 +932,9 @@ SILC_CONFIG_CALLBACK(fetch_router) } } 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; } diff --git a/apps/silcd/serverconfig.h b/apps/silcd/serverconfig.h index c4190e36..2af85bbd 100644 --- a/apps/silcd/serverconfig.h +++ b/apps/silcd/serverconfig.h @@ -90,7 +90,7 @@ typedef struct SilcServerConfigClientStruct { char *host; unsigned char *passphrase; SilcUInt32 passphrase_len; - void *publickey; + SilcHashTable publickeys; SilcServerConfigConnParams *param; struct SilcServerConfigClientStruct *next; } SilcServerConfigClient; @@ -102,7 +102,7 @@ typedef struct SilcServerConfigAdminStruct { char *nick; unsigned char *passphrase; SilcUInt32 passphrase_len; - void *publickey; + SilcHashTable publickeys; struct SilcServerConfigAdminStruct *next; } SilcServerConfigAdmin; @@ -118,7 +118,7 @@ typedef struct SilcServerConfigServerStruct { char *host; unsigned char *passphrase; SilcUInt32 passphrase_len; - void *publickey; + SilcHashTable publickeys; char *version; SilcServerConfigConnParams *param; bool backup_router; @@ -130,7 +130,7 @@ typedef struct SilcServerConfigRouterStruct { char *host; unsigned char *passphrase; SilcUInt32 passphrase_len; - void *publickey; + SilcHashTable publickeys; SilcUInt16 port; char *version; SilcServerConfigConnParams *param; diff --git a/doc/example_silcd.conf.in b/doc/example_silcd.conf.in index 5bac8bcc..2612c219 100644 --- a/doc/example_silcd.conf.in +++ b/doc/example_silcd.conf.in @@ -298,11 +298,12 @@ ConnectionParams { # "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. @@ -310,7 +311,9 @@ ConnectionParams { 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"; }; @@ -320,9 +323,9 @@ Client { # 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. # @@ -331,7 +334,7 @@ Admin { User = "priikone"; Nick = "pekka"; Passphrase = "verysecret"; - # Publickey = "/path/to/the/public.key"; + # PublicKey = "/path/to/the/public.key"; }; # @@ -342,9 +345,9 @@ Admin { # 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. # @@ -355,7 +358,7 @@ Admin { ServerConnection { Host = "10.2.1.7"; Passphrase = "verysecret"; - #Publickey = "/path/to/the/public.key"; + #PublicKey = "/path/to/the/public.key"; Params = "normal"; Backup = false; }; @@ -368,9 +371,9 @@ ServerConnection { # 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. # @@ -389,7 +392,7 @@ RouterConnection { 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"; diff --git a/lib/silcutil/silcutil.c b/lib/silcutil/silcutil.c index c3af5925..ee7f2eea 100644 --- a/lib/silcutil/silcutil.c +++ b/lib/silcutil/silcutil.c @@ -654,6 +654,16 @@ SilcUInt32 silc_hash_data(void *key, void *user_context) 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) @@ -688,6 +698,14 @@ bool silc_hash_data_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) diff --git a/lib/silcutil/silcutil.h b/lib/silcutil/silcutil.h index ca34315a..2f79f260 100644 --- a/lib/silcutil/silcutil.h +++ b/lib/silcutil/silcutil.h @@ -49,11 +49,14 @@ SilcUInt32 silc_hash_uint(void *key, void *user_context); 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);