From: Pekka Riikonen Date: Fri, 16 Mar 2001 15:51:06 +0000 (+0000) Subject: updates. X-Git-Tag: 1.2.beta1~2439 X-Git-Url: http://git.silcnet.org/gitweb/?p=runtime.git;a=commitdiff_plain;h=f9b6b6d91114fc1249b53ad4a77b3f1e974d8eef updates. --- diff --git a/CHANGES b/CHANGES index 7676dd2c..84f84aba 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,35 @@ +Fri Mar 16 15:52:49 EET 2001 Pekka Riikonen + + * Implemented OPER and SILCOPER commands into the server and + the client library. + + * Added silc_auth_verify and silc_auth_verify_data to verify + the authentication directly from the authentication payload. + It supports verifying both passphrase and public key based + authentication. Affected file lib/silccore/silcauth.[ch]. + + * Added `hash' field to the SilcIDListData structure. It is the + hash negotiated in the SKE protocol. Affected file is + silcd/idlist.[ch]. + + * Slight redesigning of the SilcAuthPayload handling routines. + Do not send SilcPKCS but SilcPublicKey as argument. + + * Implemented the public key authentication support to the + serverconfig. The public key is loaded fromthe provided path + and saved as authentication data to void * pointer. Thus, + changed the unsigned char *auth_data to void *auth_data; + + * Fixed SHUTDOWN command to send the reply before the server + is shutdown. :) Affected file silcd/command.c. + + * Fixed fatal bug in CONNECT command. The hostname was invalid + memory and server crashed. Affected file silcd/command.c. + + * Fixed fatal bug in CLOSE command. The server_entry became + invalid but was referenced later in the command. Affected file + silcd/command.c. + Thu Mar 15 12:46:58 EET 2001 Pekka Riikonen * Fixed fatal bug in failure packet handling. Server ignored diff --git a/README b/README index b630091b..191ebd1e 100644 --- a/README +++ b/README @@ -170,13 +170,21 @@ Following commands has been, at least partly, implemented: Shows client version. + /OPER [] + + Obtains server operator privileges. + + /SILCOPER [] + + Obtains router operator privileges. + /CONNECT [] Connects to server the remote . You must be server operator to be able to do this. - /CLOSE [] + /CLOSE [] Closes connection to the . You must be server operator to be able to do this. diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 0395e40d..ef844c0a 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -3307,12 +3307,138 @@ SILC_SERVER_CMD_FUNC(kick) silc_server_command_free(cmd); } +/* Server side of OPER command. Client uses this comand to obtain server + operator privileges to this server/router. */ + SILC_SERVER_CMD_FUNC(oper) { + SilcServerCommandContext cmd = (SilcServerCommandContext)context; + SilcServer server = cmd->server; + SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; + unsigned char *username, *auth; + unsigned int tmp_len; + SilcServerConfigSectionAdminConnection *admin; + SilcIDListData idata = (SilcIDListData)client; + + SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_OPER, cmd, 1, 2); + + if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) + goto out; + + /* Get the username */ + username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len); + if (!username) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + + /* Get the admin configuration */ + admin = silc_server_config_find_admin(server->config, cmd->sock->ip, + username, client->nickname); + if (!admin) { + admin = silc_server_config_find_admin(server->config, cmd->sock->hostname, + username, client->nickname); + if (!admin) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER, + SILC_STATUS_ERR_AUTH_FAILED); + goto out; + } + } + + /* Get the authentication payload */ + auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); + if (!auth) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + + /* Verify the authentication data */ + if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth, + admin->auth_data, admin->auth_data_len, + idata->hash, client->id, SILC_ID_CLIENT)) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER, + SILC_STATUS_ERR_AUTH_FAILED); + goto out; + } + + /* Client is now server operator */ + client->mode |= SILC_UMODE_SERVER_OPERATOR; + + /* Send reply to the sender */ + silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER, + SILC_STATUS_OK); + + out: + silc_server_command_free(cmd); } +/* Server side of SILCOPER command. Client uses this comand to obtain router + operator privileges to this router. */ + SILC_SERVER_CMD_FUNC(silcoper) { + SilcServerCommandContext cmd = (SilcServerCommandContext)context; + SilcServer server = cmd->server; + SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; + unsigned char *username, *auth; + unsigned int tmp_len; + SilcServerConfigSectionAdminConnection *admin; + SilcIDListData idata = (SilcIDListData)client; + + SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SILCOPER, cmd, 1, 2); + + if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) + goto out; + + /* Get the username */ + username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len); + if (!username) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + + /* Get the admin configuration */ + admin = silc_server_config_find_admin(server->config, cmd->sock->ip, + username, client->nickname); + if (!admin) { + admin = silc_server_config_find_admin(server->config, cmd->sock->hostname, + username, client->nickname); + if (!admin) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER, + SILC_STATUS_ERR_AUTH_FAILED); + goto out; + } + } + + /* Get the authentication payload */ + auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); + if (!auth) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + + /* Verify the authentication data */ + if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth, + admin->auth_data, admin->auth_data_len, + idata->hash, client->id, SILC_ID_CLIENT)) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER, + SILC_STATUS_ERR_AUTH_FAILED); + goto out; + } + + /* Client is now router operator */ + client->mode |= SILC_UMODE_ROUTER_OPERATOR; + + /* Send reply to the sender */ + silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER, + SILC_STATUS_OK); + + out: + silc_server_command_free(cmd); } /* Server side command of CONNECT. Connects us to the specified remote @@ -3323,7 +3449,7 @@ SILC_SERVER_CMD_FUNC(connect) SilcServerCommandContext cmd = (SilcServerCommandContext)context; SilcServer server = cmd->server; SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; - unsigned char *tmp; + unsigned char *tmp, *host; unsigned int tmp_len; unsigned int port = SILC_PORT; @@ -3347,8 +3473,8 @@ SILC_SERVER_CMD_FUNC(connect) } /* Get the remote server */ - tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len); - if (!tmp) { + host = silc_argument_get_arg_type(cmd->args, 1, &tmp_len); + if (!host) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT, SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; @@ -3360,7 +3486,7 @@ SILC_SERVER_CMD_FUNC(connect) SILC_GET32_MSB(port, tmp); /* Create the connection. It is done with timeout and is async. */ - silc_server_create_connection(server, tmp, port); + silc_server_create_connection(server, host, port); /* Send reply to the sender */ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT, @@ -3382,6 +3508,7 @@ SILC_SERVER_CMD_FUNC(close) SilcServer server = cmd->server; SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; SilcServerEntry server_entry; + SilcSocketConnection sock; unsigned char *tmp; unsigned int tmp_len; unsigned char *name; @@ -3420,16 +3547,15 @@ SILC_SERVER_CMD_FUNC(close) goto out; } - /* Close the connection to the server */ - silc_server_free_sock_user_data(server, server_entry->connection); - silc_server_disconnect_remote(server, server_entry->connection, - "Server closed connection: " - "Closed by operator"); - /* Send reply to the sender */ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE, SILC_STATUS_OK); + /* Close the connection to the server */ + sock = (SilcSocketConnection)server_entry->connection; + silc_server_free_sock_user_data(server, sock); + silc_server_close_connection(server, sock); + out: silc_server_command_free(cmd); } @@ -3455,13 +3581,14 @@ SILC_SERVER_CMD_FUNC(shutdown) goto out; } - /* Then, gracefully, or not, bring the server down. */ - silc_server_stop(server); - /* Send reply to the sender */ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN, SILC_STATUS_OK); + /* Then, gracefully, or not, bring the server down. */ + silc_server_stop(server); + exit(0); + out: silc_server_command_free(cmd); } diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index 86b60317..aca1c281 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -36,6 +36,7 @@ void silc_idlist_add_data(void *entry, SilcIDListData idata) SilcIDListData data = (SilcIDListData)entry; data->send_key = idata->send_key; data->receive_key = idata->receive_key; + data->hash = idata->hash; data->hmac = idata->hmac; data->hmac_key = idata->hmac_key; data->hmac_key_len = idata->hmac_key_len; @@ -179,8 +180,9 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname, server = (SilcServerEntry)id_cache->context; sock = (SilcSocketConnection)server->connection; - if (sock && (!strcmp(sock->hostname, hostname) || - !strcmp(sock->ip, hostname)) && sock->port == port) + if (sock && ((sock->hostname && !strcmp(sock->hostname, hostname)) || + (sock->ip && !strcmp(sock->ip, hostname))) + && sock->port == port) break; id_cache = NULL; diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h index 9d29d74f..bcd3c3f1 100644 --- a/apps/silcd/idlist.h +++ b/apps/silcd/idlist.h @@ -44,6 +44,9 @@ typedef struct { SilcCipher send_key; SilcCipher receive_key; + /* Hash selected in the SKE protocol, NULL if not needed at all */ + SilcHash hash; + /* HMAC and raw key data */ SilcHmac hmac; unsigned char *hmac_key; diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c index ca091612..1c033557 100644 --- a/apps/silcd/protocol.c +++ b/apps/silcd/protocol.c @@ -113,10 +113,19 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske, ske->ke2_payload->pk_len); #endif + /* Save the hash */ + if (!silc_hash_alloc(hash->hash->name, &idata->hash)) { + silc_cipher_free(idata->send_key); + silc_cipher_free(idata->receive_key); + silc_free(conn_data); + return FALSE; + } + /* Save HMAC key to be used in the communication. */ if (!silc_hmac_alloc(hmac->hmac->name, NULL, &idata->hmac)) { silc_cipher_free(idata->send_key); silc_cipher_free(idata->receive_key); + silc_hash_free(idata->hash); silc_free(conn_data); return FALSE; } diff --git a/apps/silcd/serverconfig.c b/apps/silcd/serverconfig.c index cc51b89b..d1c0ad37 100644 --- a/apps/silcd/serverconfig.c +++ b/apps/silcd/serverconfig.c @@ -682,12 +682,30 @@ int silc_server_config_parse_lines(SilcServerConfig config, } /* Get authentication data */ - ret = silc_config_get_token(line, &config->clients->auth_data); + ret = silc_config_get_token(line, (char **)&config->clients->auth_data); if (ret < 0) break; - if (ret == 0) - /* Any host */ - config->clients->host = strdup("*"); + + if (config->clients->auth_meth == SILC_AUTH_PASSWORD) { + config->clients->auth_data_len = strlen(config->clients->auth_data); + } else if (config->clients->auth_meth == SILC_AUTH_PUBLIC_KEY) { + /* Get the public key */ + SilcPublicKey public_key; + + if (!silc_pkcs_load_public_key(config->clients->auth_data, + &public_key, SILC_PKCS_FILE_PEM)) + if (!silc_pkcs_load_public_key(config->clients->auth_data, + &public_key, SILC_PKCS_FILE_BIN)) { + fprintf(stderr, "%s:%d: Could not load public key file `%s'\n", + config->filename, pc->linenum, + (char *)config->clients->auth_data); + break; + } + + silc_free(config->clients->auth_data); + config->clients->auth_data = (void *)public_key; + config->clients->auth_data_len = 0; + } /* Get port */ ret = silc_config_get_token(line, &tmp); @@ -745,10 +763,31 @@ int silc_server_config_parse_lines(SilcServerConfig config, } /* Get authentication data */ - ret = silc_config_get_token(line, &config->servers->auth_data); + ret = silc_config_get_token(line, (char **)&config->servers->auth_data); if (ret < 0) break; + if (config->servers->auth_meth == SILC_AUTH_PASSWORD) { + config->servers->auth_data_len = strlen(config->servers->auth_data); + } else if (config->servers->auth_meth == SILC_AUTH_PUBLIC_KEY) { + /* Get the public key */ + SilcPublicKey public_key; + + if (!silc_pkcs_load_public_key(config->servers->auth_data, + &public_key, SILC_PKCS_FILE_PEM)) + if (!silc_pkcs_load_public_key(config->servers->auth_data, + &public_key, SILC_PKCS_FILE_BIN)) { + fprintf(stderr, "%s:%d: Could not load public key file `%s'\n", + config->filename, pc->linenum, + (char *)config->servers->auth_data); + break; + } + + silc_free(config->servers->auth_data); + config->servers->auth_data = (void *)public_key; + config->servers->auth_data_len = 0; + } + /* Get port */ ret = silc_config_get_token(line, &tmp); if (ret < 0) @@ -810,10 +849,31 @@ int silc_server_config_parse_lines(SilcServerConfig config, } /* Get authentication data */ - ret = silc_config_get_token(line, &config->routers->auth_data); + ret = silc_config_get_token(line, (char **)&config->routers->auth_data); if (ret < 0) break; + if (config->routers->auth_meth == SILC_AUTH_PASSWORD) { + config->routers->auth_data_len = strlen(config->routers->auth_data); + } else if (config->routers->auth_meth == SILC_AUTH_PUBLIC_KEY) { + /* Get the public key */ + SilcPublicKey public_key; + + if (!silc_pkcs_load_public_key(config->routers->auth_data, + &public_key, SILC_PKCS_FILE_PEM)) + if (!silc_pkcs_load_public_key(config->routers->auth_data, + &public_key, SILC_PKCS_FILE_BIN)) { + fprintf(stderr, "%s:%d: Could not load public key file `%s'\n", + config->filename, pc->linenum, + (char *)config->routers->auth_data); + break; + } + + silc_free(config->routers->auth_data); + config->routers->auth_data = (void *)public_key; + config->routers->auth_data_len = 0; + } + /* Get port */ ret = silc_config_get_token(line, &tmp); if (ret < 0) @@ -902,10 +962,31 @@ int silc_server_config_parse_lines(SilcServerConfig config, } /* Get authentication data */ - ret = silc_config_get_token(line, &config->admins->auth_data); + ret = silc_config_get_token(line, (char **)&config->admins->auth_data); if (ret < 0) break; + if (config->admins->auth_meth == SILC_AUTH_PASSWORD) { + config->admins->auth_data_len = strlen(config->admins->auth_data); + } else if (config->admins->auth_meth == SILC_AUTH_PUBLIC_KEY) { + /* Get the public key */ + SilcPublicKey public_key; + + if (!silc_pkcs_load_public_key(config->admins->auth_data, + &public_key, SILC_PKCS_FILE_PEM)) + if (!silc_pkcs_load_public_key(config->admins->auth_data, + &public_key, SILC_PKCS_FILE_BIN)) { + fprintf(stderr, "%s:%d: Could not load public key file `%s'\n", + config->filename, pc->linenum, + (char *)config->admins->auth_data); + break; + } + + silc_free(config->admins->auth_data); + config->admins->auth_data = (void *)public_key; + config->admins->auth_data_len = 0; + } + check = TRUE; checkmask |= (1L << pc->section->type); break; @@ -1403,7 +1484,7 @@ silc_server_config_find_admin(SilcServerConfig config, host = "*"; if (!username) username = "*"; - if (nickname) + if (!nickname) nickname = "*"; admin = config->admins; diff --git a/apps/silcd/serverconfig.h b/apps/silcd/serverconfig.h index 3e911eac..77644e4f 100644 --- a/apps/silcd/serverconfig.h +++ b/apps/silcd/serverconfig.h @@ -95,8 +95,9 @@ typedef struct SilcServerConfigSectionConnectionClassStruct { /* Holds all client authentication data from config file */ typedef struct SilcServerConfigSectionClientConnectionStruct { char *host; - int auth_meth; - char *auth_data; + SilcAuthMethod auth_meth; + void *auth_data; + unsigned int auth_data_len; unsigned short port; unsigned int class; struct SilcServerConfigSectionClientConnectionStruct *next; @@ -108,8 +109,9 @@ typedef struct SilcServerConfigSectionAdminConnectionStruct { char *host; char *username; char *nickname; - int auth_meth; - char *auth_data; + SilcAuthMethod auth_meth; + void *auth_data; + unsigned int auth_data_len; struct SilcServerConfigSectionAdminConnectionStruct *next; struct SilcServerConfigSectionAdminConnectionStruct *prev; } SilcServerConfigSectionAdminConnection; @@ -117,8 +119,9 @@ typedef struct SilcServerConfigSectionAdminConnectionStruct { /* Holds all configured server/router connections from config file */ typedef struct SilcServerConfigSectionServerConnectionStruct { char *host; - int auth_meth; - char *auth_data; + SilcAuthMethod auth_meth; + void *auth_data; + unsigned int auth_data_len; unsigned short port; char *version; unsigned int class; diff --git a/doc/draft-riikonen-silc-spec-01.nroff b/doc/draft-riikonen-silc-spec-01.nroff index fa590917..79e6fafd 100644 --- a/doc/draft-riikonen-silc-spec-01.nroff +++ b/doc/draft-riikonen-silc-spec-01.nroff @@ -2354,7 +2354,7 @@ List of all defined commands in SILC follows. 13 SILC_COMMAND_OPER Max Arguments: 2 - Arguments: (1) (2) + Arguments: (1) (2) This command is used by normal client to obtain server operator privileges on some server or router. Note that router operator @@ -2363,11 +2363,10 @@ List of all defined commands in SILC follows. must use SILCOPER command to obtain router level privileges. The is the username set in the server configurations - as operator. The is the data that the + as operator. The is the data that the client is authenticated against. It may be passphrase prompted - for user on client's screen or it may be public key - authentication data (data signed with private key), or - certificate. + for user on client's screen or it may be public key or certificate + authentication data (data signed with private key). Reply messages to the command: @@ -2382,7 +2381,6 @@ List of all defined commands in SILC follows. SILC_STATUS_ERR_NOT_ENOUGH_PARAMS SILC_STATUS_ERR_TOO_MANY_PARAMS SILC_STATUS_ERR_NOT_REGISTERED - SILC_STATUS_ERR_BAD_PASSWORD SILC_STATUS_ERR_AUTH_FAILED @@ -2961,7 +2959,7 @@ List of all defined commands in SILC follows. 23 SILC_COMMAND_SILCOPER Max Arguments: 2 - Arguments: (1) (2) + Arguments: (1) (2) This command is used by normal client to obtain router operator privileges (also known as SILC operator) on some router. Note @@ -2969,7 +2967,7 @@ List of all defined commands in SILC follows. server operator privileges. The is the username set in the server configurations - as operator. The is the data that the + as operator. The is the data that the client is authenticated against. It may be passphrase prompted for user on client's screen or it may be public key authentication data (data signed with private key), or @@ -2994,7 +2992,6 @@ List of all defined commands in SILC follows. SILC_STATUS_ERR_NOT_ENOUGH_PARAMS SILC_STATUS_ERR_TOO_MANY_PARAMS SILC_STATUS_ERR_NOT_REGISTERED - SILC_STATUS_ERR_BAD_PASSWORD SILC_STATUS_ERR_AUTH_FAILED diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index e01a9b19..4b3214b4 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -35,7 +35,7 @@ SilcClientCommand silc_command_list[] = SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3), SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 2), SILC_CLIENT_CMD(kill, KILL, "KILL", - SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2), + SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3), SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2), SILC_CLIENT_CMD(connect, CONNECT, "CONNECT", SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3), @@ -51,11 +51,11 @@ SilcClientCommand silc_command_list[] = SILC_CLIENT_CMD(restart, RESTART, "RESTART", SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2), SILC_CLIENT_CMD(close, CLOSE, "CLOSE", - SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2), + SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3), SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN", SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 1), SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER", - SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2), + SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3), SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2), SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2), @@ -1264,12 +1264,126 @@ SILC_CLIENT_CMD_FUNC(kick) silc_client_command_free(cmd); } -SILC_CLIENT_CMD_FUNC(silcoper) +/* OPER command. Used to obtain server operator privileges. */ + +SILC_CLIENT_CMD_FUNC(oper) { + SilcClientCommandContext cmd = (SilcClientCommandContext)context; + SilcClientConnection conn = cmd->conn; + SilcBuffer buffer; + unsigned char *auth_data; + SilcBuffer auth; + + if (!cmd->conn) { + SILC_NOT_CONNECTED(cmd->client, cmd->conn); + COMMAND_ERROR; + goto out; + } + + if (cmd->argc < 2) { + cmd->client->ops->say(cmd->client, conn, + "Usage: /OPER []"); + COMMAND_ERROR; + goto out; + } + + if (cmd->argc == 3) { + /* XXX Get public key */ + auth_data = NULL; + COMMAND_ERROR; + goto out; + } else { + /* Get passphrase */ + + auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn); + if (!auth_data) { + COMMAND_ERROR; + goto out; + } + + /* Encode the authentication payload */ + auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0, + auth_data, strlen(auth_data)); + } + + buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2, + 1, cmd->argv[1], + strlen(cmd->argv[1]), + 2, auth->data, auth->len); + 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(auth); + memset(auth_data, 0, strlen(auth_data)); + silc_free(auth_data); + + /* Notify application */ + COMMAND; + + out: + silc_client_command_free(cmd); } -SILC_CLIENT_CMD_FUNC(oper) +/* SILCOPER command. Used to obtain router operator privileges. */ + +SILC_CLIENT_CMD_FUNC(silcoper) { + SilcClientCommandContext cmd = (SilcClientCommandContext)context; + SilcClientConnection conn = cmd->conn; + SilcBuffer buffer; + unsigned char *auth_data; + SilcBuffer auth; + + if (!cmd->conn) { + SILC_NOT_CONNECTED(cmd->client, cmd->conn); + COMMAND_ERROR; + goto out; + } + + if (cmd->argc < 2) { + cmd->client->ops->say(cmd->client, conn, + "Usage: /SILCOPER []"); + COMMAND_ERROR; + goto out; + } + + if (cmd->argc == 3) { + /* XXX Get public key */ + auth_data = NULL; + COMMAND_ERROR; + goto out; + } else { + /* Get passphrase */ + + auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn); + if (!auth_data) { + COMMAND_ERROR; + goto out; + } + + /* Encode the authentication payload */ + auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0, + auth_data, strlen(auth_data)); + } + + buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2, + 1, cmd->argv[1], + strlen(cmd->argv[1]), + 2, auth->data, auth->len); + 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(auth); + memset(auth_data, 0, strlen(auth_data)); + silc_free(auth_data); + + /* Notify application */ + COMMAND; + + out: + silc_client_command_free(cmd); } /* CONNECT command. Connects the server to another server. */ diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index e21a3f52..a9833571 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -1160,10 +1160,56 @@ SILC_CLIENT_CMD_REPLY_FUNC(kick) SILC_CLIENT_CMD_REPLY_FUNC(silcoper) { + SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; + SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; + SilcCommandStatus status; + unsigned char *tmp; + + tmp = silc_argument_get_arg_type(cmd->args, 1, NULL); + SILC_GET16_MSB(status, tmp); + if (status != SILC_STATUS_OK) { + cmd->client->ops->say(cmd->client, conn, + "%s", silc_client_command_status_message(status)); + COMMAND_REPLY_ERROR; + goto out; + } + + /* Notify application */ + COMMAND_REPLY((ARGS)); + + /* Execute any pending command callbacks */ + SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER); + + out: + SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER); + silc_client_command_reply_free(cmd); } SILC_CLIENT_CMD_REPLY_FUNC(oper) { + SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; + SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; + SilcCommandStatus status; + unsigned char *tmp; + + tmp = silc_argument_get_arg_type(cmd->args, 1, NULL); + SILC_GET16_MSB(status, tmp); + if (status != SILC_STATUS_OK) { + cmd->client->ops->say(cmd->client, conn, + "%s", silc_client_command_status_message(status)); + COMMAND_REPLY_ERROR; + goto out; + } + + /* Notify application */ + COMMAND_REPLY((ARGS)); + + /* Execute any pending command callbacks */ + SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER); + + out: + SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER); + silc_client_command_reply_free(cmd); } SILC_CLIENT_CMD_REPLY_FUNC(connect) diff --git a/lib/silccore/silcauth.c b/lib/silccore/silcauth.c index 15305860..a7a43c41 100644 --- a/lib/silccore/silcauth.c +++ b/lib/silccore/silcauth.c @@ -132,7 +132,8 @@ void silc_auth_payload_free(SilcAuthPayload payload) dictates. */ static unsigned char * -silc_auth_public_key_encode_data(SilcPKCS pkcs, unsigned char *random, +silc_auth_public_key_encode_data(SilcPublicKey public_key, + unsigned char *random, unsigned int random_len, void *id, SilcIdType type, unsigned int *ret_len) { @@ -140,7 +141,7 @@ silc_auth_public_key_encode_data(SilcPKCS pkcs, unsigned char *random, unsigned char *pk, *id_data, *ret; unsigned int pk_len, id_len; - pk = silc_pkcs_get_public_key(pkcs, &pk_len); + pk = silc_pkcs_public_key_encode(public_key, &pk_len); if (!pk) return NULL; @@ -176,7 +177,7 @@ silc_auth_public_key_encode_data(SilcPKCS pkcs, unsigned char *random, to do public key based authentication. This generates the random data and the actual authentication data. Returns NULL on error. */ -SilcBuffer silc_auth_public_key_auth_generate(SilcPKCS pkcs, +SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key, SilcHash hash, void *id, SilcIdType type) { @@ -186,6 +187,7 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPKCS pkcs, unsigned char *tmp; unsigned int tmp_len; SilcBuffer buf; + SilcPKCS pkcs; SILC_LOG_DEBUG(("Generating Authentication Payload with data")); @@ -195,11 +197,18 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPKCS pkcs, return NULL; /* Encode the auth data */ - tmp = silc_auth_public_key_encode_data(pkcs, random, 256, id, type, + tmp = silc_auth_public_key_encode_data(public_key, random, 256, id, type, &tmp_len); if (!tmp) return NULL; + /* Allocate PKCS object */ + if (!silc_pkcs_alloc(public_key->name, &pkcs)) { + memset(tmp, 0, tmp_len); + silc_free(tmp); + return NULL; + } + /* Compute the hash and the signature. */ if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data, &auth_len)) { @@ -207,6 +216,7 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPKCS pkcs, memset(tmp, 0, tmp_len); silc_free(tmp); silc_free(random); + silc_pkcs_free(pkcs); return NULL; } @@ -219,6 +229,7 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPKCS pkcs, memset(random, 0, 256); silc_free(tmp); silc_free(random); + silc_pkcs_free(pkcs); return buf; } @@ -227,16 +238,17 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPKCS pkcs, successfull. */ int silc_auth_public_key_auth_verify(SilcAuthPayload payload, - SilcPKCS pkcs, SilcHash hash, + SilcPublicKey public_key, SilcHash hash, void *id, SilcIdType type) { unsigned char *tmp; unsigned int tmp_len; + SilcPKCS pkcs; SILC_LOG_DEBUG(("Verifying authentication data")); /* Encode auth data */ - tmp = silc_auth_public_key_encode_data(pkcs, payload->random_data, + tmp = silc_auth_public_key_encode_data(public_key, payload->random_data, payload->random_len, id, type, &tmp_len); if (!tmp) { @@ -244,18 +256,27 @@ int silc_auth_public_key_auth_verify(SilcAuthPayload payload, return FALSE; } + /* Allocate PKCS object */ + if (!silc_pkcs_alloc(public_key->name, &pkcs)) { + memset(tmp, 0, tmp_len); + silc_free(tmp); + return FALSE; + } + /* Verify the authentication data */ if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data, payload->auth_len, tmp, tmp_len)) { memset(tmp, 0, tmp_len); silc_free(tmp); + silc_pkcs_free(pkcs); SILC_LOG_DEBUG(("Authentication failed")); return FALSE; } memset(tmp, 0, tmp_len); silc_free(tmp); + silc_pkcs_free(pkcs); SILC_LOG_DEBUG(("Authentication successfull")); @@ -265,7 +286,8 @@ int silc_auth_public_key_auth_verify(SilcAuthPayload payload, /* Same as above but the payload is not parsed yet. This will parse it. */ int silc_auth_public_key_auth_verify_data(SilcBuffer payload, - SilcPKCS pkcs, SilcHash hash, + SilcPublicKey public_key, + SilcHash hash, void *id, SilcIdType type) { SilcAuthPayload auth_payload; @@ -277,7 +299,7 @@ int silc_auth_public_key_auth_verify_data(SilcBuffer payload, return FALSE; } - ret = silc_auth_public_key_auth_verify(auth_payload, pkcs, hash, + ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash, id, type); silc_auth_payload_free(auth_payload); @@ -285,6 +307,81 @@ int silc_auth_public_key_auth_verify_data(SilcBuffer payload, return ret; } +/* Verifies the authentication data directly from the Authentication + Payload. Supports all authentication methods. If the authentication + method is passphrase based then the `auth_data' and `auth_data_len' + are the passphrase and its length. If the method is public key + authentication then the `auth_data' is the SilcPublicKey and the + `auth_data_len' is ignored. */ + +int silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method, + void *auth_data, unsigned int auth_data_len, + SilcHash hash, void *id, SilcIdType type) +{ + SILC_LOG_DEBUG(("Verifying authentication")); + + if (auth_method != payload->auth_method) + return FALSE; + + switch (payload->auth_method) { + case SILC_AUTH_NONE: + /* No authentication */ + SILC_LOG_DEBUG(("No authentication required")); + return TRUE; + + case SILC_AUTH_PASSWORD: + /* 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")); + return TRUE; + } + break; + + case SILC_AUTH_PUBLIC_KEY: + /* Public key based authentication */ + return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data, + hash, id, type); + break; + + default: + break; + } + + SILC_LOG_DEBUG(("Authentication failed")); + + return FALSE; +} + +/* Same as above but parses the authentication payload before verify. */ + +int silc_auth_verify_data(unsigned char *payload, unsigned int payload_len, + SilcAuthMethod auth_method, void *auth_data, + unsigned int auth_data_len, SilcHash hash, + 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); + 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; +} + /****************************************************************************** Key Agreement Payload diff --git a/lib/silccore/silcauth.h b/lib/silccore/silcauth.h index c691722c..1e55d264 100644 --- a/lib/silccore/silcauth.h +++ b/lib/silccore/silcauth.h @@ -48,15 +48,23 @@ SilcBuffer silc_auth_payload_encode(SilcAuthMethod method, unsigned char *auth_data, unsigned short auth_len); void silc_auth_payload_free(SilcAuthPayload payload); -SilcBuffer silc_auth_public_key_auth_generate(SilcPKCS pkcs, +SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key, SilcHash hash, void *id, SilcIdType type); int silc_auth_public_key_auth_verify(SilcAuthPayload payload, - SilcPKCS pkcs, SilcHash hash, + SilcPublicKey public_key, SilcHash hash, void *id, SilcIdType type); int silc_auth_public_key_auth_verify_data(SilcBuffer payload, - SilcPKCS pkcs, SilcHash hash, + SilcPublicKey public_key, + SilcHash hash, void *id, SilcIdType type); +int silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method, + void *auth_data, unsigned int auth_data_len, + SilcHash hash, void *id, SilcIdType type); +int silc_auth_verify_data(unsigned char *payload, unsigned int payload_len, + SilcAuthMethod auth_method, void *auth_data, + unsigned int auth_data_len, SilcHash hash, + void *id, SilcIdType type); SilcKeyAgreementPayload silc_key_agreement_payload_parse(SilcBuffer buffer); SilcBuffer silc_key_agreement_payload_encode(char *hostname, unsigned int port);