From cdedc07c65bab8467f6f5b1ef4b38982c2c77571 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 10 Nov 2002 20:30:49 +0000 Subject: [PATCH] Protocol version 1.2 integrations --- CHANGES | 39 +++ apps/irssi/docs/help/in/key.in | 14 +- apps/irssi/docs/help/in/kill.in | 29 +- .../irssi/src/fe-common/silc/module-formats.c | 2 +- apps/irssi/src/silc/core/silc-channels.c | 41 ++- apps/irssi/src/silc/core/silc-queries.c | 6 +- apps/irssi/src/silc/core/silc-servers.c | 2 +- apps/silcd/command.c | 210 +++++------ apps/silcd/command_reply.c | 18 +- apps/silcd/packet_receive.c | 9 +- apps/silcd/packet_send.c | 73 +++- apps/silcd/server.c | 24 +- apps/silcd/server_backup.c | 6 + apps/silcd/server_internal.h | 4 + apps/silcd/server_query.c | 2 + doc/draft-riikonen-presence-attrs-01.nroff | 19 +- doc/draft-riikonen-silc-commands-04.nroff | 101 ++++-- ...raft-riikonen-silc-flags-payloads-01.nroff | 124 ++++++- doc/draft-riikonen-silc-pp-06.nroff | 94 +++-- doc/draft-riikonen-silc-spec-06.nroff | 17 +- includes/silcincludes.h.in | 10 +- includes/silcversion.h | 2 +- lib/silcclient/client.c | 20 +- lib/silcclient/client_channel.c | 31 +- lib/silcclient/client_internal.h | 6 +- lib/silcclient/client_prvmsg.c | 142 +++++--- lib/silcclient/command.c | 50 ++- lib/silcclient/command_reply.c | 16 +- lib/silcclient/silcclient.h | 161 ++++----- lib/silccore/silcargument.c | 2 +- lib/silccore/silcargument.h | 2 +- lib/silccore/silcattrs.c | 51 ++- lib/silccore/silcattrs.h | 2 + lib/silccore/silcauth.c | 326 +++++++++++++++++- lib/silccore/silcauth.h | 208 ++++++++--- lib/silccore/silcchannel.c | 67 +--- lib/silccore/silcchannel.h | 4 +- lib/silccore/silcchannel_i.h | 95 +++++ lib/silccore/silcpacket.c | 7 +- lib/silccore/silcpacket.h | 21 +- lib/silccore/silcprivate.c | 135 +++++--- lib/silccore/silcprivate.h | 32 +- lib/silccore/silcprivate_i.h | 56 +++ lib/silccore/silcstatus.h | 2 + lib/silccrypt/silchmac.h | 5 +- lib/silccrypt/silcpkcs.c | 85 +++++ lib/silccrypt/silcpkcs.h | 41 ++- lib/silcutil/silcbuffmt.c | 4 + lib/silcutil/silcutil.c | 2 + lib/silcutil/stacktrace.h | 2 +- prepare | 2 +- 51 files changed, 1797 insertions(+), 626 deletions(-) create mode 100644 lib/silccore/silcchannel_i.h create mode 100644 lib/silccore/silcprivate_i.h diff --git a/CHANGES b/CHANGES index d265e7f8..a456d060 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,42 @@ +Sun Nov 10 12:20:56 EET 2002 Pekka Riikonen + + * Added support for rekey before 2^32 sequence number wraps. + Affected files in server and client library. + + * Padding must be at least 8 bytes now. Implemented and updated + protocol specs. + + * Compute maximum padding for authentication packets to make + passphrase approximation attacks impossible. Affected files + in client library and in server. + + * Fixed PING command sending in client library and handling in + server. The server ID must be ID Payload, not raw ID data. + Affected files in server and client library. + + * Defined that all public keys sent in commands and notify + payloads are actually Public Key Payloads not raw public key + data. Updated protocol specs and implemented. + + * Updated protocol version to 1.2. Updated specs and code. + + * Added ERR_UNSUPPORTED_PUBLIC_KEY and ERR_OPERATION_ALLOWED + status types. Updated specs and the code. + + * Added support for normal client to kill its own entries from + the network. Updated protocol specs and the code. + + * Defined the SILC_MESSAGE_FLAG_SIGNED. Updated protocol specs + and added initial implementation. + + * Added MAC field to the Private Message Payload to protect + against chosen ciphertext attacks. Updated the protocol specs + and implemented. + + * Added idle and signon fields to the ATTRIBUTE_SERVICE + attribute to indicate the user's current idle and signon time + of a service. Updated protocol specs and implemented. + Thu Nov 7 19:21:10 EET 2002 Pekka Riikonen * Added "do_not_bind" argument to silc_client_file_send what diff --git a/apps/irssi/docs/help/in/key.in b/apps/irssi/docs/help/in/key.in index 3d3a7162..92f96999 100644 --- a/apps/irssi/docs/help/in/key.in +++ b/apps/irssi/docs/help/in/key.in @@ -20,7 +20,7 @@ Types: Commands: - set [ [] []] + set [ [] []] [-responder] Set the key into use. If the is provided it is used as the key material. If the is not provided the @@ -28,9 +28,11 @@ Commands: been performed this command has no effect. If the type is MSG and the is `*' then random key - will be generated automatically. The may be set - for both private message and channel private keys and the - may be set only to the channel private keys. + will be generated automatically. The -responder option + may be used ONLY with MSG type. One of the clients must + be the responder side. The one being the responder must + use this option. The clients setting the key must agree + on which one is the responder. unset [] @@ -97,3 +99,7 @@ Examples: /KEY CHANNEL set very_secret_key_this_is /KEY CHANNEL list + /KEY MSG nickname set secretkey + /KEY MSG nick set secretkey -responder + /KEY MSG foo agreement 10.2.1.7 5000 + /KEY MSG bar negotiate 10.2.1.7 5000 diff --git a/apps/irssi/docs/help/in/kill.in b/apps/irssi/docs/help/in/kill.in index 8b3b91cd..96b6b6ca 100644 --- a/apps/irssi/docs/help/in/kill.in +++ b/apps/irssi/docs/help/in/kill.in @@ -1,11 +1,30 @@ @SYNTAX:kill@ -This is operator command. KILL is used to forcibly remove -a client from the network. It works similarly to KICK expect -that the client is removed from the entire network. In general, -KILL is useful only as a warning tool for abusive users and -it has only temporary effects. +This command can be used for two purpose: SILC operator may use it +to remove a client from the network, or user may use it to remove +its own client entries from the network. + +If you are not SILC operator you cannot use this command to remove +anybody else except yourself from the network. Only SILC operator +is able to kill other clients from the network. When killing your +own client entry you must provide -pubkey argument to the command. +For killing your own client from network you also must be connected +to the same server as your own client entry (the client entry may +be for example detached client entry). When using this command as +SILC operator -pubkey has no effect. + +Examples: + + /KILL myself -pubkey + + Kill yourself with nickname "myself" from network. + + /SILCOPER user + /KILL someclient You have been killed + + Become SILC operator and kill client named + "someclient", with comment "You have been killed". See also: OPER, SILCOPER diff --git a/apps/irssi/src/fe-common/silc/module-formats.c b/apps/irssi/src/fe-common/silc/module-formats.c index c1521c31..ecd8fafd 100644 --- a/apps/irssi/src/fe-common/silc/module-formats.c +++ b/apps/irssi/src/fe-common/silc/module-formats.c @@ -159,7 +159,7 @@ FORMAT_REC fecommon_silc_formats[] = { { "attr_allow", " Sending allowed : $0", 1, { 0 } }, { "attr_vcard_file", " Business card : $0", 1, { 0 } }, { "attr_services", " Services used : $0", 1, { 0 } }, - { "attr_service", " Service : port [$0] address [$1] logged in [$2]", 3, { 0, 0, 0 } }, + { "attr_service", " Service : port [$0] address [$1] logged in [$2] login time [$3] idle [$4]", 5, { 0, 0, 0, 0, 0 } }, { "attr_status_mood", " User's mood : $0", 1, { 0 } }, { "attr_status_text", " User's message : $0", 1, { 0 } }, { "attr_status_message", " User's message : $0", 1, { 0 } }, diff --git a/apps/irssi/src/silc/core/silc-channels.c b/apps/irssi/src/silc/core/silc-channels.c index 005763bf..a720ecdb 100644 --- a/apps/irssi/src/silc/core/silc-channels.c +++ b/apps/irssi/src/silc/core/silc-channels.c @@ -424,7 +424,7 @@ static void keyagr_completion(SilcClient client, /* Set the private key for this client */ silc_client_del_private_message_key(client, conn, client_entry); silc_client_add_private_message_key_ske(client, conn, client_entry, - NULL, key, i->responder); + NULL, NULL, key, i->responder); printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP, SILCTXT_KEY_AGREEMENT_PRIVMSG, client_entry->nickname); @@ -612,23 +612,36 @@ static void command_key(const char *data, SILC_SERVER_REC *server, command = 1; if (argc >= 5) { + char *cipher = NULL, *hmac = NULL; + if (type == 1 && client_entry) { /* Set private message key */ + bool responder = FALSE; silc_client_del_private_message_key(silc_client, conn, client_entry); - if (argc >= 6) - silc_client_add_private_message_key(silc_client, conn, client_entry, - argv[5], argv[4], - argv_lens[4], - (argv[4][0] == '*' ? - TRUE : FALSE), FALSE); - else - silc_client_add_private_message_key(silc_client, conn, client_entry, - NULL, argv[4], - argv_lens[4], - (argv[4][0] == '*' ? - TRUE : FALSE), FALSE); + if (argc >= 6) { + if (!strcasecmp(argv[5], "-responder")) + responder = TRUE; + else + cipher = argv[5]; + } + if (argc >= 7) { + if (!strcasecmp(argv[6], "-responder")) + responder = TRUE; + else + hmac = argv[6]; + } + if (argc >= 8) { + if (!strcasecmp(argv[7], "-responder")) + responder = TRUE; + } + + silc_client_add_private_message_key(silc_client, conn, client_entry, + cipher, hmac, + argv[4], argv_lens[4], + (argv[4][0] == '*' ? + TRUE : FALSE), responder); /* Send the key to the remote client so that it starts using it too. */ @@ -639,8 +652,6 @@ static void command_key(const char *data, SILC_SERVER_REC *server, */ } else if (type == 2) { /* Set private channel key */ - char *cipher = NULL, *hmac = NULL; - if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) { printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, SILCTXT_CH_PRIVATE_KEY_NOMODE, diff --git a/apps/irssi/src/silc/core/silc-queries.c b/apps/irssi/src/silc/core/silc-queries.c index e4a03ae8..c946f56d 100644 --- a/apps/irssi/src/silc/core/silc-queries.c +++ b/apps/irssi/src/silc/core/silc-queries.c @@ -323,6 +323,7 @@ void silc_query_attributes_default(SilcClient client, silc_strncat(service.address, sizeof(service.address), *entry, strlen(*entry)); service.status = TRUE; + service.idle = 0; silc_client_attribute_add(silc_client, conn, SILC_ATTRIBUTE_SERVICE, &service, sizeof(service)); @@ -609,9 +610,10 @@ void silc_query_attributes_print(SILC_SERVER_REC *server, if (!silc_attribute_get_object(attr, (void *)&service, sizeof(service))) continue; - snprintf(tmp, sizeof(tmp) - 1, "%s:%d (logged %s)", + snprintf(tmp, sizeof(tmp) - 1, "%s:%d (logged %s) idle %d seconds", service.address, (unsigned int)service.port, - service.status ? "in" : "out"); + service.status ? "in" : "out", + service.idle); printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, SILCTXT_ATTR_SERVICES, tmp); } diff --git a/apps/irssi/src/silc/core/silc-servers.c b/apps/irssi/src/silc/core/silc-servers.c index 77ae7d8d..4d68aeb0 100644 --- a/apps/irssi/src/silc/core/silc-servers.c +++ b/apps/irssi/src/silc/core/silc-servers.c @@ -414,7 +414,7 @@ char *silc_server_get_channels(SILC_SERVER_REC *server) /* SYNTAX: KEY MSG set|unset|list|agreement|negotiate [] */ /* SYNTAX: KEY CHANNEL set|unset|list|change [] */ /* SYNTAX: KICK [@] [] */ -/* SYNTAX: KILL [@] [] */ +/* SYNTAX: KILL [@] [] [-pubkey] */ /* SYNTAX: OPER [-pubkey] */ /* SYNTAX: SILCOPER [-pubkey] */ /* SYNTAX: TOPIC [] */ diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 06fbd9fb..13aaad03 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -1086,7 +1086,7 @@ SILC_SERVER_CMD_FUNC(invite) /* Get the client entry */ dest = silc_server_query_client(server, dest_id, FALSE, &resolve); if (!dest) { - if (server->server_type != SILC_SERVER || !resolve) { + if (server->server_type != SILC_SERVER || !resolve || cmd->pending) { silc_server_command_send_status_reply( cmd, SILC_COMMAND_INVITE, SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0); @@ -1299,28 +1299,34 @@ SILC_SERVER_CMD_FUNC(kill) SilcServer server = cmd->server; SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; SilcClientEntry remote_client; - SilcClientID *client_id; - unsigned char *tmp, *comment; - SilcUInt32 tmp_len, tmp_len2; - bool local; + SilcClientID *client_id = NULL; + unsigned char *tmp, *comment, *auth; + SilcUInt32 tmp_len, tmp_len2, auth_len; - SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 2); + SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 3); if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client) goto out; - /* KILL command works only on router */ - if (server->server_type != SILC_ROUTER) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL, - SILC_STATUS_ERR_NO_ROUTER_PRIV, 0); - goto out; - } + /* Get authentication payload if present */ + auth = silc_argument_get_arg_type(cmd->args, 3, &auth_len); - /* Check whether client has the permissions. */ - if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL, - SILC_STATUS_ERR_NO_ROUTER_PRIV, 0); - goto out; + if (!auth) { + /* Router operator killing */ + + /* KILL command works only on router */ + if (server->server_type != SILC_ROUTER) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL, + SILC_STATUS_ERR_NO_ROUTER_PRIV, 0); + goto out; + } + + /* Check whether client has the permissions. */ + if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL, + SILC_STATUS_ERR_NO_ROUTER_PRIV, 0); + goto out; + } } /* Get the client ID */ @@ -1342,11 +1348,9 @@ SILC_SERVER_CMD_FUNC(kill) /* Get the client entry */ remote_client = silc_idlist_find_client_by_id(server->local_list, client_id, TRUE, NULL); - local = TRUE; if (!remote_client) { remote_client = silc_idlist_find_client_by_id(server->global_list, client_id, TRUE, NULL); - local = FALSE; if (!remote_client) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL, SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, @@ -1357,23 +1361,64 @@ SILC_SERVER_CMD_FUNC(kill) /* Get comment */ comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2); - if (tmp_len2 > 128) + if (comment && tmp_len2 > 128) { tmp_len2 = 128; + comment[127] = '\0'; + } - /* Send reply to the sender */ - silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL, - SILC_STATUS_OK, 0); + /* If authentication data is provided then verify that killing is + actually allowed */ + if (auth && auth_len) { + SilcSocketConnection sock; - /* Check if anyone is watching this nickname */ - if (server->server_type == SILC_ROUTER) - silc_server_check_watcher_list(server, client, NULL, - SILC_NOTIFY_TYPE_KILLED); + if (!SILC_IS_LOCAL(remote_client) || !remote_client->data.public_key) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL, + SILC_STATUS_ERR_OPERATION_ALLOWED, + 0); + goto out; + } - /* Now do the killing */ - silc_server_kill_client(server, remote_client, comment, client->id, - SILC_ID_CLIENT); + /* Verify the signature */ + if (!silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY, + remote_client->data.public_key, 0, + server->sha1hash, remote_client->id, + SILC_ID_CLIENT)) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL, + SILC_STATUS_ERR_AUTH_FAILED, + 0); + goto out; + } + + /* Send reply to the sender */ + silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL, + SILC_STATUS_OK, 0); + + /* Do normal signoff for the destination client */ + sock = remote_client->connection; + silc_server_free_client_data(server, NULL, remote_client, TRUE, + comment ? comment : + (unsigned char *)"Killed"); + if (sock) + silc_server_close_connection(server, sock); + } else { + /* Router operator killing */ + + /* Send reply to the sender */ + silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL, + SILC_STATUS_OK, 0); + + /* Check if anyone is watching this nickname */ + if (server->server_type == SILC_ROUTER) + silc_server_check_watcher_list(server, client, NULL, + SILC_NOTIFY_TYPE_KILLED); + + /* Now do the killing */ + silc_server_kill_client(server, remote_client, comment, client->id, + SILC_ID_CLIENT); + } out: + silc_free(client_id); silc_server_command_free(cmd); } @@ -1545,20 +1590,24 @@ SILC_SERVER_CMD_FUNC(ping) { SilcServerCommandContext cmd = (SilcServerCommandContext)context; SilcServer server = cmd->server; - SilcUInt32 len; + SilcUInt32 tmp_len; unsigned char *tmp; + SilcServerID *server_id = NULL; - SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PING, cmd, 1, 2); + SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PING, cmd, 1, 1); /* Get Server ID */ - tmp = silc_argument_get_arg_type(cmd->args, 1, &len); + tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len); if (!tmp) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING, SILC_STATUS_ERR_NO_SERVER_ID, 0); goto out; } + server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL); + if (!server_id) + goto out; - if (!memcmp(tmp, server->id_string, server->id_string_len)) { + if (SILC_ID_SERVER_COMPARE(server_id, server->id)) { /* Send our reply */ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING, SILC_STATUS_OK, 0); @@ -1569,6 +1618,7 @@ SILC_SERVER_CMD_FUNC(ping) } out: + silc_free(server_id); silc_server_command_free(cmd); } @@ -1590,7 +1640,7 @@ SILC_SERVER_CMD_FUNC(stats) /* Get Server ID */ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len); if (!tmp) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO, + silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING, SILC_STATUS_ERR_NO_SERVER_ID, 0); goto out; } @@ -1600,7 +1650,7 @@ SILC_SERVER_CMD_FUNC(stats) /* The ID must be ours */ if (!SILC_ID_SERVER_COMPARE(server->id, server_id)) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO, + silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING, SILC_STATUS_ERR_NO_SUCH_SERVER, 0); silc_free(server_id); goto out; @@ -1693,8 +1743,7 @@ static void silc_server_command_join_channel(SilcServer server, char check[512], check2[512]; bool founder = FALSE; bool resolve; - unsigned char *fkey = NULL; - SilcUInt32 fkey_len = 0; + SilcBuffer fkey = NULL; const char *cipher; SILC_LOG_DEBUG(("Joining client to channel")); @@ -1711,10 +1760,7 @@ static void silc_server_command_join_channel(SilcServer server, client = silc_server_query_client(server, client_id, FALSE, &resolve); if (!client) { - if (cmd->pending) - goto out; - - if (!resolve) { + if (!resolve || cmd->pending) { silc_server_command_send_status_reply( cmd, SILC_COMMAND_JOIN, SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0); @@ -1935,7 +1981,7 @@ static void silc_server_command_join_channel(SilcServer server, } if (channel->founder_key) - fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len); + fkey = silc_pkcs_public_key_payload_encode(channel->founder_key); reply = silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN, @@ -1964,7 +2010,8 @@ static void silc_server_command_join_channel(SilcServer server, 13, user_list->data, user_list->len, 14, mode_list->data, mode_list->len, - 15, fkey, fkey_len); + 15, fkey ? fkey->data : NULL, + fkey ? fkey->len : 0); /* Send command reply */ silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, @@ -2008,7 +2055,8 @@ static void silc_server_command_join_channel(SilcServer server, SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4, clidp->data, clidp->len, mode, 4, clidp->data, clidp->len, - fkey, fkey_len); + fkey ? fkey->data : NULL, + fkey ? fkey->len : 0); } } @@ -2025,7 +2073,7 @@ static void silc_server_command_join_channel(SilcServer server, silc_buffer_free(keyp); silc_buffer_free(user_list); silc_buffer_free(mode_list); - silc_free(fkey); + silc_buffer_free(fkey); out: silc_free(passphrase); @@ -2510,8 +2558,7 @@ SILC_SERVER_CMD_FUNC(cmode) SilcUInt16 ident = silc_command_get_ident(cmd->payload); bool set_mask = FALSE; SilcPublicKey founder_key = NULL; - unsigned char *fkey = NULL; - SilcUInt32 fkey_len = 0; + SilcBuffer fkey = NULL; if (!client) { silc_server_command_free(cmd); @@ -2837,7 +2884,7 @@ SILC_SERVER_CMD_FUNC(cmode) } founder_key = channel->founder_key; - fkey = silc_pkcs_public_key_encode(founder_key, &fkey_len); + fkey = silc_pkcs_public_key_payload_encode(founder_key); if (!fkey) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, SILC_STATUS_ERR_AUTH_FAILED, @@ -2871,7 +2918,8 @@ SILC_SERVER_CMD_FUNC(cmode) hmac, hmac ? strlen(hmac) : 0, passphrase, passphrase ? strlen(passphrase) : 0, - fkey, fkey_len); + fkey ? fkey->data : NULL, + fkey ? fkey->len : 0); /* Set CMODE notify type to network */ silc_server_send_notify_cmode(server, SILC_PRIMARY_ROUTE(server), @@ -2892,7 +2940,7 @@ SILC_SERVER_CMD_FUNC(cmode) out: channel->mode = old_mask; - silc_free(fkey); + silc_buffer_free(fkey); silc_free(channel_id); silc_server_command_free(cmd); } @@ -2916,8 +2964,7 @@ SILC_SERVER_CMD_FUNC(cumode) int notify = FALSE; SilcUInt16 ident = silc_command_get_ident(cmd->payload); SilcPublicKey founder_key = NULL; - unsigned char *fkey = NULL; - SilcUInt32 fkey_len = 0; + SilcBuffer fkey = NULL; if (!client) goto out; @@ -3063,7 +3110,7 @@ SILC_SERVER_CMD_FUNC(cumode) notify = TRUE; founder_key = channel->founder_key; - fkey = silc_pkcs_public_key_encode(founder_key, &fkey_len); + fkey = silc_pkcs_public_key_payload_encode(founder_key); if (!fkey) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, SILC_STATUS_ERR_AUTH_FAILED, 0); @@ -3232,7 +3279,8 @@ SILC_SERVER_CMD_FUNC(cumode) idp->data, idp->len, tmp_mask, 4, tmp_id, tmp_len, - fkey, fkey_len); + fkey ? fkey->data : NULL, + fkey ? fkey->len : 0); /* Set CUMODE notify type to network */ silc_server_send_notify_cumode(server, SILC_PRIMARY_ROUTE(server), @@ -3256,7 +3304,7 @@ SILC_SERVER_CMD_FUNC(cumode) out: silc_free(channel_id); silc_free(client_id); - silc_free(fkey); + silc_buffer_free(fkey); silc_server_command_free(cmd); } @@ -4277,8 +4325,8 @@ SILC_SERVER_CMD_FUNC(getkey) SilcServerID *server_id = NULL; SilcIDPayload idp = NULL; SilcUInt16 ident = silc_command_get_ident(cmd->payload); - unsigned char *tmp, *pkdata; - SilcUInt32 tmp_len, pklen; + unsigned char *tmp; + SilcUInt32 tmp_len; SilcBuffer pk = NULL; SilcIdType id_type; SilcPublicKey public_key; @@ -4353,22 +4401,8 @@ SILC_SERVER_CMD_FUNC(getkey) send it back. If they key does not exist then do not send it, send just OK reply */ public_key = client->data.public_key; - if (!public_key) { - pkdata = NULL; - pklen = 0; - } else { - tmp = silc_pkcs_public_key_encode(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); - pkdata = pk->data; - pklen = pk->len; - } + if (public_key) + pk = silc_pkcs_public_key_payload_encode(public_key); } else if (id_type == SILC_ID_SERVER) { server_id = silc_id_payload_get_id(idp); @@ -4419,42 +4453,26 @@ SILC_SERVER_CMD_FUNC(getkey) public_key = (!server_entry->data.public_key ? (server_entry == server->id_entry ? server->public_key : NULL) : server_entry->data.public_key); - if (!public_key) { - pkdata = NULL; - pklen = 0; - } else { - tmp = silc_pkcs_public_key_encode(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); - pkdata = pk->data; - pklen = pk->len; - } + if (public_key) + pk = silc_pkcs_public_key_payload_encode(public_key); } 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, 0, ident, - pkdata ? 2 : 1, + SILC_STATUS_OK, 0, ident, 2, 2, tmp, tmp_len, - 3, pkdata, pklen); + 3, pk ? pk->data : NULL, + pk ? pk->len : 0); silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, packet->data, packet->len, FALSE); silc_buffer_free(packet); - if (pk) - silc_buffer_free(pk); - out: if (idp) silc_id_payload_free(idp); + silc_buffer_free(pk); silc_free(client_id); silc_free(server_id); silc_server_command_free(cmd); diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index 6a4713d6..d02b62ff 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -939,7 +939,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join) /* Get founder key */ tmp = silc_argument_get_arg_type(cmd->args, 15, &len); if (tmp) - silc_pkcs_public_key_decode(tmp, len, &founder_key); + silc_pkcs_public_key_payload_decode(tmp, len, &founder_key); /* See whether we already have the channel. */ entry = silc_idlist_find_channel_by_name(server->local_list, @@ -1205,10 +1205,8 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey) SilcServerEntry server_entry = NULL; SilcClientID *client_id = NULL; SilcServerID *server_id = NULL; - SilcSKEPKType type; - unsigned char *tmp, *pk; + unsigned char *tmp; SilcUInt32 len; - SilcUInt16 pk_len; SilcIDPayload idp = NULL; SilcIdType id_type; SilcPublicKey public_key = NULL; @@ -1227,16 +1225,8 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey) 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)) + /* Decode the public key payload */ + if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key)) goto out; id_type = silc_id_payload_get_type(idp); diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index feb4e019..b715828d 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -612,7 +612,8 @@ void silc_server_notify(SilcServer server, if (channel->founder_key) silc_pkcs_public_key_free(channel->founder_key); channel->founder_key = NULL; - silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key); + silc_pkcs_public_key_payload_decode(tmp, tmp_len, + &channel->founder_key); } break; @@ -718,7 +719,7 @@ void silc_server_notify(SilcServer server, if (channel->founder_key) silc_pkcs_public_key_free(channel->founder_key); channel->founder_key = NULL; - silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key); + silc_pkcs_public_key_payload_decode(tmp, tmp_len, &channel->founder_key); if (!channel->founder_key || (client && client->data.public_key && @@ -938,8 +939,8 @@ void silc_server_notify(SilcServer server, if (channel->founder_key) { /* Get public key that must be present in notify */ tmp = silc_argument_get_arg_type(args, 4, &tmp_len); - if (!tmp || !silc_pkcs_public_key_decode(tmp, tmp_len, - &founder_key)) { + if (!tmp || !silc_pkcs_public_key_payload_decode(tmp, tmp_len, + &founder_key)) { chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO; silc_server_force_cumode_change(server, sock, channel, chl, mode); notify_sent = TRUE; diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index 2a5118cc..9113f688 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -181,6 +181,12 @@ void silc_server_packet_send_dest(SilcServer server, hmac = idata->hmac_send; sequence = idata->psn_send++; block_len = silc_cipher_get_block_len(cipher); + + /* Check for mandatory rekey */ + if (sequence == SILC_SERVER_REKEY_THRESHOLD) + silc_schedule_task_add(server->schedule, sock->sock, + silc_server_rekey_callback, sock, 0, 1, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); } /* Set the packet context pointers */ @@ -197,7 +203,10 @@ void silc_server_packet_send_dest(SilcServer server, packetdata.dst_id_len)); packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + packetdata.src_id_len + dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len); + if (type == SILC_PACKET_CONNECTION_AUTH) + SILC_PACKET_PADLEN_MAX(packetdata.truelen, block_len, packetdata.padlen); + else + SILC_PACKET_PADLEN(packetdata.truelen, block_len, packetdata.padlen); /* Create the outgoing packet */ if (!silc_packet_assemble(&packetdata, NULL, cipher, hmac, sock, @@ -272,6 +281,12 @@ void silc_server_packet_send_srcdest(SilcServer server, hmac = idata->hmac_send; sequence = idata->psn_send++; block_len = silc_cipher_get_block_len(cipher); + + /* Check for mandatory rekey */ + if (sequence == SILC_SERVER_REKEY_THRESHOLD) + silc_schedule_task_add(server->schedule, sock->sock, + silc_server_rekey_callback, sock, 0, 1, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); } if (dst_id) { @@ -298,7 +313,7 @@ void silc_server_packet_send_srcdest(SilcServer server, dst_id_len)); packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + packetdata.src_id_len + dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len); + SILC_PACKET_PADLEN(packetdata.truelen, block_len, packetdata.padlen); /* Create the outgoing packet */ if (!silc_packet_assemble(&packetdata, NULL, cipher, hmac, sock, data, @@ -364,6 +379,12 @@ void silc_server_packet_broadcast(SilcServer server, /* Now actually send the packet */ silc_server_packet_send_real(server, sock, TRUE); silc_free(id); + + /* Check for mandatory rekey */ + if (idata->psn_send == SILC_SERVER_REKEY_THRESHOLD) + silc_schedule_task_add(server->schedule, sock->sock, + silc_server_rekey_callback, sock, 0, 1, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); return; } @@ -402,6 +423,12 @@ void silc_server_packet_route(SilcServer server, /* Now actually send the packet */ silc_server_packet_send_real(server, sock, TRUE); + + /* Check for mandatory rekey */ + if (idata->psn_send == SILC_SERVER_REKEY_THRESHOLD) + silc_schedule_task_add(server->schedule, sock->sock, + silc_server_rekey_callback, sock, 0, 1, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); } /* This routine can be used to send a packet to table of clients provided @@ -513,11 +540,11 @@ silc_server_packet_send_to_channel_real(SilcServer server, block_len = cipher ? silc_cipher_get_block_len(cipher) : 0; if (channel_message) - packet->padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + - packet->src_id_len + - packet->dst_id_len), block_len); + SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + + packet->src_id_len + + packet->dst_id_len), block_len, packet->padlen); else - packet->padlen = SILC_PACKET_PADLEN(packet->truelen, block_len); + SILC_PACKET_PADLEN(packet->truelen, block_len, packet->padlen); /* Put the data to buffer, assemble and encrypt the packet. The packet is encrypted with normal session key shared with the client, unless @@ -1045,6 +1072,12 @@ void silc_server_send_private_message(SilcServer server, /* Send the packet */ silc_server_packet_send_real(server, dst_sock, FALSE); + + /* Check for mandatory rekey */ + if (sequence == SILC_SERVER_REKEY_THRESHOLD) + silc_schedule_task_add(server->schedule, dst_sock->sock, + silc_server_rekey_callback, dst_sock, 0, 1, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); } /* Sends current motd to client */ @@ -1237,14 +1270,13 @@ void silc_server_send_notify_cmode(SilcServer server, const char *passphrase, SilcPublicKey founder_key) { - SilcBuffer idp; - unsigned char mode[4], *key = NULL; - SilcUInt32 key_len = 0; + SilcBuffer idp, fkey = NULL; + unsigned char mode[4]; idp = silc_id_payload_encode((void *)id, id_type); SILC_PUT32_MSB(mode_mask, mode); if (founder_key) - key = silc_pkcs_public_key_encode(founder_key, &key_len); + fkey = silc_pkcs_public_key_payload_encode(founder_key); silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id, SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE, @@ -1254,8 +1286,8 @@ void silc_server_send_notify_cmode(SilcServer server, hmac, hmac ? strlen(hmac) : 0, passphrase, passphrase ? strlen(passphrase) : 0, - key, key_len); - silc_free(key); + fkey ? fkey->data : NULL, fkey ? fkey->len : 0); + silc_buffer_free(fkey), silc_buffer_free(idp); } @@ -1272,15 +1304,14 @@ void silc_server_send_notify_cumode(SilcServer server, SilcClientID *target, SilcPublicKey founder_key) { - SilcBuffer idp1, idp2; - unsigned char mode[4], *key = NULL; - SilcUInt32 key_len = 0; + SilcBuffer idp1, idp2, fkey = NULL; + unsigned char mode[4]; idp1 = silc_id_payload_encode((void *)id, id_type); idp2 = silc_id_payload_encode((void *)target, SILC_ID_CLIENT); SILC_PUT32_MSB(mode_mask, mode); if (founder_key) - key = silc_pkcs_public_key_encode(founder_key, &key_len); + fkey = silc_pkcs_public_key_payload_encode(founder_key); silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id, SILC_ID_CHANNEL, @@ -1288,8 +1319,8 @@ void silc_server_send_notify_cumode(SilcServer server, idp1->data, idp1->len, mode, 4, idp2->data, idp2->len, - key, key_len); - silc_free(key); + fkey ? fkey->data : NULL, fkey ? fkey->len : 0); + silc_buffer_free(fkey); silc_buffer_free(idp1); silc_buffer_free(idp2); } @@ -1917,6 +1948,12 @@ void silc_server_relay_packet(SilcServer server, silc_buffer_pull(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len + packet->dst_id_len + packet->padlen); + + /* Check for mandatory rekey */ + if (sequence == SILC_SERVER_REKEY_THRESHOLD) + silc_schedule_task_add(server->schedule, dst_sock->sock, + silc_server_rekey_callback, dst_sock, 0, 1, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); } /* Routine used to send the connection authentication packet. */ diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 502f3cba..5656be0b 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -43,7 +43,6 @@ SILC_TASK_CALLBACK(silc_server_free_client_data_timeout); SILC_TASK_CALLBACK(silc_server_timeout_remote); SILC_TASK_CALLBACK(silc_server_channel_key_rekey); SILC_TASK_CALLBACK(silc_server_failure_callback); -SILC_TASK_CALLBACK(silc_server_rekey_callback); SILC_TASK_CALLBACK(silc_server_get_stats); /* Allocates a new SILC server object. This has to be done before the server @@ -4233,10 +4232,9 @@ void silc_server_announce_get_channel_users(SilcServer server, SilcChannelClientEntry chl; SilcHashTableList htl; SilcBuffer chidp, clidp, csidp; - SilcBuffer tmp; + SilcBuffer tmp, fkey = NULL; int len; - unsigned char mode[4], *fkey = NULL; - SilcUInt32 fkey_len = 0; + unsigned char mode[4]; char *hmac; SILC_LOG_DEBUG(("Start")); @@ -4248,7 +4246,7 @@ void silc_server_announce_get_channel_users(SilcServer server, SILC_PUT32_MSB(channel->mode, mode); hmac = channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : NULL; if (channel->founder_key) - fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len); + fkey = silc_pkcs_public_key_payload_encode(channel->founder_key); tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CMODE_CHANGE, 6, csidp->data, csidp->len, @@ -4258,7 +4256,8 @@ void silc_server_announce_get_channel_users(SilcServer server, channel->passphrase, channel->passphrase ? strlen(channel->passphrase) : 0, - fkey, fkey_len); + fkey ? fkey->data : NULL, + fkey ? fkey->len : 0); len = tmp->len; *channel_modes = silc_buffer_realloc(*channel_modes, @@ -4270,9 +4269,8 @@ void silc_server_announce_get_channel_users(SilcServer server, silc_buffer_put(*channel_modes, tmp->data, tmp->len); silc_buffer_pull(*channel_modes, len); silc_buffer_free(tmp); - silc_free(fkey); + silc_buffer_free(fkey); fkey = NULL; - fkey_len = 0; /* Now find all users on the channel */ silc_hash_table_list(channel->user_list, &htl); @@ -4299,12 +4297,13 @@ void silc_server_announce_get_channel_users(SilcServer server, /* CUMODE notify for mode change on the channel */ SILC_PUT32_MSB(chl->mode, mode); if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && channel->founder_key) - fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len); + fkey = silc_pkcs_public_key_payload_encode(channel->founder_key); tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4, csidp->data, csidp->len, mode, sizeof(mode), clidp->data, clidp->len, - fkey, fkey_len); + fkey ? fkey->data : NULL, + fkey ? fkey->len : 0); len = tmp->len; *channel_users_modes = silc_buffer_realloc(*channel_users_modes, @@ -4317,9 +4316,8 @@ void silc_server_announce_get_channel_users(SilcServer server, silc_buffer_put(*channel_users_modes, tmp->data, tmp->len); silc_buffer_pull(*channel_users_modes, len); silc_buffer_free(tmp); - silc_free(fkey); + silc_buffer_free(fkey); fkey = NULL; - fkey_len = 0; silc_buffer_free(clidp); } silc_hash_table_list_reset(&htl); @@ -5011,7 +5009,7 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server, /* A timeout callback for the re-key. We will be the initiator of the re-key protocol. */ -SILC_TASK_CALLBACK(silc_server_rekey_callback) +SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback) { SilcServer server = app_context; SilcSocketConnection sock = (SilcSocketConnection)context; diff --git a/apps/silcd/server_backup.c b/apps/silcd/server_backup.c index 12479fff..88da61f8 100644 --- a/apps/silcd/server_backup.c +++ b/apps/silcd/server_backup.c @@ -333,6 +333,12 @@ void silc_server_backup_broadcast(SilcServer server, /* Now actually send the packet */ silc_server_packet_send_real(server, sock, FALSE); + + /* Check for mandatory rekey */ + if (idata->psn_send == SILC_SERVER_REKEY_THRESHOLD) + silc_schedule_task_add(server->schedule, sender->sock, + silc_server_rekey_callback, sender, 0, 1, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); } } diff --git a/apps/silcd/server_internal.h b/apps/silcd/server_internal.h index 1fb5201e..406d4338 100644 --- a/apps/silcd/server_internal.h +++ b/apps/silcd/server_internal.h @@ -152,6 +152,9 @@ typedef struct { SilcUInt32 failure; } *SilcServerFailureContext; +/* Rekey must be performed at the lastest when this many packets is sent */ +#define SILC_SERVER_REKEY_THRESHOLD 0xfffffe00 + /* Macros */ /* Return pointer to the primary router connection */ @@ -228,6 +231,7 @@ do { \ /* Prototypes */ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final); +SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback); void silc_server_watcher_list_destroy(void *key, void *context, void *user_context); diff --git a/apps/silcd/server_query.c b/apps/silcd/server_query.c index cf309e77..dd79c597 100644 --- a/apps/silcd/server_query.c +++ b/apps/silcd/server_query.c @@ -1573,6 +1573,8 @@ SilcBuffer silc_server_query_reply_attrs(SilcServer server, silc_strncat(service.address, sizeof(service.address), server->server_name, strlen(server->server_name)); service.status = !(client_entry->mode & SILC_UMODE_DETACHED); + if (client_entry->connection) + service.idle = time(NULL) - client_entry->data.last_receive; buffer = silc_attribute_payload_encode(buffer, attribute, SILC_ATTRIBUTE_FLAG_VALID, &service, sizeof(service)); diff --git a/doc/draft-riikonen-presence-attrs-01.nroff b/doc/draft-riikonen-presence-attrs-01.nroff index d938e68f..2736584a 100644 --- a/doc/draft-riikonen-presence-attrs-01.nroff +++ b/doc/draft-riikonen-presence-attrs-01.nroff @@ -8,7 +8,7 @@ .ds RF FORMFEED[Page %] .ds CF .ds LH Internet Draft -.ds RH 15 May 2002 +.ds RH XXX .ds CH .na .hy 0 @@ -16,8 +16,8 @@ .nf Network Working Group P. Riikonen Internet-Draft -draft-riikonen-presence-attrs-00.txt 15 May 2002 -Expires: 15 November 2002 +draft-riikonen-presence-attrs-00.txt XXX +Expires: XXX .in 3 @@ -306,8 +306,9 @@ multiple same attributes in the packet. 2 ATTRIBUTE_SERVICE This attribute indicates a service in the Internet that the user - is currently using or has logged in. The value of this attribute - is as follows: + is currently using or has logged in. It also shows when the user + started using the service, and how long user has been idle in the + service. The value of this attribute is as follows: Length Type Value 4 bytes integer Service Port (IANA specified) @@ -316,6 +317,9 @@ multiple same attributes in the packet. 0x01 (true) it means the user is online in the service. Set to 0x00 (false) when out of reach. + variable string Signon date and time, UTC date, format as + in ISO 8601 + 4 bytes integer Idle time 3 ATTRIBUTE_STATUS_MOOD @@ -542,7 +546,8 @@ multiple same attributes in the packet. The procedure producing the signature and encoding it are done in the manner defined in their respective definitions, see the - provided references. + provided references. Also the hash function used with the + signature procedure is defined by the public key/certificate type. 15 ATTRIBUTE_SERVER_DIGITAL_SIGNATURE @@ -628,4 +633,4 @@ Finland EMail: priikone@iki.fi -This Internet-Draft expires 15 November 2002 +This Internet-Draft expires XXX diff --git a/doc/draft-riikonen-silc-commands-04.nroff b/doc/draft-riikonen-silc-commands-04.nroff index b9359734..0dfaabeb 100644 --- a/doc/draft-riikonen-silc-commands-04.nroff +++ b/doc/draft-riikonen-silc-commands-04.nroff @@ -74,8 +74,9 @@ Table of Contents 1.1 Requirements Terminology .................................. 2 2 SILC Commands ................................................. 2 2.1 SILC Commands Syntax ...................................... 2 - 2.2 SILC Commands List ........................................ 4 - 2.3 SILC Command Status Payload ............................... 40 + 2.2 SILC Command Argument Idioms .............................. 2 + 2.3 SILC Commands List ........................................ 4 + 2.4 SILC Command Status Payload ............................... 40 3 SILC Status Types ............................................. 41 4 Security Considerations ....................................... 47 5 References .................................................... 47 @@ -196,18 +197,30 @@ Status messages: Every command reply also defines set of status message that it may return inside the . All status messages are defined in the section 2.3 SILC Command Status Payload - +The status messages defined with the command are recommendations. +It is possible to return other status messages not listes with +the command reply definition. .in 3 -Every command that has some kind of ID as argument (for example -) are actually ID Payloads, defined in [SILC2] that includes -the type of the ID, length of the ID and the actual ID data. This -way variable length ID's can be sent as arguments. Also note that -all passphrases that may be sent in commands MUST be UTF-8 [RFC2279] -encoded. .ti 0 -2.2 SILC Commands List +2.2 SILC Command Argument Idioms + +All commands that has an ID as argument (for example ) are +actually ID Payloads, defined in [SILC2] that includes the type of the +ID, length of the ID and the actual ID data. This way variable length +ID's can be sent as arguments. + +All passphrases that may be sent in commands as arguments MUST be +UTF-8 [RFC2279] encoded. + +All public keys and certificates that are sent as arguments are actually +Public Key Payloads [SILC2]. This way it is possible to send different +kind of public keys and certificate types as arguments. + + +.ti 0 +2.3 SILC Commands List This section lists all SILC commands, however, it is expected that a implementation and especially client implementation has many more @@ -660,15 +673,22 @@ List of all defined commands in SILC follows. 9 SILC_COMMAND_KILL - Max Arguments: 2 - Arguments: (1) (2) [] + Max Arguments: 3 + Arguments: (1) (2) [] + (3) [] + + This command can be used by SILC operators to remove a client from + SILC network. It also can be used by a normal client to remove + its own client from network by providing correct authentication + data. + + Router operator killing a client: - This command is used by SILC operators to remove a client from - SILC network. The removing has temporary effects and client may - reconnect to SILC network. The is the client to be - removed from SILC. The argument may be provided to - give to the removed client some information why it was removed - from the network. + The removing has temporary effects and client may reconnect to + SILC network. The is the client to be removed from SILC. + The argument may be provided to give to the removed client + some information why it was removed from the network. The killer + MUST have SILC operator privileges. When killing a client the router MUST first send notify type SILC_NOTIFY_TYPE_KILLED to all channels the client has joined. @@ -677,6 +697,19 @@ List of all defined commands in SILC follows. router. Finally, the router MUST send the same notify type directly to the client which was killed. + Normal client killing by authentication: + + When normal client executes this command the is the + destination client to be removed from the network. The client + MUST provide the which includes a digital signature + that MUST be verified with the public key of the client indicated + by . The MUST be local client to the server. + If the signature verification is successful the server sends + SILC_NOTIFY_TYPE_SIGNOFF to network and to the destination client. + The SILC_NOTIFY_TYPE_KILLED MUST NOT be used in this case. If the + verification fails the destination client remains in network. + The hash function used in computing is SHA1. + Reply messages to the command: Max Arguments: 1 @@ -829,12 +862,10 @@ List of all defined commands in SILC follows. The is the username set in the server configurations 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 or certificate - authentication data (data signed with private key). The public - key that server will use to verify the signature found in the - payload should be verified. It is recommended that the public - key is saved locally in the server and server would not use - any public keys received during the SKE. + for user on client's screen or it may be public key authentication + based on digital signatures. The public key used to verify the + signature should be locally saved in the server, and server should + not use public key received during the SKE to verify this signature. After changing the mode the server MUST send the notify type SILC_NOTIFY_TYPE_UMODE_CHANGE to its primary router. @@ -942,7 +973,7 @@ List of all defined commands in SILC follows. channel. The is formed by adding the ID Payloads one after the other. The is formed by adding 32 bit MSB first order values one after the other. The is the public key of the channel founder. + pubkey> is the public key (or certificate) of the channel founder. Client receives the channel key in the reply message as well inside . @@ -1943,7 +1974,7 @@ List of all defined commands in SILC follows. .ti 0 -2.3.1 SILC Command Status Payload +2.4 SILC Command Status Payload Command Status Payload is sent in command reply messages to indicate the status of the command. The payload is one of argument in the @@ -2014,7 +2045,7 @@ All Status messages are described in the next section. .ti 0 -2.3.2 SILC Status Types +3 SILC Status Types Status messages are returned in SILC protocol in command reply packet and in notify packet. The SILC_PACKET_COMMAND_REPLY is @@ -2296,11 +2327,21 @@ List of all defined status types: "Operation timed out". Operation or service request timed out, and thus was not processed. + 55 SILC_STATUS_ERR_UNSUPPORTED_PUBLIC_KEY + + "Unsupported public key type". The public key or certificate + type is not supported in this implementation. + + 56 SILC_STATUS_ERR_OPERATION_ALLOWED + + "Operation is not allowed". A operation, for example a command, + is not allowed or it's execution is not allowed. + .in 3 .ti 0 -3 Security Considerations +4 Security Considerations Security is central to the design of this protocol, and these security considerations permeate the specification. Common security considerations @@ -2310,7 +2351,7 @@ security of this protocol. .ti 0 -4 References +5 References [SILC1] Riikonen, P., "Secure Internet Live Conferencing (SILC), Protocol Specification", Internet Draft, May 2002. @@ -2382,7 +2423,7 @@ security of this protocol. .ti 0 -5 Author's Address +6 Author's Address .nf Pekka Riikonen diff --git a/doc/draft-riikonen-silc-flags-payloads-01.nroff b/doc/draft-riikonen-silc-flags-payloads-01.nroff index fb9d84b6..cb0240d8 100644 --- a/doc/draft-riikonen-silc-flags-payloads-01.nroff +++ b/doc/draft-riikonen-silc-flags-payloads-01.nroff @@ -8,7 +8,7 @@ .ds RF FORMFEED[Page %] .ds CF .ds LH Internet Draft -.ds RH 15 May 2002 +.ds RH XXX .ds CH .na .hy 0 @@ -16,14 +16,14 @@ .nf Network Working Group P. Riikonen Internet-Draft -draft-riikonen-flags-payloads-00.txt 15 May 2002 -Expires: 15 November 2002 +draft-riikonen-flags-payloads-01.txt XXX +Expires: 20 April 2003 .in 3 .ce 2 SILC Message Flag Payloads - + .ti 0 Status of this Memo @@ -178,7 +178,106 @@ additional payload. .ti 0 3.3 SILC_MESSAGE_FLAG_SIGNED -Not defined yet. +This flag is used to tell the recipient that the sent message is +digitally signed by the sender, and that the receipient should verify +the signature to verify the true authenticity of the received message. +All message payloads in SILC provides message authentication code (MAC) +which can be used to verify that the sender produced and sent the message. +Even so, signing messages digitally can be used to verify the authenticity +of the message when recipient trusts the sender. + +This flag defines a payload which is used to deliver the actual message, +sender's public key and the digital signature. The payload for +SILC_MESSAGE_FLAG_SIGNED is as follows: + +.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 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | +~ Message Payload ~ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | +~ Public Key Payload ~ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Signature Data Length | | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +| | +~ Signature Data ~ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.in 3 + +.ce +Figure 1: SILC_MESSAGE_FLAG_SIGNED Payload + + +.in 6 +o Message Payload (variable length) - This is a message payload + consisting of the encrypted message. When this flag is used + with channel messages it include Channel Message Payload, and + when used with private messages it include Private Message + Payload [SILC2]. + +o Public Key Payload (variable length) - This includes the + Public Key Payload which can be used to deliver the sender's + public key (or certificate). It also indicates the type of the + public key (or certificate) which the recipient use to identify + how the signature must be verified. This payload must always + be present but it is not required to include the public key + data. The Public Key Type field in the Public Key Payload + MUST be set to the correct type of the key, even if the + actual public key data is not included. + +o Signature Data Length (2 bytes) - Indicates the length of + the Signature Data field not including any other field. + +o Signature Data (variable lenght) - Includes the actual + signature data. The signature computation and encoding + is key type specific. See [SILC3] for all key types, and + their respective references of how to compute and encode + the signature. +.in 3 + +How the data is processed before it is signed is key type specific. +The actual data that to be signed MUST be the plaintext message +payload before encryption. For Channel Message Payload the data to +be signed is concatenation of Message Flags, Message Length, Message +Data, Padding Length, Padding, Initial Vector fields and the Public +Key Payload. Any other field is not included for signature data. +For Private Message Payload the data to be signed is concatenation +of Message Flags, Message Data Length, Message Data, Padding fields and +the Public Key Payload fields. Any other field is not included for +signature data. Before signing, the data is always processed, usually +hashed. The hash function to be used is defined in the key type +specific definitions. See the key type specific references in +[SILC3]. + +If the public key of the sender is included in the payload the +recipient SHOULD verify before accepting the public key. Recipient +SHOULD verify the signature before accepting a public key. With +certificates the certificate verification may be done before +verifying the signature. If the signature verification fails the +message should still be displayed. The end user should also be +notified about the result of the signature verification. + +To make the packet size smaller implementations may not want to +include the actual public key in all signed messages. Sending the +public key in the first message is usually sufficient. Subsequent +messages may include empty Public Key Payload with an indication of +the public key type. + +Implementations that do not support this flag can still process the +message payload in normal manner. These implementations merely ignore +rest of the data after the message payload. + +This flag MAY be masked with any other Message Flag including those that +define additional payloads. As long as the defined payload resides in +the data area of the message payload this flag may be masked with the +other flags. .ti 0 @@ -236,10 +335,12 @@ MIME fragmentation is defined for gateway usage, but in case of SILC the sender may also start sending fragmented MIME objects. This flag SHOULD NOT be masked with some other Message Flag that defines -payloads. Generally this sort of setting would be impossible for the -receiver to interpret. However, flags that does not define any specific -payloads MAY be masked with this flag as well. For example, this flag -could be masked also with SILC_MESSAGE_FLAG_REQUEST flag. +payloads for message data. Generally this sort of setting would be +impossible for the receiver to interpret. However, flags that does not +define any specific payloads MAY be masked with this flag as well. For +example, this flag could be masked also with SILC_MESSAGE_FLAG_REQUEST flag. +It also can be masked with SILC_MESSAGE_FLAG_SIGNED flag since it does not +define data specific payload. .ti 0 @@ -266,6 +367,9 @@ support S/MIME may be desired in some implementations. [SILC2] Riikonen, P., "SILC Packet Protocol", Internet Draft, May 2002. +[SILC3] Riikonen, P., "SILC Key Exchange and Authentication + Protocols", Internet Draft, May 2002. + [RFC2045] Freed, N., et al., "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", Standards Track, RFC 2045, November 1996. @@ -301,4 +405,4 @@ Finland EMail: priikone@iki.fi -This Internet-Draft expires 15 November 2002 +This Internet-Draft expires 20 April 2003 diff --git a/doc/draft-riikonen-silc-pp-06.nroff b/doc/draft-riikonen-silc-pp-06.nroff index 6c511ffa..24e7690e 100644 --- a/doc/draft-riikonen-silc-pp-06.nroff +++ b/doc/draft-riikonen-silc-pp-06.nroff @@ -231,11 +231,9 @@ packet. The packet data is the packet payloads defined in this protocol. The data payload area is always encrypted. The last part of SILC packet is the packet MAC that assures the -integrity of the packet. The MAC is always computed from the packet -before the encryption is applied to the packet. If compression is used -in the packet the MAC is computed after the compression has been -applied. The compression, on the other hand, is always applied before -encryption. See more details in the section 2.6 Packet MAC Generation. +integrity of the packet. See the section 2.6 Packet MAC Generation +for more information. If compsession is used the compsession is +always applied before encryption. All fields in all packet payloads are always in MSB (most significant byte first) order. @@ -1009,7 +1007,7 @@ The following diagram represents the Public Key Payload. | Public Key Length | Public Key Type | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | -~ Public Key of the party (or certificate) ~ +~ Public Key (or certificate) ~ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ .in 3 @@ -1214,8 +1212,8 @@ The following list of currently defined notify types. The format for notify arguments is same as in SILC commands described in [SILC4]. Note that all ID's sent in arguments are sent inside ID Payload. Also note that all passphrases that may be sent inside arguments MUST be -UTF-8 [RFC2279] encoded. - +UTF-8 [RFC2279] encoded. Also note that all public keys or certificates +sent in arguments are actually Public Key Payloads. .in 6 @@ -1870,11 +1868,16 @@ Private Message Payload is used to send private message between two clients (or users for that matter). The messages are sent only to the specified user and no other user inside SILC network is able to see the message. The message is protected by the session -key established by the SILC Key Exchange Protocol. However, -it is also possible to agree to use a private key to protect -just the private messages. See section 2.3.11 Private Message -Key Payload for detailed description of how to agree to use -specific key. +key established by the SILC Key Exchange Protocol. + +However, it is also possible to agree to use a private key to +protect just the private messages. It is for example possible to +perform Key Agreement between two clients. See section 2.3.20 +Key Agreement Payload how to perform key agreement. See also +section 2.3.12 Private Message Key Payload for another way of +using private keys with private messages. See [SILC1] section +4.6 for detailed description for private message key generation +procedure. If normal session key is used to protect the message, every server between the sender client and the receiving client MUST decrypt the @@ -1903,7 +1906,11 @@ diagram represents the Private Message Payload. | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | -~ Padding ~ +~ Padding ~ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | +~ MAC ~ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ .in 3 @@ -1921,11 +1928,10 @@ o Message Flags (2 bytes) - This field includes the Message same purpose. o Message Data Length (2 bytes) - Indicates the length of the - Message Data field, not includes any other field. + Message Data field, not including any other field. o Message Data (variable length) - The actual message to - the client. Rest of the packet is reserved for the message - data. + the client. o Padding (variable length) - This field is present only when the private message payload is encrypted with private @@ -1933,6 +1939,16 @@ o Padding (variable length) - This field is present only the payload multiple by eight (8), or by the block size of the cipher, which ever is larger. When encrypted with normal session keys, this field MUST NOT be included. + +o MAC (variable length) - This field is present only when + the private message payload is encrypted with private + message key. The MAC is computed from the Message Flags, + Message Data Length, Message Data and Padding fields in + that order. The MAC protects the integrity of the channel + message. The MAC is computed after encryption from the + ciphertext. Note that, this field is not encrypted and + thus not included in the padding calculation. When encrypted + with normal session keys, this field MUST NOT be included. .in 3 @@ -1950,7 +1966,7 @@ whether user wants to receive private message key. Note that there are other, more secure ways of exchanging private message keys in the SILC network. Instead of sending this payload it is possible to negotiate the private message key with SKE protocol using the Key -Agreement payload directly peer to peer. +Agreement payload directly peer to peer, see section 2.3.20. This payload may only be sent by client to another client. Server MUST NOT send this payload at any time. After sending this payload @@ -1979,6 +1995,12 @@ diagram represents the Private Message Key Payload. ~ Cipher Name ~ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| HMAC Name Length | | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +| | +~ HMAC Name ~ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ .in 3 .ce @@ -2003,8 +2025,16 @@ o Cipher Name (variable length) - Name of the cipher to use in the private message encryption. If this field does not exist then the default cipher of the SILC protocol is used. See the [SILC1] for defined ciphers. -.in 3 +o HMAC Name Length (2 bytes) - Indicates the length of the + HMAC Name field in the payload, not including any other + field. + +o HMAC Name (variable length) - Name of the HMAC to use + in the private message MAC computation. If this field does + not exist then the default HMAC of the SILC protocol is used. + See the [SILC1] for defined HMACs. +.in 3 .ti 0 @@ -2380,9 +2410,9 @@ After the key material has been received from the SKE protocol it is processed as the [SILC3] describes. If the key material is used as channel private key then the Sending Encryption Key, as defined in [SILC3] is used as the channel private key. Other key material must -be discarded. The [SILC1] defines the way to use the key material if -it is intended to be used as private message keys. Any other use for -the key material is undefined. +be discarded. The [SILC1] in section 4.6 defines the way to use the +key material if it is intended to be used as private message keys. +Any other use for the key material is undefined. .ti 0 @@ -2719,7 +2749,7 @@ However, rekey MUST be performed before the sequence number wraps and repeats from zero. Note that the sequence number is incremented only when MAC is computed for a packet. If packet is not encrypted and MAC is not computed then the sequence number is not incremented. Hence, the -sequence number is zero for first encrypted packet. +sequence number is zero for the very first encrypted packet. See [SILC1] for defined and allowed MAC algorithms. @@ -2736,16 +2766,20 @@ and between the Data Payload area. The padding for normal packets may be calculated as follows: .in 6 -padding length = 16 - (packet_length mod block_size) +padding_length = 16 - (packet_length mod block_size) +if (padding_length < 8) + padding_length += block_size .in 3 The `block_size' is the block size of the cipher. The maximum padding -length is 128 bytes, and minimum is 1 byte. The above algorithm calculates -the padding to the next block size, and always returns the padding -length between 1 - 16 bytes. However, implementations may add padding -up to 128 bytes. For example packets that include a passphrase or a -password for authentication purposes SHOULD pad the packet up to the -maximum padding length. +length is 128 bytes, and minimum is 8 bytes. For example, packets that +include a passphrase or a password for authentication purposes SHOULD +pad the packet up to the maximum padding length. The maximum padding +is calculated as follows: + +.in 6 +padding_length = 128 - (packet_length mod block_size) +.in 3 For special packets the padding calculation is different as special packets may be encrypted differently. In these cases the encrypted diff --git a/doc/draft-riikonen-silc-spec-06.nroff b/doc/draft-riikonen-silc-spec-06.nroff index 7c5cf250..0cf5c3ad 100644 --- a/doc/draft-riikonen-silc-spec-06.nroff +++ b/doc/draft-riikonen-silc-spec-06.nroff @@ -1457,7 +1457,7 @@ software version = [.[.]] Protocol version MAY provide both major and minor version. Currently implementations MUST set the protocol version and accept at least the -protocol version as SILC-1.1-. If new protocol version +protocol version as SILC-1.2-. If new protocol version causes incompatibilities with older version the version number MUST be incremented. The is incremented if new protocol version is fully incompatible. @@ -1472,8 +1472,8 @@ Thus, the version strings could be, for example: .in 6 SILC-1.1-2.0.2 SILC-1.0-1.2 -SILC-1.1-1.0.VendorXYZ -SILC-1.1-2.4.5 Vendor Limited +SILC-1.2-1.0.VendorXYZ +SILC-1.2-2.4.5 Vendor Limited .in 3 @@ -1987,7 +1987,7 @@ the MACs of the channel messages. The processing is as follows: The raw key data is the key data received in the Channel Key Payload. The hash() function is the hash function used in the HMAC of the channel. -Note that the server MUST also save the channel key. +Note that the server also MUST save the channel key. .ti 0 @@ -2038,12 +2038,13 @@ generated key, and the SILC_PACKET_KEY_AGREEMENT was not used, then the key material SHOULD be processed as defined in the [SILC3]. In the processing, however, the HASH, as defined in [SILC3] MUST be ignored. After processing the key material it is employed as defined -in [SILC3], however, the HMAC key material MUST be discarded. +in [SILC3]. If the key is pre-shared-key or randomly generated the implementations -SHOULD use the SILC protocol's mandatory cipher as the cipher. If the -SKE was used to negotiate key material the cipher was negotiated as well, -and may be different from default cipher. +SHOULD use the SILC protocol's mandatory cipher as the cipher, and the +mandatory HMAC as the HMAC. If the SKE was used to negotiate key material +the cipher was negotiated as well, and may be different from default +cipher and default HMAC. .ti 0 diff --git a/includes/silcincludes.h.in b/includes/silcincludes.h.in index 60a38238..16bbf4d2 100644 --- a/includes/silcincludes.h.in +++ b/includes/silcincludes.h.in @@ -221,6 +221,11 @@ extern "C" { #include "silcmp.h" #include "silcmath.h" +/* SILC util library includes */ +#include "silcmemory.h" +#include "silcbuffer.h" +#include "silcbuffmt.h" + /* Crypto library includes */ #include "silccipher.h" #include "silchash.h" @@ -228,17 +233,14 @@ extern "C" { #include "silcrng.h" #include "silcpkcs.h" -/* SILC util library includes */ +/* More SILC util library includes */ #include "silcmutex.h" #include "silcthread.h" #include "silcschedule.h" #include "silchashtable.h" #include "silclog.h" -#include "silcmemory.h" #include "silclist.h" #include "silcdlist.h" -#include "silcbuffer.h" -#include "silcbuffmt.h" #include "silcnet.h" #include "silcfileutil.h" #include "silcstrutil.h" diff --git a/includes/silcversion.h b/includes/silcversion.h index 9d184165..e8959c13 100644 --- a/includes/silcversion.h +++ b/includes/silcversion.h @@ -27,7 +27,7 @@ extern "C" { #include "version_internal.h" /* SILC Protocol version number */ -#define SILC_PROTOCOL_VERSION_CURRENT 11 +#define SILC_PROTOCOL_VERSION_CURRENT 12 /* SILC version string */ #define silc_version SILC_VERSION_STRING diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 62dba28c..631862a8 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -26,7 +26,6 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start); SILC_TASK_CALLBACK(silc_client_connect_to_server_second); SILC_TASK_CALLBACK(silc_client_connect_to_server_final); -SILC_TASK_CALLBACK(silc_client_rekey_callback); SILC_TASK_CALLBACK(silc_client_rekey_final); static bool silc_client_packet_parse(SilcPacketParserContext *parser_context, @@ -100,7 +99,7 @@ void silc_client_free(SilcClient client) the client ready to be run. One must call silc_client_run to run the client. Returns FALSE if error occured, TRUE otherwise. */ -int silc_client_init(SilcClient client) +bool silc_client_init(SilcClient client) { SILC_LOG_DEBUG(("Initializing client")); @@ -427,7 +426,7 @@ silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx) case then this function is not used at all. When the connecting is done the `connect' client operation is called. */ -int silc_client_connect_to_server(SilcClient client, +bool silc_client_connect_to_server(SilcClient client, SilcClientConnectionParams *params, int port, char *host, void *context) { @@ -890,7 +889,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final) is used directly only in special cases. Normal cases should use silc_server_packet_send. Returns < 0 on error. */ -int silc_client_packet_send_real(SilcClient client, +bool silc_client_packet_send_real(SilcClient client, SilcSocketConnection sock, bool force_send) { @@ -1402,6 +1401,12 @@ void silc_client_packet_send(SilcClient client, if (hmac) sequence = ((SilcClientConnection)sock->user_data)->internal->psn_send++; + + /* Check for mandatory rekey */ + if (sequence == SILC_CLIENT_REKEY_THRESHOLD) + silc_schedule_task_add(client->schedule, sock->sock, + silc_client_rekey_callback, sock, 0, 1, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); } block_len = cipher ? silc_cipher_get_block_len(cipher) : 0; @@ -1434,7 +1439,10 @@ void silc_client_packet_send(SilcClient client, packetdata.dst_id_len)); packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + packetdata.src_id_len + packetdata.dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len); + if (type == SILC_PACKET_CONNECTION_AUTH) + SILC_PACKET_PADLEN_MAX(packetdata.truelen, block_len, packetdata.padlen); + else + SILC_PACKET_PADLEN(packetdata.truelen, block_len, packetdata.padlen); /* Create the outgoing packet */ if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock, @@ -1832,7 +1840,7 @@ void silc_client_process_failure(SilcClient client, /* A timeout callback for the re-key. We will be the initiator of the re-key protocol. */ -SILC_TASK_CALLBACK(silc_client_rekey_callback) +SILC_TASK_CALLBACK_GLOBAL(silc_client_rekey_callback) { SilcSocketConnection sock = (SilcSocketConnection)context; SilcClientConnection conn = (SilcClientConnection)sock->user_data; diff --git a/lib/silcclient/client_channel.c b/lib/silcclient/client_channel.c index d4aac686..0eb263c1 100644 --- a/lib/silcclient/client_channel.c +++ b/lib/silcclient/client_channel.c @@ -1,16 +1,15 @@ /* - client_channel.c + client_channel.c - Author: Pekka Riikonen + Author: Pekka Riikonen - Copyright (C) 1997 - 2001 Pekka Riikonen + Copyright (C) 1997 - 2002 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - + the Free Software Foundation; version 2 of the License. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -40,7 +39,7 @@ void silc_client_send_channel_message(SilcClient client, SilcMessageFlags flags, unsigned char *data, SilcUInt32 data_len, - int force_send) + bool force_send) { int i; SilcSocketConnection sock; @@ -146,9 +145,9 @@ void silc_client_send_channel_message(SilcClient client, packetdata.dst_id_len); packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + packetdata.src_id_len + packetdata.dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + - packetdata.src_id_len + - packetdata.dst_id_len), block_len); + SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + + packetdata.src_id_len + + packetdata.dst_id_len), block_len, packetdata.padlen); /* Create the outgoing packet */ if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock, @@ -170,6 +169,12 @@ void silc_client_send_channel_message(SilcClient client, /* Now actually send the packet */ silc_client_packet_send_real(client, sock, force_send); + /* Check for mandatory rekey */ + if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD) + silc_schedule_task_add(client->schedule, sock->sock, + silc_client_rekey_callback, sock, 0, 1, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + out: silc_buffer_free(payload); silc_free(id_string); @@ -484,7 +489,7 @@ void silc_client_receive_channel_key(SilcClient client, currently it is not expected that the SKE key material would be used as channel private key. However, this API allows it. */ -int silc_client_add_channel_private_key(SilcClient client, +bool silc_client_add_channel_private_key(SilcClient client, SilcClientConnection conn, SilcChannelEntry channel, const char *name, @@ -571,7 +576,7 @@ int silc_client_add_channel_private_key(SilcClient client, after calling this to protect the channel messages. Returns FALSE on on error, TRUE otherwise. */ -int silc_client_del_channel_private_keys(SilcClient client, +bool silc_client_del_channel_private_keys(SilcClient client, SilcClientConnection conn, SilcChannelEntry channel) { @@ -607,7 +612,7 @@ int silc_client_del_channel_private_keys(SilcClient client, old channel key is used hereafter to protect the channel messages. This returns FALSE on error, TRUE otherwise. */ -int silc_client_del_channel_private_key(SilcClient client, +bool silc_client_del_channel_private_key(SilcClient client, SilcClientConnection conn, SilcChannelEntry channel, SilcChannelPrivateKey key) diff --git a/lib/silcclient/client_internal.h b/lib/silcclient/client_internal.h index 195f5cdf..09805480 100644 --- a/lib/silcclient/client_internal.h +++ b/lib/silcclient/client_internal.h @@ -155,6 +155,9 @@ typedef void (*SilcClientResumeSessionCallback)(SilcClient client, bool success, void *context); +/* Rekey must be performed at the lastest when this many packets is sent */ +#define SILC_CLIENT_REKEY_THRESHOLD 0xfffffe00 + /* Macros */ /* Registers generic task for file descriptor for reading from network and @@ -218,7 +221,7 @@ void silc_client_packet_send(SilcClient client, unsigned char *data, SilcUInt32 data_len, bool force_send); -int silc_client_packet_send_real(SilcClient client, +bool silc_client_packet_send_real(SilcClient client, SilcSocketConnection sock, bool force_send); void silc_client_ftp_free_sessions(SilcClient client, @@ -286,5 +289,6 @@ void silc_client_resume_session(SilcClient client, SilcBuffer silc_client_attributes_process(SilcClient client, SilcSocketConnection sock, SilcDList attrs); +SILC_TASK_CALLBACK_GLOBAL(silc_client_rekey_callback); #endif diff --git a/lib/silcclient/client_prvmsg.c b/lib/silcclient/client_prvmsg.c index dc7b14d4..d447e0af 100644 --- a/lib/silcclient/client_prvmsg.c +++ b/lib/silcclient/client_prvmsg.c @@ -1,16 +1,15 @@ /* - client_prvmsg.c + client_prvmsg.c - Author: Pekka Riikonen + Author: Pekka Riikonen - Copyright (C) 1997 - 2001 Pekka Riikonen + Copyright (C) 1997 - 2002 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - + the Free Software Foundation; version 2 of the License. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -39,7 +38,7 @@ void silc_client_send_private_message(SilcClient client, SilcMessageFlags flags, unsigned char *data, SilcUInt32 data_len, - int force_send) + bool force_send) { SilcSocketConnection sock; SilcBuffer buffer; @@ -57,6 +56,7 @@ void silc_client_send_private_message(SilcClient client, buffer = silc_private_message_payload_encode(flags, data_len, data, client_entry->send_key, + client_entry->hmac_send, client->rng); /* If we don't have private message specific key then private messages @@ -93,9 +93,9 @@ void silc_client_send_private_message(SilcClient client, packetdata.dst_id_len); packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + packetdata.src_id_len + packetdata.dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + - packetdata.src_id_len + - packetdata.dst_id_len), block_len); + SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + + packetdata.src_id_len + + packetdata.dst_id_len), block_len, packetdata.padlen); /* Create the outgoing packet */ if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock, @@ -106,7 +106,7 @@ void silc_client_send_private_message(SilcClient client, /* Encrypt the header and padding of the packet. */ silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++, - (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN + + (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN + packetdata.src_id_len + packetdata.dst_id_len + packetdata.padlen); @@ -115,6 +115,13 @@ void silc_client_send_private_message(SilcClient client, /* Now actually send the packet */ silc_client_packet_send_real(client, sock, force_send); + + /* Check for mandatory rekey */ + if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD) + silc_schedule_task_add(client->schedule, sock->sock, + silc_client_rekey_callback, sock, 0, 1, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + silc_free(packetdata.dst_id); out: @@ -153,6 +160,7 @@ void silc_client_private_message(SilcClient client, unsigned char *message; SilcUInt32 message_len; SilcCipher cipher = NULL; + SilcHmac hmac = NULL; if (packet->src_id_type != SILC_ID_CLIENT) goto out; @@ -182,14 +190,16 @@ void silc_client_private_message(SilcClient client, } cipher = remote_client->receive_key; - if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher) { + hmac = remote_client->hmac_receive; + if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher && !hmac) { silc_free(remote_id); return; } /* Parse the payload and decrypt it also if private message key is set */ payload = silc_private_message_payload_parse(packet->buffer->data, - packet->buffer->len, cipher); + packet->buffer->len, + cipher, hmac); if (!payload) { silc_free(remote_id); return; @@ -235,7 +245,7 @@ static void silc_client_private_message_key_cb(SilcClient client, SilcPacketContext *packet = (SilcPacketContext *)context; unsigned char *key; SilcUInt16 key_len; - unsigned char *cipher; + unsigned char *cipher = NULL, *hmac = NULL; int ret; if (!clients) @@ -244,7 +254,8 @@ static void silc_client_private_message_key_cb(SilcClient client, /* Parse the private message key payload */ ret = silc_buffer_unformat(packet->buffer, SILC_STR_UI16_NSTRING(&key, &key_len), - SILC_STR_UI16_STRING(&cipher), + SILC_STR_UI16_STRING_ALLOC(&cipher), + SILC_STR_UI16_STRING_ALLOC(&hmac), SILC_STR_END); if (!ret) goto out; @@ -254,7 +265,8 @@ static void silc_client_private_message_key_cb(SilcClient client, /* Now take the key in use */ if (!silc_client_add_private_message_key(client, conn, clients[0], - cipher, key, key_len, FALSE, TRUE)) + cipher, hmac, key, key_len, + FALSE, TRUE)) goto out; /* Print some info for application */ @@ -269,6 +281,8 @@ static void silc_client_private_message_key_cb(SilcClient client, clients[0]->username ? ")" : ""); out: + silc_free(cipher); + silc_free(hmac); silc_packet_context_free(packet); } @@ -301,9 +315,9 @@ void silc_client_private_message_key(SilcClient client, indicated by the `client_entry'. If the `key' is NULL and the boolean value `generate_key' is TRUE the library will generate random key. The `key' maybe for example pre-shared-key, passphrase or similar. - The `cipher' MAY be provided but SHOULD be NULL to assure that the - requirements of the SILC protocol are met. The API, however, allows - to allocate any cipher. + The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure + that the requirements of the SILC protocol are met. The API, however, + allows to allocate any cipher and HMAC. If `responder' is TRUE then the sending and receiving keys will be set according the client being the receiver of the private key. If @@ -317,14 +331,15 @@ void silc_client_private_message_key(SilcClient client, Returns FALSE if the key is already set for the `client_entry', TRUE otherwise. */ -int silc_client_add_private_message_key(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - char *cipher, - unsigned char *key, - SilcUInt32 key_len, - bool generate_key, - bool responder) +bool silc_client_add_private_message_key(SilcClient client, + SilcClientConnection conn, + SilcClientEntry client_entry, + const char *cipher, + const char *hmac, + unsigned char *key, + SilcUInt32 key_len, + bool generate_key, + bool responder) { unsigned char private_key[32]; SilcUInt32 len; @@ -339,15 +354,20 @@ int silc_client_add_private_message_key(SilcClient client, if (!cipher) cipher = SILC_DEFAULT_CIPHER; + if (!hmac) + hmac = SILC_DEFAULT_HMAC; - /* Check the requested cipher */ + /* Check the requested cipher and HMAC */ if (!silc_cipher_is_supported(cipher)) return FALSE; + if (!silc_hmac_is_supported(hmac)) + return FALSE; /* Generate key if not provided */ if (generate_key == TRUE) { len = 32; - for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng); + for (i = 0; i < len; i++) + private_key[i] = silc_rng_get_byte_fast(client->rng); key = private_key; key_len = len; client_entry->generated = TRUE; @@ -364,9 +384,11 @@ int silc_client_add_private_message_key(SilcClient client, != SILC_SKE_STATUS_OK) return FALSE; - /* Allocate the ciphers */ + /* Allocate the cipher and HMAC */ silc_cipher_alloc(cipher, &client_entry->send_key); silc_cipher_alloc(cipher, &client_entry->receive_key); + silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send); + silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive); /* Set the keys */ if (responder == TRUE) { @@ -376,6 +398,10 @@ int silc_client_add_private_message_key(SilcClient client, silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key, keymat->enc_key_len); silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv); + silc_hmac_set_key(client_entry->hmac_send, keymat->receive_hmac_key, + keymat->hmac_key_len); + silc_hmac_set_key(client_entry->hmac_receive, keymat->send_hmac_key, + keymat->hmac_key_len); } else { silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key, keymat->enc_key_len); @@ -383,6 +409,10 @@ int silc_client_add_private_message_key(SilcClient client, silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key, keymat->enc_key_len); silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv); + silc_hmac_set_key(client_entry->hmac_send, keymat->send_hmac_key, + keymat->hmac_key_len); + silc_hmac_set_key(client_entry->hmac_receive, keymat->receive_hmac_key, + keymat->hmac_key_len); } /* Free the key material */ @@ -394,15 +424,16 @@ int silc_client_add_private_message_key(SilcClient client, /* Same as above but takes the key material from the SKE key material structure. This structure is received if the application uses the silc_client_send_key_agreement to negotiate the key material. The - `cipher' SHOULD be provided as it is negotiated also in the SKE - protocol. */ - -int silc_client_add_private_message_key_ske(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - char *cipher, - SilcSKEKeyMaterial *key, - bool responder) + `cipher' and `hmac' SHOULD be provided as it is negotiated also in + the SKE protocol. */ + +bool silc_client_add_private_message_key_ske(SilcClient client, + SilcClientConnection conn, + SilcClientEntry client_entry, + const char *cipher, + const char *hmac, + SilcSKEKeyMaterial *key, + bool responder) { assert(client && client_entry); @@ -412,14 +443,20 @@ int silc_client_add_private_message_key_ske(SilcClient client, if (!cipher) cipher = SILC_DEFAULT_CIPHER; + if (!hmac) + hmac = SILC_DEFAULT_HMAC; - /* Check the requested cipher */ + /* Check the requested cipher and HMAC */ if (!silc_cipher_is_supported(cipher)) return FALSE; + if (!silc_hmac_is_supported(hmac)) + return FALSE; - /* Allocate the ciphers */ + /* Allocate the cipher and HMAC */ silc_cipher_alloc(cipher, &client_entry->send_key); silc_cipher_alloc(cipher, &client_entry->receive_key); + silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send); + silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive); /* Set the keys */ if (responder == TRUE) { @@ -429,6 +466,10 @@ int silc_client_add_private_message_key_ske(SilcClient client, silc_cipher_set_key(client_entry->receive_key, key->send_enc_key, key->enc_key_len); silc_cipher_set_iv(client_entry->receive_key, key->send_iv); + silc_hmac_set_key(client_entry->hmac_send, key->receive_hmac_key, + key->hmac_key_len); + silc_hmac_set_key(client_entry->hmac_receive, key->send_hmac_key, + key->hmac_key_len); } else { silc_cipher_set_key(client_entry->send_key, key->send_enc_key, key->enc_key_len); @@ -436,6 +477,10 @@ int silc_client_add_private_message_key_ske(SilcClient client, silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key, key->enc_key_len); silc_cipher_set_iv(client_entry->receive_key, key->receive_iv); + silc_hmac_set_key(client_entry->hmac_send, key->send_hmac_key, + key->hmac_key_len); + silc_hmac_set_key(client_entry->hmac_receive, key->receive_hmac_key, + key->hmac_key_len); } return TRUE; @@ -451,15 +496,15 @@ int silc_client_add_private_message_key_ske(SilcClient client, through the SILC network. The packet is protected using normal session keys. */ -int silc_client_send_private_message_key(SilcClient client, +bool silc_client_send_private_message_key(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry, - int force_send) + bool force_send) { SilcSocketConnection sock; SilcBuffer buffer; - int cipher_len; - const char *cipher; + int cipher_len, hmac_len; + const char *cipher, *hmac; assert(client && conn && client_entry); @@ -471,6 +516,8 @@ int silc_client_send_private_message_key(SilcClient client, cipher = silc_cipher_get_name(client_entry->send_key); cipher_len = strlen(cipher); + hmac = silc_hmac_get_name(client_entry->hmac_send); + hmac_len = strlen(hmac); /* Create private message key payload */ buffer = silc_buffer_alloc(2 + client_entry->key_len); @@ -482,6 +529,9 @@ int silc_client_send_private_message_key(SilcClient client, SILC_STR_UI_SHORT(cipher_len), SILC_STR_UI_XNSTRING(cipher, cipher_len), + SILC_STR_UI_SHORT(hmac_len), + SILC_STR_UI_XNSTRING(hmac, + hmac_len), SILC_STR_END); /* Send the packet */ @@ -497,7 +547,7 @@ int silc_client_send_private_message_key(SilcClient client, after this to protect the private messages with the remote `client_entry' client. Returns FALSE on error, TRUE otherwise. */ -int silc_client_del_private_message_key(SilcClient client, +bool silc_client_del_private_message_key(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry) { diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index 66e51786..f765408c 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -845,9 +845,9 @@ SILC_CLIENT_CMD_FUNC(kill) SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClient client = cmd->client; SilcClientConnection conn = cmd->conn; - SilcBuffer buffer, idp; + SilcBuffer buffer, idp, auth = NULL; SilcClientEntry target; - char *nickname = NULL; + char *nickname = NULL, *comment = NULL; if (!cmd->conn) { SILC_NOT_CONNECTED(cmd->client, cmd->conn); @@ -857,7 +857,7 @@ SILC_CLIENT_CMD_FUNC(kill) if (cmd->argc < 2) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, - "Usage: /KILL []"); + "Usage: /KILL [] [-pubkey]"); COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } @@ -887,22 +887,35 @@ SILC_CLIENT_CMD_FUNC(kill) goto out; } + if (cmd->argc >= 3) { + if (strcasecmp(cmd->argv[2], "-pubkey")) + comment = cmd->argv[2]; + + if (!strcasecmp(cmd->argv[2], "-pubkey") || + (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) { + /* Encode the public key authentication payload */ + auth = silc_auth_public_key_auth_generate(cmd->client->public_key, + cmd->client->private_key, + cmd->client->rng, + client->sha1hash, + target->id, SILC_ID_CLIENT); + } + } + /* Send the KILL command to the server */ idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT); - if (cmd->argc == 2) - buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, - ++conn->cmd_ident, 1, - 1, idp->data, idp->len); - else - buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, - ++conn->cmd_ident, 2, - 1, idp->data, idp->len, - 2, cmd->argv[2], - strlen(cmd->argv[2])); + buffer = + silc_command_payload_encode_va(SILC_COMMAND_KILL, + ++conn->cmd_ident, 3, + 1, idp->data, idp->len, + 2, comment, comment ? strlen(comment) : 0, + 3, auth ? auth->data : NULL, + auth ? auth->len : 0); silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(idp); + silc_buffer_free(auth); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -996,7 +1009,7 @@ SILC_CLIENT_CMD_FUNC(ping) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; - SilcBuffer buffer; + SilcBuffer buffer, idp; void *id; int i; @@ -1006,14 +1019,15 @@ SILC_CLIENT_CMD_FUNC(ping) goto out; } + idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER); + /* Send the command */ buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1, - 1, conn->remote_id_data, - silc_id_get_len(conn->remote_id, - SILC_ID_SERVER)); + 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); id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len, SILC_ID_SERVER); @@ -2548,7 +2562,7 @@ void silc_client_commands_register(SilcClient client) SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3); SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3); SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2); - SILC_CLIENT_CMD(kill, KILL, "KILL", 3); + SILC_CLIENT_CMD(kill, KILL, "KILL", 4); SILC_CLIENT_CMD(info, INFO, "INFO", 2); SILC_CLIENT_CMD(stats, STATS, "STATS", 0); SILC_CLIENT_CMD(ping, PING, "PING", 2); diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index e1c03f38..67d8f666 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -1770,10 +1770,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(getkey) SilcClientEntry client_entry; SilcServerID *server_id = NULL; SilcServerEntry server_entry; - SilcSKEPKType type; - unsigned char *tmp, *pk; + unsigned char *tmp; SilcUInt32 len; - SilcUInt16 pk_len; SilcIdType id_type; SilcPublicKey public_key = NULL; @@ -1800,15 +1798,9 @@ SILC_CLIENT_CMD_REPLY_FUNC(getkey) /* Get the public key payload */ tmp = silc_argument_get_arg_type(cmd->args, 3, &len); if (tmp) { - /* 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) - if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) - public_key = NULL; - } + if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key)) + public_key = NULL; + } id_type = silc_id_payload_get_type(idp); if (id_type == SILC_ID_CLIENT) { diff --git a/lib/silcclient/silcclient.h b/lib/silcclient/silcclient.h index 156cdf1d..62a788a3 100644 --- a/lib/silcclient/silcclient.h +++ b/lib/silcclient/silcclient.h @@ -215,7 +215,9 @@ struct SilcClientEntryStruct { /* Private message keys */ SilcCipher send_key; /* Private message key for sending */ SilcCipher receive_key; /* Private message key for receiving */ - unsigned char *key; /* Set only if appliation provided the + SilcHmac hmac_send; /* Private mesage key HMAC for sending */ + SilcHmac hmac_receive; /* Private mesage key HMAC for receiving */ + unsigned char *key; /* Set only if application provided the key material. NULL if the library generated the key. */ SilcUInt32 key_len; /* Key length */ @@ -853,7 +855,7 @@ void silc_client_free(SilcClient client); * * SYNOPSIS * - * int silc_client_init(SilcClient client); + * bool silc_client_init(SilcClient client); * * DESCRIPTION * @@ -862,7 +864,7 @@ void silc_client_free(SilcClient client); * client. Returns FALSE if error occurred, TRUE otherwise. * ***/ -int silc_client_init(SilcClient client); +bool silc_client_init(SilcClient client); /****f* silcclient/SilcClientAPI/silc_client_run * @@ -952,7 +954,7 @@ typedef struct { * * SYNOPSIS * - * int silc_client_connect_to_server(SilcClient client, + * bool silc_client_connect_to_server(SilcClient client, * SilcClientConnectionParams *params, * int port, char *host, void *context); * @@ -969,9 +971,9 @@ typedef struct { * If the `params' is provided they are used by the routine. * ***/ -int silc_client_connect_to_server(SilcClient client, - SilcClientConnectionParams *params, - int port, char *host, void *context); +bool silc_client_connect_to_server(SilcClient client, + SilcClientConnectionParams *params, + int port, char *host, void *context); /****f* silcclient/SilcClientAPI/silc_client_add_connection * @@ -1107,7 +1109,7 @@ void silc_client_close_connection(SilcClient client, * SilcMessageFlags flags, * unsigned char *data, * SilcUInt32 data_len, - * int force_send); + * bool_force_send); * * DESCRIPTION * @@ -1132,7 +1134,7 @@ void silc_client_send_channel_message(SilcClient client, SilcMessageFlags flags, unsigned char *data, SilcUInt32 data_len, - int force_send); + bool force_send); /****f* silcclient/SilcClientAPI/silc_client_send_private_message * @@ -1144,7 +1146,7 @@ void silc_client_send_channel_message(SilcClient client, * SilcMessageFlags flags, * unsigned char *data, * SilcUInt32 data_len, - * int force_send); + * bool force_send); * * DESCRIPTION * @@ -1163,7 +1165,7 @@ void silc_client_send_private_message(SilcClient client, SilcMessageFlags flags, unsigned char *data, SilcUInt32 data_len, - int force_send); + bool force_send); /* Client and Channel entry retrieval (idlist.c) */ @@ -1533,7 +1535,7 @@ SilcChannelUser silc_client_on_channel(SilcChannelEntry channel, * * SYNOPSIS * - * void silc_client_command_call(SilcClient client, + * bool silc_client_command_call(SilcClient client, * SilcClientConnection conn, * const char *command_line, ...); * @@ -1664,14 +1666,15 @@ void silc_client_command_pending(SilcClientConnection conn, * * SYNOPSIS * - * int silc_client_add_private_message_key(SilcClient client, - * SilcClientConnection conn, - * SilcClientEntry client_entry, - * char *cipher, - * unsigned char *key, - * SilcUInt32 key_len, - * bool generate_key, - * bool responder); + * bool silc_client_add_private_message_key(SilcClient client, + * SilcClientConnection conn, + * SilcClientEntry client_entry, + * const char *cipher, + * const char *hmac, + * unsigned char *key, + * SilcUInt32 key_len, + * bool generate_key, + * bool responder); * * DESCRIPTION * @@ -1680,9 +1683,9 @@ void silc_client_command_pending(SilcClientConnection conn, * indicated by the `client_entry'. If the `key' is NULL and the boolean * value `generate_key' is TRUE the library will generate random key. * The `key' maybe for example pre-shared-key, passphrase or similar. - * The `cipher' MAY be provided but SHOULD be NULL to assure that the - * requirements of the SILC protocol are met. The API, however, allows - * to allocate any cipher. + * The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure + * that the requirements of the SILC protocol are met. The API, however, + * allows to allocate any cipher and HMAC. * * If `responder' is TRUE then the sending and receiving keys will be * set according the client being the receiver of the private key. If @@ -1697,48 +1700,52 @@ void silc_client_command_pending(SilcClientConnection conn, * otherwise. * ***/ -int silc_client_add_private_message_key(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - char *cipher, - unsigned char *key, - SilcUInt32 key_len, - bool generate_key, - bool responder); +bool silc_client_add_private_message_key(SilcClient client, + SilcClientConnection conn, + SilcClientEntry client_entry, + const char *cipher, + const char *hmac, + unsigned char *key, + SilcUInt32 key_len, + bool generate_key, + bool responder); /****f* silcclient/SilcClientAPI/silc_client_add_private_message_key_ske * * SYNOPSIS * - * int silc_client_add_private_message_key_ske(SilcClient client, - * SilcClientConnection conn, - * SilcClientEntry client_entry, - * char *cipher, - * SilcSKEKeyMaterial *key); + * bool + * silc_client_add_private_message_key_ske(SilcClient client, + * SilcClientConnection conn, + * SilcClientEntry client_entry, + * const char *cipher, + * const char *hmac, + * SilcSKEKeyMaterial *key); * * DESCRIPTION * * Same as silc_client_add_private_message_key but takes the key material * from the SKE key material structure. This structure is received if * the application uses the silc_client_send_key_agreement to negotiate - * the key material. The `cipher' SHOULD be provided as it is negotiated - * also in the SKE protocol. + * the key material. The `cipher' and `hmac' SHOULD be provided as it is + * negotiated also in the SKE protocol. * ***/ -int silc_client_add_private_message_key_ske(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - char *cipher, - SilcSKEKeyMaterial *key, - bool responder); +bool silc_client_add_private_message_key_ske(SilcClient client, + SilcClientConnection conn, + SilcClientEntry client_entry, + const char *cipher, + const char *hmac, + SilcSKEKeyMaterial *key, + bool responder); /****f* silcclient/SilcClientAPI/silc_client_del_private_message_key * * SYNOPSIS * - * int silc_client_del_private_message_key(SilcClient client, - * SilcClientConnection conn, - * SilcClientEntry client_entry); + * bool silc_client_del_private_message_key(SilcClient client, + * SilcClientConnection conn, + * SilcClientEntry client_entry); * * DESCRIPTION * @@ -1747,9 +1754,9 @@ int silc_client_add_private_message_key_ske(SilcClient client, * client. Returns FALSE on error, TRUE otherwise. * ***/ -int silc_client_del_private_message_key(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry); +bool silc_client_del_private_message_key(SilcClient client, + SilcClientConnection conn, + SilcClientEntry client_entry); /****f* silcclient/SilcClientAPI/silc_client_list_private_message_keys * @@ -1800,14 +1807,14 @@ void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys, * * SYNOPSIS * - * int silc_client_add_channel_private_key(SilcClient client, - * SilcClientConnection conn, - * SilcChannelEntry channel, - * const char *name, - * char *cipher, - * char *hmac, - * unsigned char *key, - * SilcUInt32 key_len); + * bool silc_client_add_channel_private_key(SilcClient client, + * SilcClientConnection conn, + * SilcChannelEntry channel, + * const char *name, + * char *cipher, + * char *hmac, + * unsigned char *key, + * SilcUInt32 key_len); * * DESCRIPTION * @@ -1841,22 +1848,22 @@ void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys, * as channel private key. However, this API allows it. * ***/ -int silc_client_add_channel_private_key(SilcClient client, - SilcClientConnection conn, - SilcChannelEntry channel, - const char *name, - char *cipher, - char *hmac, - unsigned char *key, - SilcUInt32 key_len); +bool silc_client_add_channel_private_key(SilcClient client, + SilcClientConnection conn, + SilcChannelEntry channel, + const char *name, + char *cipher, + char *hmac, + unsigned char *key, + SilcUInt32 key_len); /****f* silcclient/SilcClientAPI/silc_client_del_channel_private_keys * * SYNOPSIS * - * int silc_client_del_channel_private_keys(SilcClient client, - * SilcClientConnection conn, - * SilcChannelEntry channel); + * bool silc_client_del_channel_private_keys(SilcClient client, + * SilcClientConnection conn, + * SilcChannelEntry channel); * * DESCRIPTION * @@ -1865,15 +1872,15 @@ int silc_client_add_channel_private_key(SilcClient client, * on error, TRUE otherwise. * ***/ -int silc_client_del_channel_private_keys(SilcClient client, - SilcClientConnection conn, - SilcChannelEntry channel); +bool silc_client_del_channel_private_keys(SilcClient client, + SilcClientConnection conn, + SilcChannelEntry channel); /****f* silcclient/SilcClientAPI/silc_client_del_channel_private_key * * SYNOPSIS * - * int silc_client_del_channel_private_key(SilcClient client, + * bool silc_client_del_channel_private_key(SilcClient client, * SilcClientConnection conn, * SilcChannelEntry channel, * SilcChannelPrivateKey key); @@ -1888,10 +1895,10 @@ int silc_client_del_channel_private_keys(SilcClient client, * on error, TRUE otherwise. * ***/ -int silc_client_del_channel_private_key(SilcClient client, - SilcClientConnection conn, - SilcChannelEntry channel, - SilcChannelPrivateKey key); +bool silc_client_del_channel_private_key(SilcClient client, + SilcClientConnection conn, + SilcChannelEntry channel, + SilcChannelPrivateKey key); /****f* silcclient/SilcClientAPI/silc_client_list_channel_private_keys * diff --git a/lib/silccore/silcargument.c b/lib/silccore/silcargument.c index 2b69f80b..58ddbed9 100644 --- a/lib/silccore/silcargument.c +++ b/lib/silccore/silcargument.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2001 Pekka Riikonen + Copyright (C) 2001 - 2002 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/lib/silccore/silcargument.h b/lib/silccore/silcargument.h index bb38c75f..305b6902 100644 --- a/lib/silccore/silcargument.h +++ b/lib/silccore/silcargument.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2001 Pekka Riikonen + Copyright (C) 2001 - 2002 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/lib/silccore/silcattrs.c b/lib/silccore/silcattrs.c index 067d8c67..fee2c395 100644 --- a/lib/silccore/silcattrs.c +++ b/lib/silccore/silcattrs.c @@ -70,18 +70,23 @@ silc_attribute_payload_encode_int(SilcAttribute attribute, case SILC_ATTRIBUTE_SERVICE: { SilcAttributeObjService *service = object; + int len2; if (object_size != sizeof(*service)) return NULL; len = strlen(service->address); - str = silc_malloc(7 + len); - if (!str) - return NULL; - SILC_PUT32_MSB(service->port, str); - SILC_PUT16_MSB(len, str + 4); - memcpy(str + 6, service->address, len); - str[6 + len] = service->status; - object = str; - object_size = 7 + len; + len2 = strlen(service->signon); + tmpbuf = silc_buffer_alloc_size(13 + len + len2); + silc_buffer_format(tmpbuf, + SILC_STR_UI_INT(service->port), + SILC_STR_UI_SHORT(len), + SILC_STR_UI_XNSTRING(service->address, len), + SILC_STR_UI_CHAR(service->status), + SILC_STR_UI_SHORT(len2), + SILC_STR_UI_XNSTRING(service->signon, len2), + SILC_STR_UI_INT(service->idle), + SILC_STR_END); + object = tmpbuf->data; + object_size = tmpbuf->len; } break; @@ -481,18 +486,32 @@ bool silc_attribute_get_object(SilcAttributePayload payload, case SILC_ATTRIBUTE_SERVICE: { SilcAttributeObjService *service = object; + SilcBufferStruct buf; + SilcUInt16 addr_len, signon_len; + char *addr, *signon; + int res; if (object_size != sizeof(*service)) break; - if (payload->data_len < 7) + if (payload->data_len < 13) break; - SILC_GET32_MSB(service->port, payload->data); - SILC_GET16_MSB(len, payload->data + 4); - if (payload->data_len < 7 + len) + silc_buffer_set(&buf, payload->data, payload->data_len); + res = silc_buffer_unformat(&buf, + SILC_STR_UI_INT(&service->port), + SILC_STR_UI16_NSTRING(&addr, &addr_len), + SILC_STR_UI_CHAR(&service->status), + SILC_STR_UI16_NSTRING(&signon, &signon_len), + SILC_STR_UI_INT(&service->idle), + SILC_STR_END); + if (res == -1) break; - memcpy(service->address, payload->data + 6, - (len < sizeof(service->address) - 1 ? len : + memset(service->address, 0, sizeof(service->address)); + memset(service->signon, 0, sizeof(service->signon)); + memcpy(service->address, addr, + (addr_len < sizeof(service->address) - 1 ? addr_len : sizeof(service->address) - 1)); - service->status = payload->data[6 + len] ? TRUE : FALSE; + memcpy(service->signon, signon, + (signon_len < sizeof(service->signon) - 1 ? signon_len : + sizeof(service->signon) - 1)); ret = TRUE; } break; diff --git a/lib/silccore/silcattrs.h b/lib/silccore/silcattrs.h index b9097bc6..afcc0194 100644 --- a/lib/silccore/silcattrs.h +++ b/lib/silccore/silcattrs.h @@ -390,6 +390,8 @@ unsigned char *silc_attribute_get_verify_data(SilcDList attrs, */ typedef struct { SilcUInt32 port; /* IANA specified service port */ + SilcUInt32 idle; /* Idle time in the service */ + char signon[64]; /* Signon date and time (UTC) */ char address[256]; /* service address */ bool status; /* online status (TRUE present in service) */ } SilcAttributeObjService; diff --git a/lib/silccore/silcauth.c b/lib/silccore/silcauth.c index aea21a99..c93f02df 100644 --- a/lib/silccore/silcauth.c +++ b/lib/silccore/silcauth.c @@ -1,6 +1,6 @@ /* - silcauth.c + silcauth.c Author: Pekka Riikonen @@ -8,8 +8,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -21,6 +20,8 @@ #include "silcincludes.h" #include "silcauth.h" +#include "silcchannel_i.h" +#include "silcprivate_i.h" /****************************************************************************** @@ -224,6 +225,7 @@ silc_auth_public_key_encode_data(SilcPublicKey public_key, if (ret_len) *ret_len = buf->len; + silc_buffer_clear(buf); silc_buffer_free(buf); silc_free(id_data); silc_free(pk); @@ -265,7 +267,7 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key, return NULL; /* Allocate PKCS object */ - if (!silc_pkcs_alloc(public_key->name, &pkcs)) { + if (!silc_pkcs_alloc(private_key->name, &pkcs)) { memset(tmp, 0, tmp_len); silc_free(tmp); return NULL; @@ -538,3 +540,319 @@ SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload) { return payload->port; } + +/****************************************************************************** + + SILC_MESSAGE_FLAG_SIGNED Payload + +******************************************************************************/ + +/* The SILC_MESSAGE_FLAG_SIGNED Payload */ +struct SilcSignedPayloadStruct { + SilcUInt16 pk_len; + SilcUInt16 pk_type; + SilcUInt16 sign_len; + unsigned char *pk_data; + unsigned char *sign_data; +}; + +/* Encodes the data to be signed to SILC_MESSAGE_FLAG_SIGNED Payload */ + +static SilcBuffer +silc_signed_payload_encode_data(const unsigned char *message_payload, + SilcUInt32 message_payload_len, + unsigned char *pk, + SilcUInt32 pk_len, SilcUInt32 pk_type) +{ + SilcBuffer sign; + + sign = silc_buffer_alloc_size(message_payload_len + 4 + pk_len); + if (!sign) + return NULL; + + silc_buffer_format(sign, + SILC_STR_UI_XNSTRING(message_payload, + message_payload_len), + SILC_STR_UI_SHORT(pk_len), + SILC_STR_UI_SHORT(pk_type), + SILC_STR_END); + + if (pk && pk_len) { + silc_buffer_pull(sign, message_payload_len + 4); + silc_buffer_format(sign, + SILC_STR_UI_XNSTRING(pk, pk_len), + SILC_STR_END); + silc_buffer_push(sign, message_payload_len + 4); + } + + return sign; +} + +/* Parses the SILC_MESSAGE_FLAG_SIGNED Payload */ + +SilcSignedPayload silc_signed_payload_parse(const unsigned char *data, + SilcUInt32 data_len) +{ + SilcSignedPayload sig; + SilcBufferStruct buffer; + int ret; + + SILC_LOG_DEBUG(("Parsing SILC_MESSAGE_FLAG_SIGNED Payload")); + + silc_buffer_set(&buffer, (unsigned char *)data, data_len); + sig = silc_calloc(1, sizeof(*sig)); + if (!sig) + return NULL; + + /* Parse the payload */ + ret = silc_buffer_unformat(&buffer, + SILC_STR_UI_SHORT(&sig->pk_len), + SILC_STR_UI_SHORT(&sig->pk_type), + SILC_STR_END); + if (ret == -1 || sig->pk_len > data_len - 4) { + silc_signed_payload_free(sig); + return NULL; + } + + silc_buffer_pull(&buffer, 4); + ret = silc_buffer_unformat(&buffer, + SILC_STR_UI_XNSTRING_ALLOC(&sig->pk_data, + sig->pk_len), + SILC_STR_UI16_NSTRING_ALLOC(&sig->sign_data, + &sig->sign_len), + SILC_STR_END); + if (ret == -1) { + silc_signed_payload_free(sig); + return NULL; + } + silc_buffer_push(&buffer, 4); + + /* Signature must be provided */ + if (sig->sign_len < 1) { + silc_signed_payload_free(sig); + return NULL; + } + + return sig; +} + +/* Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the digital + signature. */ + +SilcBuffer silc_signed_payload_encode(const unsigned char *message_payload, + SilcUInt32 message_payload_len, + SilcPublicKey public_key, + SilcPrivateKey private_key, + SilcHash hash, + bool include_public_key) +{ + SilcBuffer buffer, sign; + SilcPKCS pkcs; + unsigned char auth_data[2048]; + SilcUInt32 auth_len; + unsigned char *pk = NULL; + SilcUInt32 pk_len = 0; + SilcUInt16 pk_type; + + if (!message_payload || !message_payload_len || !private_key || !hash) + return NULL; + if (include_public_key && !public_key) + return NULL; + + if (include_public_key) + pk = silc_pkcs_public_key_encode(public_key, &pk_len); + + /* Now we support only SILC style public key */ + pk_type = SILC_SKE_PK_TYPE_SILC; + + /* Encode the data to be signed */ + sign = silc_signed_payload_encode_data(message_payload, + message_payload_len, + pk, pk_len, pk_type); + if (!sign) { + silc_free(pk); + return NULL; + } + + /* Sign the buffer */ + + /* Allocate PKCS object */ + if (!silc_pkcs_alloc(private_key->name, &pkcs)) { + silc_buffer_clear(sign); + silc_buffer_free(sign); + silc_free(pk); + return NULL; + } + silc_pkcs_private_key_set(pkcs, private_key); + + /* Compute the hash and the signature. */ + if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 || + !silc_pkcs_sign_with_hash(pkcs, hash, sign->data, sign->len, auth_data, + &auth_len)) { + silc_buffer_clear(sign); + silc_buffer_free(sign); + silc_pkcs_free(pkcs); + silc_free(pk); + return NULL; + } + + /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */ + + buffer = silc_buffer_alloc_size(4 + pk_len + 2 + auth_len); + if (!buffer) { + silc_buffer_clear(sign); + silc_buffer_free(sign); + silc_pkcs_free(pkcs); + memset(auth_data, 0, sizeof(auth_data)); + silc_free(pk); + return NULL; + } + + silc_buffer_format(sign, + SILC_STR_UI_SHORT(pk_len), + SILC_STR_UI_SHORT(pk_type), + SILC_STR_END); + + if (pk_len && pk) { + silc_buffer_pull(sign, 4); + silc_buffer_format(sign, + SILC_STR_UI_XNSTRING(pk, pk_len), + SILC_STR_END); + silc_buffer_push(sign, 4); + } + + silc_buffer_pull(sign, 4 + pk_len); + silc_buffer_format(sign, + SILC_STR_UI_SHORT(auth_len), + SILC_STR_UI_XNSTRING(auth_data, auth_len), + SILC_STR_END); + silc_buffer_push(sign, 4 + pk_len); + + memset(auth_data, 0, sizeof(auth_data)); + silc_pkcs_free(pkcs); + silc_buffer_clear(sign); + silc_buffer_free(sign); + silc_free(pk); + + return buffer; +} + +/* Free the payload */ + +void silc_signed_payload_free(SilcSignedPayload sig) +{ + if (sig) { + memset(sig->sign_data, 0, sig->sign_len); + silc_free(sig->sign_data); + silc_free(sig->pk_data); + silc_free(sig); + } +} + +/* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */ + +int silc_signed_payload_verify(SilcSignedPayload sig, + bool channel_message, + void *message_payload, + SilcPublicKey remote_public_key, + SilcHash hash) +{ + int ret = SILC_AUTH_FAILED; +#if 0 + SilcBuffer sign; + SilcPKCS pkcs; + + if (!sig || !remote_public_key || !hash) + return ret; + + /* Generate the signature verification data */ + if (channel_message) { + SilcChannelMessagePayload chm = + (SilcChannelMessagePayload)message_payload; + SilcBuffer tmp; + + /* Encode Channel Message Payload */ + tmp = silc_buffer_alloc_size(6 + chm->data_len + chm->pad_len + + chm->iv_len); + silc_buffer_format(tmp, + SILC_STR_UI_SHORT(chm->flags), + SILC_STR_UI_SHORT(chm->data_len), + SILC_STR_UI_XNSTRING(chm->data, chm->data_len), + SILC_STR_UI_SHORT(chm->pad_len), + SILC_STR_UI_XNSTRING(chm->pad, chm->pad_len), + SILC_STR_UI_XNSTRING(chm->iv, chm->iv_len), + SILC_STR_END); + + sign = silc_signed_payload_encode_data(tmp->data, tmp->len, + sig->pk_data, sig->pk_len, + sig->pk_type); + silc_buffer_clear(tmp); + silc_buffer_free(tmp); + } else { + SilcPrivateMessagePayload prm = + (SilcPrivateMessagePayload)message_payload; + SilcBuffer tmp; + + /* Encode Private Message Payload */ + tmp = silc_buffer_alloc_size(4 + prm->data_len + + SILC_PRIVATE_MESSAGE_PAD(4 + prm->data_len)); + silc_buffer_format(tmp, + SILC_STR_UI_SHORT(prm->flags), + SILC_STR_UI_SHORT(prm->message_len), + SILC_STR_UI_XNSTRING(prm->message, prm->message_len), + SILC_STR_END); + + sign = silc_signed_payload_encode_data(tmp->data, tmp->len, + sig->pk_data, sig->pk_len, + sig->pk_type); + silc_buffer_clear(tmp); + silc_buffer_free(tmp); + } + + if (!sign) + return ret; + + /* Allocate PKCS object */ + if (!silc_pkcs_alloc(remote_public_key->name, &pkcs)) { + silc_buffer_clear(sign); + silc_buffer_free(sign); + return ret; + } + silc_pkcs_public_key_set(pkcs, remote_public_key); + + /* Verify the authentication data */ + if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->sign_data + payload->sign_len, + sign->data, sign->len)) { + + silc_buffer_clear(sign); + silc_buffer_free(sign); + silc_pkcs_free(pkcs); + SILC_LOG_DEBUG(("Signature verification failed")); + return ret; + } + + ret = SILC_AUTH_OK; + + silc_buffer_clear(sign); + silc_buffer_free(sign); + silc_pkcs_free(pkcs); + + SILC_LOG_DEBUG(("Signature verification successful")); + +#endif + return ret; +} + +/* Return the public key from the payload */ + +SilcPublicKey silc_signed_payload_get_public_key(SilcSignedPayload sig) +{ + SilcPublicKey pk; + + if (!sig->pk_data || !silc_pkcs_public_key_decode(sig->pk_data, + sig->pk_len, &pk)) + return NULL; + + return pk; +} diff --git a/lib/silccore/silcauth.h b/lib/silccore/silcauth.h index f6662132..be30c1a6 100644 --- a/lib/silccore/silcauth.h +++ b/lib/silccore/silcauth.h @@ -1,16 +1,15 @@ /* - silcauth.h - + silcauth.h + Author: Pekka Riikonen - - Copyright (C) 2001 Pekka Riikonen - + + Copyright (C) 2001 - 2002 Pekka Riikonen + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - + the Free Software Foundation; version 2 of the License. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -33,44 +32,16 @@ * used by client to agree on key material usually with another client * in the network. * + * This interface defines also the SILC_MESSAGE_FLAG_SIGNED Payload, + * which defines how channel messages and private messages can be digitally + * signed. This interface provides the payload parsing, encoding, + * signature computing and signature verification routines. + * ***/ #ifndef SILCAUTH_H #define SILCAUTH_H -/****s* silccore/SilcAuthAPI/SilcAuthPayload - * - * NAME - * - * typedef struct SilcAuthPayloadStruct *SilcAuthPayload; - * - * - * DESCRIPTION - * - * This context is the actual Authentication Payload and is allocated - * by silc_auth_payload_parse and given as argument usually to all - * silc_auth_payload_* functions. It is freed by silc_auth_payload_free - * function. - * - ***/ -typedef struct SilcAuthPayloadStruct *SilcAuthPayload; - -/****s* silccore/SilcAuthAPI/SilcKeyAgreementPayload - * - * NAME - * - * typedef struct SilcKeyAgreementPayloadStruct *SilcKeyAgreementPayload; - * - * DESCRIPTION - * - * This context is the actual Key Agreement Payload and is allocated - * by silc_key_agreement_payload_parse and given as argument usually to all - * silc_key_agreement_* functions. It is freed by the function - * silc_key_agreement_payload_free. - * - ***/ -typedef struct SilcKeyAgreementPayloadStruct *SilcKeyAgreementPayload; - /****d* silccore/SilcAuthAPI/SilcAuthMethod * * NAME @@ -97,7 +68,22 @@ typedef SilcUInt16 SilcAuthMethod; #define SILC_AUTH_FAILED 1 /***/ -/* Prototypes */ +/****s* silccore/SilcAuthAPI/SilcAuthPayload + * + * NAME + * + * typedef struct SilcAuthPayloadStruct *SilcAuthPayload; + * + * + * DESCRIPTION + * + * This context is the actual Authentication Payload and is allocated + * by silc_auth_payload_parse and given as argument usually to all + * silc_auth_payload_* functions. It is freed by silc_auth_payload_free + * function. + * + ***/ +typedef struct SilcAuthPayloadStruct *SilcAuthPayload; /****f* silccore/SilcAuthAPI/silc_auth_payload_parse * @@ -308,6 +294,22 @@ bool silc_auth_verify_data(const unsigned char *payload, SilcUInt32 auth_data_len, SilcHash hash, const void *id, SilcIdType type); +/****s* silccore/SilcAuthAPI/SilcKeyAgreementPayload + * + * NAME + * + * typedef struct SilcKeyAgreementPayloadStruct *SilcKeyAgreementPayload; + * + * DESCRIPTION + * + * This context is the actual Key Agreement Payload and is allocated + * by silc_key_agreement_payload_parse and given as argument usually to all + * silc_key_agreement_* functions. It is freed by the function + * silc_key_agreement_payload_free. + * + ***/ +typedef struct SilcKeyAgreementPayloadStruct *SilcKeyAgreementPayload; + /****f* silccore/SilcAuthAPI/silc_key_agreement_payload_parse * * SYNOPSIS @@ -383,4 +385,126 @@ char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload); ***/ SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload); +/****s* silccore/SilcAuthAPI/SilcSignedPayload + * + * NAME + * + * typedef struct SilcSignedPayloadStruct *SilcSignedPayload; + * + * + * DESCRIPTION + * + * This context represents the SILC_MESSAGE_FLAG_SIGNED Payload which + * is used with channel messages and private messages to indicate that + * the message is digitally signed. This payload may include the + * message sender's public key and it includes the digital signature. + * This payload MUST NOT be used in any other context except with + * channel and private message sending and reception. + * + ***/ +typedef struct SilcSignedPayloadStruct *SilcSignedPayload; + +/****f* silccore/SilcAuthAPI/silc_signed_payload_parse + * + * SYNOPSIS + * + * SilcSignedPayload silc_signed_payload_parse(const unsigned char *data, + * SilcUInt32 data_len); + * + * DESCRIPTION + * + * Parses the SILC_MESSAGE_FLAG_SIGNED Payload from the `data' of + * length of `data_len' bytes. The `data' must be payload without + * the actual message payload. Returns the parsed payload or NULL + * on error. Caller must free the returned payload. + * + ***/ +SilcSignedPayload silc_signed_payload_parse(const unsigned char *data, + SilcUInt32 data_len); + +/****f* silccore/SilcAuthAPI/silc_signed_payload_encode + * + * SYNOPSIS + * + * SilcBuffer + * silc_signed_payload_encode(const unsigned char *message_payload, + * SilcUInt32 message_payload_len, + * SilcPublicKey public_key, + * SilcPrivateKey private_key, + * bool include_public_key); + * + * DESCRIPTION + * + * Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the + * digital signature. The `message_payload' is the message data that + * is used in the signature computation. The encoding of the buffer + * is specified in the SILC protocol. If `include_public_key' is + * TRUE then the public key included in the payload. The `private_key' + * is used to produce the signature. This function returns the encoded + * payload with the signature or NULL on error. Caller must free the + * returned buffer. + * + ***/ +SilcBuffer silc_signed_payload_encode(const unsigned char *message_payload, + SilcUInt32 message_payload_len, + SilcPublicKey public_key, + SilcPrivateKey private_key, + SilcHash hash, + bool include_public_key); + +/****f* silccore/SilcAuthAPI/silc_signed_payload_free + * + * SYNOPSIS + * + * void silc_signed_payload_free(SilcSignedPayload sig); + * + * DESCRIPTION + * + * Frees the SILC_MESSAGE_FLAG_SIGNED Payload. + * + ***/ +void silc_signed_payload_free(SilcSignedPayload sig); + +/****f* silccore/SilcAuthAPI/silc_signed_payload_verify + * + * SYNOPSIS + * + * int silc_signed_payload_verify(SilcSignedPayload sig, + * bool channel_message, + * void *message_payload, + * SilcPublicKey remote_public_key, + * SilcHash hash); + * + * DESCRIPTION + * + * This routine can be used to verify the signature found in + * SILC_MESSAGE_FLAG_SIGNED Payload. The `remote_public_key' is the + * sender's public key and is used in the verification. If the + * `channel_message' is TRUE then `message_payload' must include the + * SilcChannelMessagePayload. If it is FALSE then it must include + * SilcPrivateMessagePayload. This returns SILC_AUTH_OK if the + * signature verification was successful. + * + ***/ +int silc_signed_payload_verify(SilcSignedPayload sig, + bool channel_message, + void *message_payload, + SilcPublicKey remote_public_key, + SilcHash hash); + +/****f* silccore/SilcAuthAPI/silc_signed_payload_get_public_key + * + * SYNOPSIS + * + * SilcPublicKey silc_signed_payload_get_public_key(SilcSignedPayload sig); + * + * DESCRIPTION + * + * Returns the public key from the SILC_MESSAGE_FLAG_SIGNED Payload + * or NULL if it does not include public key. The caller must free + * the returned public key. + * + ***/ +SilcPublicKey silc_signed_payload_get_public_key(SilcSignedPayload sig); + #endif diff --git a/lib/silccore/silcchannel.c b/lib/silccore/silcchannel.c index e87cf934..adc857ee 100644 --- a/lib/silccore/silcchannel.c +++ b/lib/silccore/silcchannel.c @@ -23,22 +23,7 @@ #include "silcincludes.h" #include "silcchannel.h" - -/****************************************************************************** - - Channel Payload - -******************************************************************************/ - -/* Channel Message Payload structure. Contents of this structure is parsed - from SILC packets. */ -struct SilcChannelPayloadStruct { - SilcUInt16 name_len; - unsigned char *channel_name; - SilcUInt16 id_len; - unsigned char *channel_id; - SilcUInt32 mode; -}; +#include "silcchannel_i.h" /* Parses channel payload returning new channel payload structure. */ @@ -231,32 +216,6 @@ SilcUInt32 silc_channel_get_mode(SilcChannelPayload payload) ******************************************************************************/ -/* Calculates padding length for message payload */ -#define SILC_CHANNEL_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16)) - -/* Header length plus maximum padding length */ -#define SILC_CHANNEL_MESSAGE_HLEN 6 + 16 - -/* Returns the data length that fits to the packet. If data length is too - big it will be truncated to fit to the payload. */ -#define SILC_CHANNEL_MESSAGE_DATALEN(data_len, header_len) \ - ((data_len + SILC_CHANNEL_MESSAGE_HLEN + header_len) > \ - SILC_PACKET_MAX_LEN ? \ - data_len - ((data_len + SILC_CHANNEL_MESSAGE_HLEN + header_len) - \ - SILC_PACKET_MAX_LEN) : data_len) - -/* Channel Message Payload structure. Contents of this structure is parsed - from SILC packets. */ -struct SilcChannelMessagePayloadStruct { - SilcMessageFlags flags; - SilcUInt16 data_len; - unsigned char *data; - SilcUInt16 pad_len; - unsigned char *pad; - unsigned char *mac; - unsigned char *iv; -}; - /* Decrypts the channel message payload. First push the IV out of the packet. The IV is used in the decryption process. Then decrypt the message. After decyprtion, take the MAC from the decrypted packet, @@ -305,18 +264,9 @@ bool silc_channel_message_payload_decrypt(unsigned char *data, silc_hmac_update(hmac, data + (data_len - iv_len), iv_len); silc_hmac_final(hmac, mac2, &mac_len); if (memcmp(mac, mac2, mac_len)) { -#if 1 - /* Backwards support for old mac checking, remove in 1.0 */ - silc_hmac_make(hmac, dst, (data_len - iv_len - mac_len), mac2, &mac_len); - if (memcmp(mac, mac2, mac_len)) { -#endif - SILC_LOG_DEBUG(("Channel message MACs does not match")); silc_free(dst); return FALSE; -#if 1 - } -#endif } SILC_LOG_DEBUG(("MAC is Ok")); @@ -381,6 +331,8 @@ silc_channel_message_payload_parse(unsigned char *payload, goto err; } + newp->iv_len = iv_len; + return newp; err: @@ -434,7 +386,7 @@ bool silc_channel_message_payload_encrypt(unsigned char *data, encrypted separately from other parts of the packet padding must be applied to the payload. */ -SilcBuffer silc_channel_message_payload_encode(SilcUInt16 flags, +SilcBuffer silc_channel_message_payload_encode(SilcMessageFlags flags, SilcUInt16 data_len, const unsigned char *data, SilcUInt16 iv_len, @@ -544,17 +496,6 @@ unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload) ******************************************************************************/ -/* Channel Key Payload structrue. Channel keys are parsed from SILC - packets into this structure. */ -struct SilcChannelKeyPayloadStruct { - SilcUInt16 id_len; - unsigned char *id; - SilcUInt16 cipher_len; - unsigned char *cipher; - SilcUInt16 key_len; - unsigned char *key; -}; - /* Parses channel key payload returning new channel key payload structure */ SilcChannelKeyPayload diff --git a/lib/silccore/silcchannel.h b/lib/silccore/silcchannel.h index fa471a42..23dfccf1 100644 --- a/lib/silccore/silcchannel.h +++ b/lib/silccore/silcchannel.h @@ -357,7 +357,7 @@ bool silc_channel_message_payload_encrypt(unsigned char *data, * * SYNOPSIS * - * SilcBuffer silc_channel_message_payload_encode(SilcUInt16 flags, + * SilcBuffer silc_channel_message_payload_encode(SilcMessageFlags flags, * SilcUInt16 data_len, * const unsigned char *data, * SilcUInt16 iv_len, @@ -378,7 +378,7 @@ bool silc_channel_message_payload_encrypt(unsigned char *data, * the `rng' is used. * ***/ -SilcBuffer silc_channel_message_payload_encode(SilcUInt16 flags, +SilcBuffer silc_channel_message_payload_encode(SilcMessageFlags flags, SilcUInt16 data_len, const unsigned char *data, SilcUInt16 iv_len, diff --git a/lib/silccore/silcchannel_i.h b/lib/silccore/silcchannel_i.h new file mode 100644 index 00000000..372094d1 --- /dev/null +++ b/lib/silccore/silcchannel_i.h @@ -0,0 +1,95 @@ +/* + + silcchannel_i.h + + Author: Pekka Riikonen + + Copyright (C) 1997 - 2002 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#ifndef SILCCHANNEL_I_H +#define SILCCHANNEL_I_H + +#ifndef SILCCHANNEL_H +#error "Do not include internal header file directly" +#endif + +/****************************************************************************** + + Channel Payload + +******************************************************************************/ + +/* Channel Message Payload structure. Contents of this structure is parsed + from SILC packets. */ +struct SilcChannelPayloadStruct { + unsigned char *channel_name; + unsigned char *channel_id; + SilcUInt32 mode; + SilcUInt16 name_len; + SilcUInt16 id_len; +}; + + +/****************************************************************************** + + Channel Message Payload + +******************************************************************************/ + +/* Calculates padding length for message payload */ +#define SILC_CHANNEL_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16)) + +/* Header length plus maximum padding length */ +#define SILC_CHANNEL_MESSAGE_HLEN 6 + 16 + +/* Returns the data length that fits to the packet. If data length is too + big it will be truncated to fit to the payload. */ +#define SILC_CHANNEL_MESSAGE_DATALEN(data_len, header_len) \ + ((data_len + SILC_CHANNEL_MESSAGE_HLEN + header_len) > \ + SILC_PACKET_MAX_LEN ? \ + data_len - ((data_len + SILC_CHANNEL_MESSAGE_HLEN + header_len) - \ + SILC_PACKET_MAX_LEN) : data_len) + +/* Channel Message Payload structure. Contents of this structure is parsed + from SILC packets. */ +struct SilcChannelMessagePayloadStruct { + unsigned char *data; + unsigned char *pad; + unsigned char *mac; + unsigned char *iv; + SilcMessageFlags flags; + SilcUInt16 data_len; + SilcUInt16 pad_len; + SilcUInt16 iv_len; +}; + + +/****************************************************************************** + + Channel Key Payload + +******************************************************************************/ + +/* Channel Key Payload structrue. Channel keys are parsed from SILC + packets into this structure. */ +struct SilcChannelKeyPayloadStruct { + unsigned char *id; + unsigned char *cipher; + unsigned char *key; + SilcUInt16 id_len; + SilcUInt16 cipher_len; + SilcUInt16 key_len; +}; + +#endif /* SILCCHANNEL_I_H */ diff --git a/lib/silccore/silcpacket.c b/lib/silccore/silcpacket.c index c6cba515..fe768662 100644 --- a/lib/silccore/silcpacket.c +++ b/lib/silccore/silcpacket.c @@ -141,9 +141,10 @@ bool silc_packet_assemble(SilcPacketContext *packet, SilcRng rng, /* Calculate the length of the padding. The padding is calculated from the data that will be encrypted. */ if (!packet->padlen) { - packet->padlen = (packet->long_pad ? - SILC_PACKET_PADLEN_MAX(packet->truelen) : - SILC_PACKET_PADLEN(packet->truelen, block_len)); + if (packet->long_pad) + SILC_PACKET_PADLEN_MAX(packet->truelen, block_len, packet->padlen); + else + SILC_PACKET_PADLEN(packet->truelen, block_len, packet->padlen); } /* Now prepare the outgoing data buffer for packet sending and start diff --git a/lib/silccore/silcpacket.h b/lib/silccore/silcpacket.h index 3583e473..7d62a3b4 100644 --- a/lib/silccore/silcpacket.h +++ b/lib/silccore/silcpacket.h @@ -370,14 +370,18 @@ do { \ * * DESCRIPTION * - * Returns the length of the padding in the packet. This is used + * Calculates the length of the padding in the packet. This is used * by various library routines to determine needed padding length. * * SOURCE */ -#define SILC_PACKET_PADLEN(__packetlen, __blocklen) \ - SILC_PACKET_DEFAULT_PADLEN - (__packetlen) % \ - ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN) +#define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen) \ +do { \ + __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) % \ + ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \ + if (__padlen < 8) \ + __padlen = ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \ +} while(0) /***/ /****d* silccore/SilcPacketAPI/SILC_PACKET_PADLEN_MAX @@ -389,13 +393,16 @@ do { \ * DESCRIPTION * * Returns the length of the padding up to the maximum length, which - * is 128 butes. This is used by various library routines to determine + * is 128 bytes. This is used by various library routines to determine * needed padding length. * * SOURCE */ -#define SILC_PACKET_PADLEN_MAX(__packetlen) \ - SILC_PACKET_MAX_PADLEN - (__packetlen) % SILC_PACKET_MAX_PADLEN +#define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen) \ +do { \ + __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) % \ + ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \ +} while(0) /***/ /* Prototypes */ diff --git a/lib/silccore/silcprivate.c b/lib/silccore/silcprivate.c index 67cb967b..b90d0109 100644 --- a/lib/silccore/silcprivate.c +++ b/lib/silccore/silcprivate.c @@ -22,6 +22,7 @@ #include "silcincludes.h" #include "silcprivate.h" +#include "silcprivate_i.h" /****************************************************************************** @@ -29,67 +30,97 @@ ******************************************************************************/ -/* Calculates padding length for message payload */ -#define SILC_PRIVATE_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16)) - -/* Header length plus maximum padding length */ -#define SILC_PRIVATE_MESSAGE_HLEN 4 + 16 - -/* Returns the data length that fits to the packet. If data length is too - big it will be truncated to fit to the payload. */ -#define SILC_PRIVATE_MESSAGE_DATALEN(data_len) \ - ((data_len + SILC_PRIVATE_MESSAGE_HLEN) > SILC_PACKET_MAX_LEN ? \ - data_len - ((data_len + SILC_PRIVATE_MESSAGE_HLEN) - \ - SILC_PACKET_MAX_LEN) : data_len) - -/* Private Message Payload structure. Contents of this structure is parsed - from SILC packets. */ -struct SilcPrivateMessagePayloadStruct { - SilcUInt16 flags; - SilcUInt16 message_len; - unsigned char *message; -}; - /* Parses private message payload returning new private mesage payload structure. This also decrypts the message if the `cipher' is provided. */ SilcPrivateMessagePayload silc_private_message_payload_parse(unsigned char *payload, SilcUInt32 payload_len, - SilcCipher cipher) + SilcCipher cipher, + SilcHmac hmac) { SilcBufferStruct buffer; SilcPrivateMessagePayload newp; - int ret; + SilcUInt32 mac_len = 0, block_len, pad_len = 0; + unsigned char data[16], mac[32]; + int len, totlen; SILC_LOG_DEBUG(("Parsing private message payload")); silc_buffer_set(&buffer, payload, payload_len); - /* Decrypt the payload */ - if (cipher) - silc_cipher_decrypt(cipher, buffer.data, buffer.data, - buffer.len, silc_cipher_get_iv(cipher)); - newp = silc_calloc(1, sizeof(*newp)); if (!newp) return NULL; - /* Parse the Private Message Payload. Ignore the padding. */ - ret = silc_buffer_unformat(&buffer, + /* Decrypt the payload */ + if (cipher) { + /* Decrypt first block. This is to get the true length of the data in + payload. It is possible there is additional data after the message + payload with private messages. */ + block_len = silc_cipher_get_block_len(cipher); + if (block_len > buffer.len) + goto err; + silc_cipher_decrypt(cipher, buffer.data, data, block_len, + silc_cipher_get_iv(cipher)); + + /* Length of encrypted area */ + SILC_GET16_MSB(newp->message_len, data + 2); + totlen = 4 + newp->message_len; + pad_len = SILC_PRIVATE_MESSAGE_PAD(4 + newp->message_len); + totlen += pad_len; + + /* Sanity checks */ + if (totlen > buffer.len || newp->message_len < 1 || + newp->message_len > buffer.len - 4) { + SILC_LOG_DEBUG(("Incorrect private message payload in packet")); + goto err; + } + + /* Compute MAC for integrity check from the cipher text */ + if (hmac) { + SILC_LOG_DEBUG(("Checking private message MAC")); + silc_hmac_init(hmac); + silc_hmac_update(hmac, buffer.data, totlen); + silc_hmac_final(hmac, mac, &mac_len); + if (memcmp(mac, buffer.data + totlen, mac_len)) { + SILC_LOG_DEBUG(("Private message MAC does not match")); + goto err; + } + SILC_LOG_DEBUG(("MAC is Ok")); + } + + /* Now decrypt rest of the data */ + memcpy(buffer.data, data, block_len); + if (totlen - block_len > 0) + silc_cipher_decrypt(cipher, buffer.data + block_len, + buffer.data + block_len, totlen - block_len, + silc_cipher_get_iv(cipher)); + memset(data, 0, sizeof(data)); + } + + /* Parse the Private Message Payload. */ + len = silc_buffer_unformat(&buffer, SILC_STR_UI_SHORT(&newp->flags), SILC_STR_UI16_NSTRING_ALLOC(&newp->message, &newp->message_len), SILC_STR_END); - if (ret == -1) { - SILC_LOG_DEBUG(("Incorrect private message payload")); + if (len == -1 || newp->message_len < 1 || + newp->message_len > buffer.len - 4) { + SILC_LOG_DEBUG(("Incorrect private message payload in packet")); goto err; } - if ((newp->message_len < 1 || newp->message_len > buffer.len - 4)) { - SILC_LOG_DEBUG(("Incorrect private message payload in packet, " - "packet dropped")); - goto err; + /* Parse also padding and MAC */ + if (cipher) { + silc_buffer_pull(&buffer, 4 + newp->message_len); + len = silc_buffer_unformat(&buffer, + SILC_STR_UI_XNSTRING_ALLOC(&newp->pad, + pad_len), + SILC_STR_UI_XNSTRING_ALLOC(&newp->mac, + mac_len), + SILC_STR_END); + silc_buffer_push(&buffer, 4 + newp->message_len); } return newp; @@ -107,12 +138,13 @@ SilcBuffer silc_private_message_payload_encode(SilcUInt16 flags, SilcUInt16 data_len, const unsigned char *data, SilcCipher cipher, + SilcHmac hmac, SilcRng rng) { int i; SilcBuffer buffer; - SilcUInt32 len, pad_len = 0; - unsigned char pad[16]; + SilcUInt32 len, pad_len = 0, mac_len = 0; + unsigned char pad[16], mac[32]; SILC_LOG_DEBUG(("Encoding private message payload")); @@ -123,9 +155,15 @@ SilcBuffer silc_private_message_payload_encode(SilcUInt16 flags, /* Calculate length of padding. */ pad_len = SILC_PRIVATE_MESSAGE_PAD(len); len += pad_len; + mac_len = hmac ? silc_hmac_len(hmac) : 0; + len += mac_len; /* Generate padding */ - for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte(); + if (rng) { + for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng); + } else { + for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast(); + } } /* Allocate private message payload buffer */ @@ -144,8 +182,17 @@ SilcBuffer silc_private_message_payload_encode(SilcUInt16 flags, if (cipher) { /* Encrypt payload of the packet. */ silc_cipher_encrypt(cipher, buffer->data, buffer->data, - buffer->len, silc_cipher_get_iv(cipher)); + buffer->len - mac_len, silc_cipher_get_iv(cipher)); memset(pad, 0, sizeof(pad)); + + /* Compute MAC from the ciphertext */ + if (hmac) { + silc_hmac_init(hmac); + silc_hmac_update(hmac, buffer->data, buffer->len - mac_len); + silc_hmac_final(hmac, mac, &mac_len); + memcpy(buffer->data + (buffer->len - mac_len), mac, mac_len); + memset(mac, 0, sizeof(mac)); + } } return buffer; @@ -181,3 +228,11 @@ silc_private_message_get_message(SilcPrivateMessagePayload payload, return payload->message; } + +/* Return MAC. Caller knows its length */ + +unsigned char * +silc_private_message_get_mac(SilcPrivateMessagePayload payload) +{ + return payload->mac; +} diff --git a/lib/silccore/silcprivate.h b/lib/silccore/silcprivate.h index bede78e2..d776bf6d 100644 --- a/lib/silccore/silcprivate.h +++ b/lib/silccore/silcprivate.h @@ -57,18 +57,21 @@ typedef struct SilcPrivateMessagePayloadStruct *SilcPrivateMessagePayload; * SilcPrivateMessagePayload * silc_private_message_payload_parse(unsigned char *payload, * SilcUInt32 payload_len, - * SilcCipher cipher); + * SilcCipher cipher, + * SilcHmac hmac); * * DESCRIPTION * * Parses private message payload returning new private mesage payload * structure. This also decrypts the message if the `cipher' is provided. + * The data integrity is checked with `hmac'. * ***/ SilcPrivateMessagePayload silc_private_message_payload_parse(unsigned char *payload, SilcUInt32 payload_len, - SilcCipher cipher); + SilcCipher cipher, + SilcHmac hmac); /****f* silccore/SilcPrivateAPI/silc_private_message_payload_encode * @@ -78,20 +81,23 @@ silc_private_message_payload_parse(unsigned char *payload, * SilcUInt16 data_len, * const unsigned char *data, * SilcCipher cipher, + * SilcHmac hmac, * SilcRng rng); * * DESCRIPTION * * Encodes private message payload into a buffer and returns it. If - * the cipher is provided the packet is also encrypted here. It is provided - * if the private message private keys are used. If the `rng' is NULL - * then global RNG is used, if non-NULL then `rng' is used. + * the `cipher' is provided the packet is also encrypted here. It is + * provided if the private message private keys are used. If the `rng' + * is NULL then global RNG is used, if non-NULL then `rng' is used. + * The MAC for the message is computed with `hmac'. * ***/ SilcBuffer silc_private_message_payload_encode(SilcUInt16 flags, SilcUInt16 data_len, const unsigned char *data, SilcCipher cipher, + SilcHmac hmac, SilcRng rng); /****f* silccore/SilcPrivateAPI/silc_private_message_payload_free @@ -142,4 +148,20 @@ unsigned char * silc_private_message_get_message(SilcPrivateMessagePayload payload, SilcUInt32 *message_len); +/****f* silccore/SilcPrivateAPI/silc_private_message_get_mac + * + * SYNOPSIS + * + * unsigned char * + * silc_private_message_get_mac(SilcPrivateMessagePayload payload); + * + * DESCRIPTION + * + * Returns the MAC from the payload. The caller knows its length. + * The caller must not free it. + * + ***/ +unsigned char * +silc_private_message_get_mac(SilcPrivateMessagePayload payload); + #endif diff --git a/lib/silccore/silcprivate_i.h b/lib/silccore/silcprivate_i.h new file mode 100644 index 00000000..d3ad843b --- /dev/null +++ b/lib/silccore/silcprivate_i.h @@ -0,0 +1,56 @@ +/* + + silcprivate_i.h + + Author: Pekka Riikonen + + Copyright (C) 1997 - 2002 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#ifndef SILCPRIVATE_I_H +#define SILCPRIVATE_I_H + +#ifndef SILCPRIVATE_H +#error "Do not include internal header file directly" +#endif + +/****************************************************************************** + + Private Message Payload + +******************************************************************************/ + +/* Calculates padding length for message payload */ +#define SILC_PRIVATE_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16)) + +/* Header length plus maximum padding length */ +#define SILC_PRIVATE_MESSAGE_HLEN 4 + 16 + +/* Returns the data length that fits to the packet. If data length is too + big it will be truncated to fit to the payload. */ +#define SILC_PRIVATE_MESSAGE_DATALEN(data_len) \ + ((data_len + SILC_PRIVATE_MESSAGE_HLEN) > SILC_PACKET_MAX_LEN ? \ + data_len - ((data_len + SILC_PRIVATE_MESSAGE_HLEN) - \ + SILC_PACKET_MAX_LEN) : data_len) + +/* Private Message Payload structure. Contents of this structure is parsed + from SILC packets. */ +struct SilcPrivateMessagePayloadStruct { + SilcUInt16 flags; + SilcUInt16 message_len; + unsigned char *message; + unsigned char *pad; + unsigned char *mac; +}; + +#endif /* SILCPRIVATE_I_H */ diff --git a/lib/silccore/silcstatus.h b/lib/silccore/silcstatus.h index 8c91d7eb..4564a55d 100644 --- a/lib/silccore/silcstatus.h +++ b/lib/silccore/silcstatus.h @@ -100,6 +100,8 @@ typedef SilcUInt8 SilcStatus; #define SILC_STATUS_ERR_KEY_EXCHANGE_FAILED 52 #define SILC_STATUS_ERR_BAD_VERSION 53 #define SILC_STATUS_ERR_TIMEDOUT 54 +#define SILC_STATUS_ERR_UNSUPPORTED_PUBLIC_KEY 55 +#define SILC_STATUS_ERR_OPERATION_ALLOWED 56 /***/ #define SILC_STATUS_IS_ERROR(status) (status >= SILC_STATUS_ERR_NO_SUCH_NICK) diff --git a/lib/silccrypt/silchmac.h b/lib/silccrypt/silchmac.h index 290fbed1..7b853d91 100644 --- a/lib/silccrypt/silchmac.h +++ b/lib/silccrypt/silchmac.h @@ -150,7 +150,8 @@ bool silc_hmac_unregister_all(void); * * SYNOPSIS * - * bool silc_hmac_alloc(char *name, SilcHash hash, SilcHmac *new_hmac); + * bool silc_hmac_alloc(const char *name, SilcHash hash, + * SilcHmac *new_hmac); * * DESCRIPTION * @@ -161,7 +162,7 @@ bool silc_hmac_unregister_all(void); * FALSE if such HMAC does not exist. * ***/ -bool silc_hmac_alloc(char *name, SilcHash hash, SilcHmac *new_hmac); +bool silc_hmac_alloc(const char *name, SilcHash hash, SilcHmac *new_hmac); /****f* silccrypt/SilcHMACAPI/silc_hmac_free * diff --git a/lib/silccrypt/silcpkcs.c b/lib/silccrypt/silcpkcs.c index a8a2a3a4..08543c5b 100644 --- a/lib/silccrypt/silcpkcs.c +++ b/lib/silccrypt/silcpkcs.c @@ -620,6 +620,7 @@ SilcPublicKey silc_pkcs_public_key_alloc(const char *name, public_key->name = strdup(name); public_key->pk_len = pk_len; public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk)); + public_key->pk_type = SILC_SKE_PK_TYPE_SILC; memcpy(public_key->pk, pk, pk_len); if (!silc_utf8_valid(identifier, strlen(identifier))) { @@ -826,6 +827,7 @@ bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len, (*public_key)->identifier = ident; (*public_key)->pk = key_data; (*public_key)->pk_len = key_len; + (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC; } silc_buffer_free(buf); @@ -842,6 +844,88 @@ bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len, return FALSE; } +/* Encodes Public Key Payload for transmitting public keys and certificates. */ + +SilcBuffer silc_pkcs_public_key_payload_encode(SilcPublicKey public_key) +{ + SilcBuffer buffer; + unsigned char *pk; + SilcUInt32 pk_len; + + if (!public_key) + return NULL; + + pk = silc_pkcs_public_key_encode(public_key, &pk_len); + if (!pk) + return NULL; + + buffer = silc_buffer_alloc_size(4 + pk_len); + if (!buffer) { + silc_free(pk); + return NULL; + } + + silc_buffer_format(buffer, + SILC_STR_UI_SHORT(pk_len), + SILC_STR_UI_SHORT(public_key->pk_type), + SILC_STR_UI_XNSTRING(pk, pk_len), + SILC_STR_END); + + silc_free(pk); + return buffer; +} + +/* Decode Public Key Payload and decodes the public key inside it to + to `payload'. */ + +bool silc_pkcs_public_key_payload_decode(unsigned char *data, + SilcUInt32 data_len, + SilcPublicKey *public_key) +{ + SilcBufferStruct buf; + SilcUInt16 pk_len, pk_type; + unsigned char *pk; + int ret; + + if (!public_key) + return FALSE; + +#if 1 + /* XXX 1.1 version support. Check whether the data is actually raw + public key and attempt to decode. Remove this later! */ + if (silc_pkcs_public_key_decode(data, data_len, public_key)) { + (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC; + return TRUE; + } +#endif + + silc_buffer_set(&buf, data, data_len); + ret = silc_buffer_unformat(&buf, + SILC_STR_UI_SHORT(&pk_len), + SILC_STR_UI_SHORT(&pk_type), + SILC_STR_END); + if (ret < 0 || pk_len > data_len - 4) + return FALSE; + + /* For now we support only SILC public keys */ + if (pk_type != SILC_SKE_PK_TYPE_SILC) + return FALSE; + + silc_buffer_pull(&buf, 4); + ret = silc_buffer_unformat(&buf, + SILC_STR_UI_XNSTRING(&pk, pk_len), + SILC_STR_END); + silc_buffer_push(&buf, 4); + if (ret < 0) + return FALSE; + + if (!silc_pkcs_public_key_decode(pk, pk_len, public_key)) + return FALSE; + (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC; + + return TRUE; +} + /* Compares two public keys and returns TRUE if they are same key, and FALSE if they are not same. */ @@ -876,6 +960,7 @@ SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key) strlen(public_key->identifier)); key->pk = silc_memdup(public_key->pk, public_key->pk_len); key->pk_len = public_key->pk_len; + key->pk_type = public_key->pk_type; return key; } diff --git a/lib/silccrypt/silcpkcs.h b/lib/silccrypt/silcpkcs.h index d96d9ef6..d9497309 100644 --- a/lib/silccrypt/silcpkcs.h +++ b/lib/silccrypt/silcpkcs.h @@ -92,6 +92,7 @@ typedef struct SilcPKCSObjectStruct { * SOURCE */ typedef struct { + SilcUInt16 pk_type; /* Public key type (SilcSKEPKType) */ SilcUInt32 len; char *name; char *identifier; @@ -734,8 +735,9 @@ silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len, * * SYNOPSIS * - * bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len, - * SilcPublicKey *public_key); + * bool silc_pkcs_public_key_decode(unsigned char *data, + * SilcUInt32 data_len, + * SilcPublicKey *public_key); * * DESCRIPTION * @@ -746,6 +748,41 @@ silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len, bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len, SilcPublicKey *public_key); +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_decode + * + * SYNOPSIS + * + * bool silc_pkcs_public_key_payload_encode(SilcPublicKey public_key); + * + * DESCRIPTION + * + * Encodes the Public Key Payload from the public key indicated by + * `public_key' of type of `pk_type'. The type is SilcSKEPKType. + * Returns the encoded payload buffer. + * + ***/ +SilcBuffer silc_pkcs_public_key_payload_encode(SilcPublicKey public_key); + +/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_decode + * + * SYNOPSIS + * + * bool + * silc_pkcs_public_key_payload_decode(unsigned char *data, + * SilcUInt32 data_len, + * SilcPublicKey *public_key); + * + * DESCRIPTION + * + * Decodes Public Key Payload from `data' of `data_len' bytes in length + * data buffer into `public_key' pointer. Returns FALSE if the payload + * cannot be decoded. + * + ***/ +bool silc_pkcs_public_key_payload_decode(unsigned char *data, + SilcUInt32 data_len, + SilcPublicKey *public_key); + /****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_compare * * SYNOPSIS diff --git a/lib/silcutil/silcbuffmt.c b/lib/silcutil/silcbuffmt.c index 83d240ca..3f0a529b 100644 --- a/lib/silcutil/silcbuffmt.c +++ b/lib/silcutil/silcbuffmt.c @@ -179,6 +179,8 @@ int silc_buffer_format_vp(SilcBuffer dst, va_list ap) fail: SILC_LOG_DEBUG(("Error occured while formatting data")); + len = dst->data - start_ptr; + silc_buffer_push(dst, len); return -1; ok: @@ -491,6 +493,8 @@ int silc_buffer_unformat_vp(SilcBuffer src, va_list ap) fail: SILC_LOG_DEBUG(("Error occured while unformatting buffer")); + len = src->data - start_ptr; + silc_buffer_push(src, len); return -1; ok: diff --git a/lib/silcutil/silcutil.c b/lib/silcutil/silcutil.c index 1ede14fc..7898a4c9 100644 --- a/lib/silcutil/silcutil.c +++ b/lib/silcutil/silcutil.c @@ -1031,6 +1031,8 @@ static const SilcStatusMessage silc_status_messages[] = { { STAT(KEY_EXCHANGE_FAILED), "Key exchange failed" }, { STAT(BAD_VERSION), "Bad version" }, { STAT(TIMEDOUT), "Service timed out" }, + { STAT(UNSUPPORTED_PUBLIC_KEY), "Unsupported public key type" }, + { STAT(OPERATION_ALLOWED), "Operation is not allowed" }, { 0, NULL } }; diff --git a/lib/silcutil/stacktrace.h b/lib/silcutil/stacktrace.h index 5c468868..bfe8ae03 100644 --- a/lib/silcutil/stacktrace.h +++ b/lib/silcutil/stacktrace.h @@ -21,7 +21,7 @@ #define STACKTRACE_H #ifndef SILCMEMORY_H -#error "Do not include this file directly" +#error "Do not include internal header file directly" #endif #if defined(__GNUC__) && defined(__i386__) diff --git a/prepare b/prepare index a3b58a7e..fbdcd9b0 100755 --- a/prepare +++ b/prepare @@ -140,7 +140,7 @@ file=includes/version_internal.h echo "/* Automatically generated by ./prepare */" >$file echo "#define SILC_VERSION_STRING \"$dist_version\"" >>$file echo "#define SILC_DIST_VERSION_STRING \"$dist_version\"" >>$file -echo "#define SILC_PROTOCOL_VERSION_STRING \"SILC-1.1-$dist_version $distribution\"" >>$file +echo "#define SILC_PROTOCOL_VERSION_STRING \"SILC-1.2-$dist_version $distribution\"" >>$file echo "#define SILC_NAME \"SILC $distribution\"" >>$file # preparing irssi -- 2.24.0