From: Pekka Riikonen Date: Sun, 8 Apr 2001 17:54:02 +0000 (+0000) Subject: updates. X-Git-Tag: SILC.0.1~44 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=ab7251f985a453b36972bb1286f3439847b844aa updates. --- diff --git a/CHANGES b/CHANGES index b7f8a672..816493ff 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -Sun Apr 8 15:30:56 EEST 2001 Pekka Riikonen +Sun Apr 8 19:30:56 EEST 2001 Pekka Riikonen * Made the key generation options to the silcd program. Added -C option, equivalent to client's option. @@ -6,6 +6,16 @@ Sun Apr 8 15:30:56 EEST 2001 Pekka Riikonen * Added new [ServerKeys] config section to the server. It configures the server's public and private key. + * Defined generic Public Key Payload into the protocol + specification to send specific type of public keys and + certificates. + + * Defined new command SILC_COMMAND_GETKEY to fetch a client's + public key or certificate. + + * Implemented the GETKEY command to the server and to the + client library and on user interface. + Sun Apr 8 01:37:21 EEST 2001 Pekka Riikonen * Made preliminary `make install' work. diff --git a/README b/README index da6a575d..ae1c812a 100644 --- a/README +++ b/README @@ -347,6 +347,10 @@ SILC Commands This command is used to send for example informational notice messages to the channel. + /GETKEY + + Fetches remote client's public key. + Features ======== diff --git a/TODO b/TODO index 8de20df2..a43ecfd5 100644 --- a/TODO +++ b/TODO @@ -74,21 +74,6 @@ TODO/bugs In SILC Libraries more (silcpkcs.h). -TODO in the protocol before SILC 0.x -==================================== - - o New commands and features in the commands - (draft-riikonen-silc-spec-xx.txt): - - o Define GETKEY command to fetch the public key of a server - and/or a client in the SILC Network. - o Define SENDKEY command to send your public key to a client - in the network. Sending to the server must not be done due - 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). - - TODO After 1.0 ============== diff --git a/apps/silc/client_ops.c b/apps/silc/client_ops.c index f7c3964c..66e88bda 100644 --- a/apps/silc/client_ops.c +++ b/apps/silc/client_ops.c @@ -893,6 +893,28 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn, } break; + case SILC_COMMAND_GETKEY: + { + SilcIdType id_type; + void *entry; + SilcPublicKey public_key; + unsigned char *pk; + uint32 pk_len; + + id_type = va_arg(vp, SilcIdType); + entry = va_arg(vp, void *); + public_key = va_arg(vp, SilcPublicKey); + + pk = silc_pkcs_public_key_encode(public_key, &pk_len); + + if (id_type == SILC_ID_CLIENT) { + silc_verify_public_key(client, conn, SILC_SOCKET_TYPE_CLIENT, + pk, pk_len, SILC_SKE_PK_TYPE_SILC); + } + + silc_free(pk); + } + default: break; } diff --git a/apps/silc/client_ops.h b/apps/silc/client_ops.h index 214aa01f..ebcd0e31 100644 --- a/apps/silc/client_ops.h +++ b/apps/silc/client_ops.h @@ -41,7 +41,9 @@ void silc_connect(SilcClient client, SilcClientConnection conn, int success); void silc_disconnect(SilcClient client, SilcClientConnection conn); unsigned char *silc_ask_passphrase(SilcClient client, SilcClientConnection conn); -int silc_verify_server_key(SilcClient client, SilcClientConnection conn, +int silc_verify_public_key(SilcClient client, + SilcClientConnection conn, + SilcSocketType conn_type, unsigned char *pk, uint32 pk_len, SilcSKEPKType pk_type); int silc_get_auth_method(SilcClient client, SilcClientConnection conn, diff --git a/apps/silc/local_command.c b/apps/silc/local_command.c index fae582a7..509b4fa2 100644 --- a/apps/silc/local_command.c +++ b/apps/silc/local_command.c @@ -90,7 +90,6 @@ SILC_CLIENT_LCMD_FUNC(version) private messages are not really commands, they are message packets, however, on user interface it is convenient to show them as commands as that is the common way of sending private messages (like in IRC). */ -/* XXX supports only one destination */ SILC_CLIENT_LCMD_FUNC(msg) { diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 47462e69..e7e0a082 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -71,6 +71,7 @@ SilcServerCommand silc_command_list[] = SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER), SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG), SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG), + SILC_SERVER_CMD(getkey, GETKEY, SILC_CF_LAG | SILC_CF_REG), { NULL, 0 }, }; @@ -4759,3 +4760,167 @@ SILC_SERVER_CMD_FUNC(users) out: silc_server_command_free(cmd); } + +/* Server side of command GETKEY. This fetches the client's public key + from the server where to the client is connected. */ + +SILC_SERVER_CMD_FUNC(getkey) +{ + SilcServerCommandContext cmd = (SilcServerCommandContext)context; + SilcServer server = cmd->server; + SilcBuffer packet; + SilcClientEntry client; + SilcServerEntry server_entry; + SilcClientID *client_id = NULL; + SilcServerID *server_id = NULL; + SilcIDPayload idp = NULL; + uint16 ident = silc_command_get_ident(cmd->payload); + unsigned char *tmp; + uint32 tmp_len; + SilcBuffer pk; + SilcIdType id_type; + + tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len); + if (!tmp) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + idp = silc_id_payload_parse_data(tmp, tmp_len); + if (!idp) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + + id_type = silc_id_payload_get_type(idp); + if (id_type == SILC_ID_CLIENT) { + client_id = silc_id_payload_get_id(idp); + + /* If the client is not found from local list there is no chance it + would be locally connected client so send the command further. */ + client = silc_idlist_find_client_by_id(server->local_list, + client_id, NULL); + + if ((!client && !cmd->pending && !server->standalone) || + (client && !client->connection)) { + SilcBuffer tmpbuf; + uint16 old_ident; + SilcSocketConnection dest_sock; + + dest_sock = silc_server_get_client_route(server, NULL, 0, + client_id, NULL); + if (!dest_sock) + goto out; + + old_ident = silc_command_get_ident(cmd->payload); + silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng)); + tmpbuf = silc_command_payload_encode_payload(cmd->payload); + + silc_server_packet_send(server, dest_sock, + SILC_PACKET_COMMAND, cmd->packet->flags, + tmpbuf->data, tmpbuf->len, TRUE); + + /* Reprocess this packet after received reply from router */ + silc_server_command_pending(server, SILC_COMMAND_GETKEY, + silc_command_get_ident(cmd->payload), + silc_server_command_destructor, + silc_server_command_getkey, + silc_server_command_dup(cmd)); + cmd->pending = TRUE; + + silc_command_set_ident(cmd->payload, old_ident); + silc_buffer_free(tmpbuf); + return; + } + + if (!client && cmd->pending) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY, + SILC_STATUS_ERR_NO_SUCH_CLIENT_ID); + goto out; + } + + /* The client is locally connected, just get the public key and + send it back. */ + tmp = silc_pkcs_public_key_encode(client->data.public_key, &tmp_len); + pk = silc_buffer_alloc(4 + tmp_len); + silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk)); + silc_buffer_format(pk, + SILC_STR_UI_SHORT(tmp_len), + SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC), + SILC_STR_UI_XNSTRING(tmp, tmp_len), + SILC_STR_END); + silc_free(tmp); + + } else if (id_type == SILC_ID_SERVER) { + server_id = silc_id_payload_get_id(idp); + + /* If the server is not found from local list there is no chance it + would be locally connected server so send the command further. */ + server_entry = silc_idlist_find_server_by_id(server->local_list, + server_id, NULL); + + if ((!server_entry && !cmd->pending && !server->standalone) || + (server_entry && !server_entry->connection)) { + SilcBuffer tmpbuf; + uint16 old_ident; + + old_ident = silc_command_get_ident(cmd->payload); + silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng)); + tmpbuf = silc_command_payload_encode_payload(cmd->payload); + + silc_server_packet_send(server, server->router->connection, + SILC_PACKET_COMMAND, cmd->packet->flags, + tmpbuf->data, tmpbuf->len, TRUE); + + /* Reprocess this packet after received reply from router */ + silc_server_command_pending(server, SILC_COMMAND_GETKEY, + silc_command_get_ident(cmd->payload), + silc_server_command_destructor, + silc_server_command_getkey, + silc_server_command_dup(cmd)); + cmd->pending = TRUE; + + silc_command_set_ident(cmd->payload, old_ident); + silc_buffer_free(tmpbuf); + return; + } + + if (!server_entry && cmd->pending) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY, + SILC_STATUS_ERR_NO_SUCH_SERVER_ID); + goto out; + } + + /* The client is locally connected, just get the public key and + send it back. */ + tmp = silc_pkcs_public_key_encode(server_entry->data.public_key, &tmp_len); + pk = silc_buffer_alloc(4 + tmp_len); + silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk)); + silc_buffer_format(pk, + SILC_STR_UI_SHORT(tmp_len), + SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC), + SILC_STR_UI_XNSTRING(tmp, tmp_len), + SILC_STR_END); + silc_free(tmp); + } else { + goto out; + } + + tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len); + packet = silc_command_reply_payload_encode_va(SILC_COMMAND_GETKEY, + SILC_STATUS_OK, ident, 2, + 2, tmp, tmp_len, + 3, pk->data, pk->len); + silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, + packet->data, packet->len, FALSE); + silc_buffer_free(packet); + silc_buffer_free(pk); + + out: + if (idp) + silc_id_payload_free(idp); + silc_free(client_id); + silc_free(server_id); + silc_server_command_free(cmd); +} diff --git a/apps/silcd/command.h b/apps/silcd/command.h index 62527f0f..4134ee2e 100644 --- a/apps/silcd/command.h +++ b/apps/silcd/command.h @@ -154,5 +154,6 @@ SILC_SERVER_CMD_FUNC(shutdown); SILC_SERVER_CMD_FUNC(silcoper); SILC_SERVER_CMD_FUNC(leave); SILC_SERVER_CMD_FUNC(users); +SILC_SERVER_CMD_FUNC(getkey); #endif diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index a23e0305..2bc68693 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -56,6 +56,7 @@ SilcServerCommandReply silc_command_reply_list[] = SILC_SERVER_CMD_REPLY(motd, MOTD), SILC_SERVER_CMD_REPLY(join, JOIN), SILC_SERVER_CMD_REPLY(users, USERS), + SILC_SERVER_CMD_REPLY(getkey, GETKEY), { NULL, 0 }, }; @@ -885,7 +886,92 @@ SILC_SERVER_CMD_REPLY_FUNC(users) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS); SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS); - if (channel_id) - silc_free(channel_id); + silc_free(channel_id); + silc_server_command_reply_free(cmd); +} + +SILC_SERVER_CMD_REPLY_FUNC(getkey) +{ + SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context; + SilcServer server = cmd->server; + SilcCommandStatus status; + SilcClientEntry client = NULL; + SilcServerEntry server_entry = NULL; + SilcClientID *client_id = NULL; + SilcServerID *server_id = NULL; + SilcSKEPKType type; + unsigned char *tmp, *pk; + uint32 len; + uint16 pk_len; + SilcIDPayload idp = NULL; + SilcIdType id_type; + SilcPublicKey public_key = NULL; + + COMMAND_CHECK_STATUS; + + tmp = silc_argument_get_arg_type(cmd->args, 2, &len); + if (!tmp) + goto out; + idp = silc_id_payload_parse_data(tmp, len); + if (!idp) + goto out; + + /* Get the public key payload */ + tmp = silc_argument_get_arg_type(cmd->args, 3, &len); + if (!tmp) + goto out; + + /* Decode the public key */ + + SILC_GET16_MSB(pk_len, tmp); + SILC_GET16_MSB(type, tmp + 2); + pk = tmp + 4; + + if (type != SILC_SKE_PK_TYPE_SILC) + goto out; + + if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) + goto out; + + id_type = silc_id_payload_get_type(idp); + if (id_type == SILC_ID_CLIENT) { + client_id = silc_id_payload_get_id(idp); + + client = silc_idlist_find_client_by_id(server->local_list, client_id, + NULL); + if (!client) { + client = silc_idlist_find_client_by_id(server->global_list, + client_id, NULL); + if (!client) + goto out; + } + + client->data.public_key = public_key; + } else if (id_type == SILC_ID_SERVER) { + server_id = silc_id_payload_get_id(idp); + + server_entry = silc_idlist_find_server_by_id(server->local_list, server_id, + NULL); + if (!server_entry) { + server_entry = silc_idlist_find_server_by_id(server->global_list, + server_id, NULL); + if (!server_entry) + goto out; + } + + server_entry->data.public_key = public_key; + } else { + goto out; + } + + out: + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS); + SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS); + if (idp) + silc_id_payload_free(idp); + silc_free(client_id); + silc_free(server_id); + if (public_key) + silc_pkcs_public_key_free(public_key); silc_server_command_reply_free(cmd); } diff --git a/apps/silcd/command_reply.h b/apps/silcd/command_reply.h index 852642d6..213ed979 100644 --- a/apps/silcd/command_reply.h +++ b/apps/silcd/command_reply.h @@ -68,5 +68,6 @@ SILC_SERVER_CMD_REPLY_FUNC(info); SILC_SERVER_CMD_REPLY_FUNC(motd); SILC_SERVER_CMD_REPLY_FUNC(join); SILC_SERVER_CMD_REPLY_FUNC(users); +SILC_SERVER_CMD_REPLY_FUNC(getkey); #endif diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 87517338..7b1d27f7 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -3426,7 +3426,7 @@ void silc_server_save_users_on_channel(SilcServer server, } } -/* Lookups route to the client indicated by `id' client ID. The connection +/* Lookups route to the client indicated by the `id_data'. The connection object and internal data object is returned. Returns NULL if route could not be found to the client. If the `client_id' is specified then it is used and the `id_data' is ignored. */ @@ -3468,12 +3468,14 @@ SilcSocketConnection silc_server_get_client_route(SilcServer server, /* We are of course in this case the client's router thus the real "router" of the client is the server who owns the client. Thus we will send the packet to that server. */ - *idata = (SilcIDListData)client->router; + if (idata) + *idata = (SilcIDListData)client->router; return client->router->connection; } /* Seems that client really is directly connected to us */ - *idata = (SilcIDListData)client; + if (idata) + *idata = (SilcIDListData)client; return client->connection; } @@ -3481,7 +3483,8 @@ SilcSocketConnection silc_server_get_client_route(SilcServer server, server our action is to send the packet to our router. */ if (server->server_type == SILC_SERVER && !server->standalone) { silc_free(id); - *idata = (SilcIDListData)server->router; + if (idata) + *idata = (SilcIDListData)server->router; return server->router->connection; } @@ -3496,7 +3499,8 @@ SilcSocketConnection silc_server_get_client_route(SilcServer server, dst_sock = silc_server_route_get(server, id, SILC_ID_CLIENT); silc_free(id); - *idata = (SilcIDListData)dst_sock->user_data; + if (idata) + *idata = (SilcIDListData)dst_sock->user_data; return dst_sock; } } diff --git a/doc/draft-riikonen-silc-ke-auth-02.nroff b/doc/draft-riikonen-silc-ke-auth-02.nroff index 56f3d0bd..8b47ea93 100644 --- a/doc/draft-riikonen-silc-ke-auth-02.nroff +++ b/doc/draft-riikonen-silc-ke-auth-02.nroff @@ -471,6 +471,9 @@ o Public Key Type (2 bytes) - The public key (or certificate) sending SILC_PACKET_FAILURE message and the connection should be closed immediately. +o Public Key (or certicicate) (variable length) - The + public key or certificate. + o Public Data Length (2 bytes) - The length of the Public Data field, not including any other field. diff --git a/doc/draft-riikonen-silc-pp-02.nroff b/doc/draft-riikonen-silc-pp-02.nroff index 03d1f40e..6e3edaea 100644 --- a/doc/draft-riikonen-silc-pp-02.nroff +++ b/doc/draft-riikonen-silc-pp-02.nroff @@ -81,6 +81,7 @@ Table of Contents 2.3.2.1 ID Payload .................................. 16 2.3.2.2 Argument Payload ............................ 16 2.3.2.3 Channel Payload ............................. XXX + 2.3.2.4 Public Key Payload .......................... XXX 2.3.3 Disconnect Payload .................................. 17 2.3.4 Success Payload ..................................... 18 2.3.5 Failure Payload ..................................... 18 @@ -124,22 +125,23 @@ Figure 2: SILC Packet Header Figure 3: ID Payload Figure 4: Argument Payload Figure 5: Channel Payload -Figure 6: Disconnect Payload -Figure 7: Success Payload -Figure 8: Failure Payload -Figure 9: Reject Payload -Figure 10: Notify Payload -Figure 11: Error Payload -Figure 12: Channel Message Payload -Figure 13: Channel Key Payload -Figure 14: Private Message Payload -Figure 15: Private Message Key Payload -Figure 16: Command Payload -Figure 17: Connection Auth Request Payload -Figure 18: New Client Payload -Figure 19: New Server Payload -Figure 20: Key Agreement Payload -Figure 21: Cell Routers Payload +Figure 6: Public Key Payload +Figure 7: Disconnect Payload +Figure 8: Success Payload +Figure 9: Failure Payload +Figure 10: Reject Payload +Figure 11: Notify Payload +Figure 12: Error Payload +Figure 13: Channel Message Payload +Figure 14: Channel Key Payload +Figure 15: Private Message Payload +Figure 16: Private Message Key Payload +Figure 17: Command Payload +Figure 18: Connection Auth Request Payload +Figure 19: New Client Payload +Figure 20: New Server Payload +Figure 21: Key Agreement Payload +Figure 22: Cell Routers Payload .ti 0 @@ -915,6 +917,45 @@ o Mode Mask (4 bytes) - A mode. This can be the mode of the .in 3 +.ti 0 +2.3.2.4 Public Key Payload + +Generic Public Key Payload may be used to send different types of +public keys and certificates. + +The following diagram represents the Channel Payload 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 party (or certificate) ~ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.in 3 + +.ce +Figure 6: Public Key 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 the [SILC3] for defined public key types. + +o Public Key (or certicicate) (variable length) - The + public key or certificate. +.in 3 + + .ti 0 2.3.3 Disconnect Payload @@ -943,7 +984,7 @@ the Disconnect Payload. .in 3 .ce -Figure 6: Disconnect Payload +Figure 7: Disconnect Payload @@ -973,7 +1014,7 @@ This maybe any data, including binary or human readable data. .in 3 .ce -Figure 7: Success Payload +Figure 8: Success Payload .in 6 @@ -1005,7 +1046,7 @@ some protocol is sent in the payload. .in 3 .ce -Figure 8: Failure Payload +Figure 9: Failure Payload .in 6 @@ -1039,7 +1080,7 @@ may be binary or human readable data. .in 3 .ce -Figure 9: Reject Payload +Figure 10: Reject Payload .in 6 @@ -1080,7 +1121,7 @@ Notify Payload. .in 3 .ce -Figure 10: Notify Payload +Figure 11: Notify Payload .in 6 @@ -1376,7 +1417,7 @@ that the client takes error packet seriously. .in 3 .ce -Figure 11: Error Payload +Figure 12: Error Payload .in 6 @@ -1451,7 +1492,7 @@ represents the Channel Message Payload. .in 3 .ce -Figure 12: Channel Message Payload +Figure 13: Channel Message Payload .in 6 @@ -1604,7 +1645,7 @@ represents the Channel Key Payload. .in 3 .ce -Figure 13: Channel Key Payload +Figure 14: Channel Key Payload @@ -1688,7 +1729,7 @@ diagram represents the Private Message Payload. .in 3 .ce -Figure 14: Private Message Payload +Figure 15: Private Message Payload .in 6 @@ -1765,7 +1806,7 @@ diagram represents the Private Message Key Payload. .in 3 .ce -Figure 15: Private Message Key Payload +Figure 16: Private Message Key Payload @@ -1810,7 +1851,7 @@ represents the Command Payload. .in 3 .ce -Figure 16: Command Payload +Figure 17: Command Payload .in 6 @@ -1892,7 +1933,7 @@ diagram represents the Connection Auth Request Payload. .in 3 .ce -Figure 17: Connection Auth Request Payload +Figure 18: Connection Auth Request Payload .in 6 @@ -2010,7 +2051,7 @@ represents the New Client Payload. .in 3 .ce -Figure 18: New Client Payload +Figure 19: New Client Payload .in 6 @@ -2065,7 +2106,7 @@ the New Server Payload. .in 3 .ce -Figure 19: New Server Payload +Figure 20: New Server Payload .in 6 @@ -2139,7 +2180,7 @@ represents the Key Agreement Payload. .in 3 .ce -Figure 20: Key Agreement Payload +Figure 21: Key Agreement Payload .in 6 @@ -2205,7 +2246,7 @@ represents the Cell Routers Payload. .in 3 .ce -Figure 21: Cell Routers Payload +Figure 22: Cell Routers Payload .in 6 diff --git a/doc/draft-riikonen-silc-spec-02.nroff b/doc/draft-riikonen-silc-spec-02.nroff index d945f2aa..0cf79690 100644 --- a/doc/draft-riikonen-silc-spec-02.nroff +++ b/doc/draft-riikonen-silc-spec-02.nroff @@ -3238,6 +3238,34 @@ List of all defined commands in SILC follows. SILC_STATUS_ERR_NOT_ON_CHANNEL + 26 SILC_COMMAND_GETKEY + + Max Arguments: 1 + Arguments: (1) + + This command is used to fetch the public key of the client or + server indicated by the . The public key is fetched + from the server where to the client is connected. + + Reply messages to the command: + + Max Arguments: 3 + Arguments: (1) (2) + (3) + + This command replies with the client's or server's ID and with + the . + + Status messages: + + SILC_STATUS_OK + SILC_STATUS_ERR_NOT_REGISTERED + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS + SILC_STATUS_ERR_TOO_MANY_PARAMS + SILC_STATUS_ERR_NO_SUCH_CLIENT_ID + SILC_STATUS_ERR_NO_SUCH_SERVER_ID + + 27 - 199 Currently undefined commands. @@ -3515,6 +3543,11 @@ List of all defined command status messages following. "The algorithm was not supported." The server does not support the requested algorithm. + + 47 SILC_STATUS_ERR_NO_SUCH_SERVER_ID + + "No such Server ID". Server ID provided does not exist. + .in 3 diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index db3946ca..ffa55d5c 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -57,6 +57,7 @@ SilcClientCommand silc_command_list[] = 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), + SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", SILC_CF_LAG | SILC_CF_REG, 2), { NULL, 0, NULL, 0, 0 }, }; @@ -2049,3 +2050,64 @@ SILC_CLIENT_CMD_FUNC(users) out: silc_client_command_free(cmd); } + +/* Command GETKEY. Used to fetch remote client's public key. */ + +SILC_CLIENT_CMD_FUNC(getkey) +{ + SilcClientCommandContext cmd = (SilcClientCommandContext)context; + SilcClientConnection conn = cmd->conn; + SilcClient client = cmd->client; + SilcClientEntry client_entry = NULL; + uint32 num = 0; + char *nickname = NULL, *server = NULL; + SilcBuffer idp, buffer; + + if (!cmd->conn) { + SILC_NOT_CONNECTED(cmd->client, cmd->conn); + COMMAND_ERROR; + goto out; + } + + if (cmd->argc < 2) { + client->ops->say(client, conn, "Usage: /GETKEY "); + COMMAND_ERROR; + goto out; + } + + /* Parse the typed nickname. */ + if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) { + client->ops->say(client, conn, "Bad nickname"); + COMMAND_ERROR; + goto out; + } + + /* Find client entry */ + client_entry = silc_idlist_get_client(client, conn, nickname, server, num, + TRUE); + if (!client_entry) { + /* Client entry not found, it was requested thus mark this to be + pending command. */ + silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, + conn->cmd_ident, + silc_client_command_destructor, + silc_client_command_getkey, + silc_client_command_dup(cmd)); + cmd->pending = 1; + return; + } + + idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT); + buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1, + 1, idp->data, idp->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(idp); + + /* Notify application */ + COMMAND; + + out: + silc_client_command_free(cmd); +} diff --git a/lib/silcclient/command.h b/lib/silcclient/command.h index a9699527..69a94efd 100644 --- a/lib/silcclient/command.h +++ b/lib/silcclient/command.h @@ -153,5 +153,6 @@ SILC_CLIENT_CMD_FUNC(shutdown); SILC_CLIENT_CMD_FUNC(silcoper); SILC_CLIENT_CMD_FUNC(leave); SILC_CLIENT_CMD_FUNC(users); +SILC_CLIENT_CMD_FUNC(getkey); #endif diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index 3b34d5b5..d91710fa 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -57,12 +57,13 @@ SilcClientCommandReply silc_command_reply_list[] = SILC_CLIENT_CMD_REPLY(cmode, CMODE), SILC_CLIENT_CMD_REPLY(cumode, CUMODE), SILC_CLIENT_CMD_REPLY(kick, KICK), + SILC_CLIENT_CMD_REPLY(ban, BAN), SILC_CLIENT_CMD_REPLY(close, CLOSE), SILC_CLIENT_CMD_REPLY(shutdown, SHUTDOWN), SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER), SILC_CLIENT_CMD_REPLY(leave, LEAVE), SILC_CLIENT_CMD_REPLY(users, USERS), - SILC_CLIENT_CMD_REPLY(ban, BAN), + SILC_CLIENT_CMD_REPLY(getkey, GETKEY), { NULL, 0 }, }; @@ -106,6 +107,7 @@ const SilcCommandStatusMessage silc_command_status_messages[] = { { STAT(BAD_CHANNEL), "Bad channel name" }, { STAT(AUTH_FAILED), "Authentication failed" }, { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" }, + { STAT(NO_SUCH_SERVER_ID), "No such Server ID" }, { 0, NULL } }; @@ -1396,6 +1398,59 @@ SILC_CLIENT_CMD_REPLY_FUNC(connect) silc_client_command_reply_free(cmd); } +SILC_CLIENT_CMD_REPLY_FUNC(ban) +{ + SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; + SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; + SilcCommandStatus status; + SilcIDCacheEntry id_cache = NULL; + SilcChannelEntry channel; + SilcChannelID *channel_id; + unsigned char *tmp; + uint32 len; + + 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; + } + + /* Take Channel ID */ + tmp = silc_argument_get_arg_type(cmd->args, 2, &len); + if (!tmp) + goto out; + + channel_id = silc_id_payload_parse_id(tmp, len); + if (!channel_id) + goto out; + + /* Get the channel entry */ + if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, + SILC_ID_CHANNEL, &id_cache)) { + silc_free(channel_id); + COMMAND_REPLY_ERROR; + goto out; + } + + channel = (SilcChannelEntry)id_cache->context; + + /* Get the ban list */ + tmp = silc_argument_get_arg_type(cmd->args, 3, &len); + + /* Notify application */ + COMMAND_REPLY((ARGS, channel, tmp)); + + /* Execute any pending command callbacks */ + SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN); + + out: + SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN); + silc_client_command_reply_free(cmd); +} + SILC_CLIENT_CMD_REPLY_FUNC(close) { SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; @@ -1652,16 +1707,26 @@ SILC_CLIENT_CMD_REPLY_FUNC(users) silc_client_command_reply_free(cmd); } -SILC_CLIENT_CMD_REPLY_FUNC(ban) +/* Received command reply to GETKEY command. WE've received the remote + client's public key. */ + +SILC_CLIENT_CMD_REPLY_FUNC(getkey) { SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; SilcCommandStatus status; - SilcIDCacheEntry id_cache = NULL; - SilcChannelEntry channel; - SilcChannelID *channel_id; - unsigned char *tmp; + SilcIDCacheEntry id_cache; + SilcIDPayload idp = NULL; + SilcClientID *client_id = NULL; + SilcClientEntry client_entry; + SilcSKEPKType type; + unsigned char *tmp, *pk; uint32 len; + uint16 pk_len; + SilcIdType id_type; + SilcPublicKey public_key = NULL; + + SILC_LOG_DEBUG(("Start")); tmp = silc_argument_get_arg_type(cmd->args, 1, NULL); SILC_GET16_MSB(status, tmp); @@ -1672,35 +1737,55 @@ SILC_CLIENT_CMD_REPLY_FUNC(ban) goto out; } - /* Take Channel ID */ tmp = silc_argument_get_arg_type(cmd->args, 2, &len); if (!tmp) goto out; + idp = silc_id_payload_parse_data(tmp, len); + if (!idp) + goto out; - channel_id = silc_id_payload_parse_id(tmp, len); - if (!channel_id) + /* Get the public key payload */ + tmp = silc_argument_get_arg_type(cmd->args, 3, &len); + if (!tmp) goto out; - /* Get the channel entry */ - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - SILC_ID_CHANNEL, &id_cache)) { - silc_free(channel_id); - COMMAND_REPLY_ERROR; + /* Decode the public key */ + + SILC_GET16_MSB(pk_len, tmp); + SILC_GET16_MSB(type, tmp + 2); + pk = tmp + 4; + + if (type != SILC_SKE_PK_TYPE_SILC) goto out; - } - - channel = (SilcChannelEntry)id_cache->context; - /* Get the ban list */ - tmp = silc_argument_get_arg_type(cmd->args, 3, &len); + if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) + goto out; - /* Notify application */ - COMMAND_REPLY((ARGS, channel, tmp)); + id_type = silc_id_payload_get_type(idp); + if (id_type == SILC_ID_CLIENT) { + client_id = silc_id_payload_get_id(idp); - /* Execute any pending command callbacks */ - SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN); + if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id, + SILC_ID_CLIENT, &id_cache)) + goto out; + + client_entry = (SilcClientEntry)id_cache->context; + + /* Notify application */ + COMMAND_REPLY((ARGS, id_type, client_entry, public_key)); + } else if (id_type == SILC_ID_SERVER) { + /* XXX we don't have server entries at all */ + goto out; + } else { + goto out; + } out: - SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN); + SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY); + if (idp) + silc_id_payload_free(idp); + if (public_key) + silc_pkcs_public_key_free(public_key); + silc_free(client_id); silc_client_command_reply_free(cmd); } diff --git a/lib/silcclient/command_reply.h b/lib/silcclient/command_reply.h index ed09ab59..8c3951a4 100644 --- a/lib/silcclient/command_reply.h +++ b/lib/silcclient/command_reply.h @@ -92,11 +92,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(umode); SILC_CLIENT_CMD_REPLY_FUNC(cmode); SILC_CLIENT_CMD_REPLY_FUNC(cumode); SILC_CLIENT_CMD_REPLY_FUNC(kick); +SILC_CLIENT_CMD_REPLY_FUNC(ban); SILC_CLIENT_CMD_REPLY_FUNC(close); SILC_CLIENT_CMD_REPLY_FUNC(shutdown); SILC_CLIENT_CMD_REPLY_FUNC(silcoper); SILC_CLIENT_CMD_REPLY_FUNC(leave); SILC_CLIENT_CMD_REPLY_FUNC(users); -SILC_CLIENT_CMD_REPLY_FUNC(ban); +SILC_CLIENT_CMD_REPLY_FUNC(getkey); #endif diff --git a/lib/silccore/silccommand.h b/lib/silccore/silccommand.h index 2f835e91..2b069bc2 100644 --- a/lib/silccore/silccommand.h +++ b/lib/silccore/silccommand.h @@ -85,6 +85,7 @@ typedef enum { #define SILC_COMMAND_SILCOPER 23 #define SILC_COMMAND_LEAVE 24 #define SILC_COMMAND_USERS 25 +#define SILC_COMMAND_GETKEY 26 /* Reserved */ #define SILC_COMMAND_RESERVED 255 @@ -134,6 +135,7 @@ typedef uint16 SilcCommandStatus; #define SILC_STATUS_ERR_BAD_CHANNEL 44 #define SILC_STATUS_ERR_AUTH_FAILED 45 #define SILC_STATUS_ERR_UNKNOWN_ALGORITHM 46 +#define SILC_STATUS_ERR_NO_SUCH_SERVER_ID 47 /* Prototypes */ SilcCommandPayload silc_command_payload_parse(SilcBuffer buffer);