+Sun Nov 10 12:20:56 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * 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 <priikone@silcnet.org>
* Added "do_not_bind" argument to silc_client_file_send what
Commands:
- set [<key> [<cipher>] [<hmac>]]
+ set [<key> [<cipher>] [<hmac>]] [-responder]
Set the key into use. If the <key> is provided it is used
as the key material. If the <key> is not provided the
been performed this command has no effect.
If the type is MSG and the <key> is `*' then random key
- will be generated automatically. The <cipher> may be set
- for both private message and channel private keys and the
- <hmac> 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 [<number>]
/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
@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
{ "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 } },
/* 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);
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. */
*/
} 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,
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));
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);
}
/* SYNTAX: KEY MSG <nickname> set|unset|list|agreement|negotiate [<arguments>] */
/* SYNTAX: KEY CHANNEL <channel> set|unset|list|change [<arguments>] */
/* SYNTAX: KICK <channel> <nickname>[@<hostname>] [<comment>] */
-/* SYNTAX: KILL <nickname>[@<hostname>] [<comment>] */
+/* SYNTAX: KILL <nickname>[@<hostname>] [<comment>] [-pubkey] */
/* SYNTAX: OPER <username> [-pubkey] */
/* SYNTAX: SILCOPER <username> [-pubkey] */
/* SYNTAX: TOPIC <channel> [<topic>] */
/* 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);
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 */
/* 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,
/* 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);
}
{
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);
}
out:
+ silc_free(server_id);
silc_server_command_free(cmd);
}
/* 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;
}
/* 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;
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"));
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);
}
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,
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,
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);
}
}
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);
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);
}
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,
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),
out:
channel->mode = old_mask;
- silc_free(fkey);
+ silc_buffer_free(fkey);
silc_free(channel_id);
silc_server_command_free(cmd);
}
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;
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);
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),
out:
silc_free(channel_id);
silc_free(client_id);
- silc_free(fkey);
+ silc_buffer_free(fkey);
silc_server_command_free(cmd);
}
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;
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);
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);
/* 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,
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;
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);
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;
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 &&
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;
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 */
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,
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) {
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,
/* 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;
}
/* 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
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
/* 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 */
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,
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);
}
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,
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);
}
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. */
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
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"));
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,
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,
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);
/* 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,
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);
/* 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;
/* 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);
}
}
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 */
/* 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);
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));
.ds RF FORMFEED[Page %]
.ds CF
.ds LH Internet Draft
-.ds RH 15 May 2002
+.ds RH XXX
.ds CH
.na
.hy 0
.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
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)
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
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
EMail: priikone@iki.fi
-This Internet-Draft expires 15 November 2002
+This Internet-Draft expires XXX
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
Every command reply also defines set of status message that it
may return inside the <Status Payload>. 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
-<Client ID>) 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 <Client ID>) 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
9 SILC_COMMAND_KILL
- Max Arguments: 2
- Arguments: (1) <Client ID> (2) [<comment>]
+ Max Arguments: 3
+ Arguments: (1) <Client ID> (2) [<comment>]
+ (3) [<auth payload>]
+
+ 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 <Client ID> is the client to be
- removed from SILC. The <comment> 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 <Client ID> is the client to be removed from SILC.
+ The <comment> 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.
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 <Client ID> is the
+ destination client to be removed from the network. The client
+ MUST provide the <auth payload> which includes a digital signature
+ that MUST be verified with the public key of the client indicated
+ by <Client ID>. The <Client ID> 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 <auth payload> computing is SHA1.
+
Reply messages to the command:
Max Arguments: 1
The <username> is the username set in the server configurations
as operator. The <authentication payload> 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.
channel. The <Client ID list> is formed by adding the ID Payloads
one after the other. The <client mode list> is formed by adding
32 bit MSB first order values one after the other. The <founder
- pubkey> 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 <Channel Key Payload>.
.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
.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
"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
.ti 0
-4 References
+5 References
[SILC1] Riikonen, P., "Secure Internet Live Conferencing (SILC),
Protocol Specification", Internet Draft, May 2002.
.ti 0
-5 Author's Address
+6 Author's Address
.nf
Pekka Riikonen
.ds RF FORMFEED[Page %]
.ds CF
.ds LH Internet Draft
-.ds RH 15 May 2002
+.ds RH XXX
.ds CH
.na
.hy 0
.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
-<draft-riikonen-flags-payloads-00.txt>
+<draft-riikonen-flags-payloads-01.txt>
.ti 0
Status of this Memo
.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
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
[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.
EMail: priikone@iki.fi
-This Internet-Draft expires 15 November 2002
+This Internet-Draft expires 20 April 2003
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.
| Public Key Length | Public Key Type |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
-~ Public Key of the party (or certificate) ~
+~ Public Key (or certificate) ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
.in 3
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
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
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
-~ Padding ~
+~ Padding ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| |
+~ MAC ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
.in 3
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
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
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
~ Cipher Name ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| HMAC Name Length | |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+| |
+~ HMAC Name ~
+| |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
.in 3
.ce
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
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
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.
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
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-<software version>. If new protocol version
+protocol version as SILC-1.2-<software version>. If new protocol version
causes incompatibilities with older version the <minor> version number
MUST be incremented. The <major> is incremented if new protocol version
is fully incompatible.
.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
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
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
#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"
#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"
#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
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,
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"));
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)
{
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)
{
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;
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,
/* 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;
/*
- client_channel.c
+ client_channel.c
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ Author: Pekka Riikonen <priikone@silcnet.org>
- 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
SilcMessageFlags flags,
unsigned char *data,
SilcUInt32 data_len,
- int force_send)
+ bool force_send)
{
int i;
SilcSocketConnection sock;
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,
/* 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);
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,
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)
{
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)
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
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,
SilcBuffer silc_client_attributes_process(SilcClient client,
SilcSocketConnection sock,
SilcDList attrs);
+SILC_TASK_CALLBACK_GLOBAL(silc_client_rekey_callback);
#endif
/*
- client_prvmsg.c
+ client_prvmsg.c
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ Author: Pekka Riikonen <priikone@silcnet.org>
- 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
SilcMessageFlags flags,
unsigned char *data,
SilcUInt32 data_len,
- int force_send)
+ bool force_send)
{
SilcSocketConnection sock;
SilcBuffer buffer;
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
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,
/* 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);
/* 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:
unsigned char *message;
SilcUInt32 message_len;
SilcCipher cipher = NULL;
+ SilcHmac hmac = NULL;
if (packet->src_id_type != SILC_ID_CLIENT)
goto out;
}
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;
SilcPacketContext *packet = (SilcPacketContext *)context;
unsigned char *key;
SilcUInt16 key_len;
- unsigned char *cipher;
+ unsigned char *cipher = NULL, *hmac = NULL;
int ret;
if (!clients)
/* 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;
/* 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 */
clients[0]->username ? ")" : "");
out:
+ silc_free(cipher);
+ silc_free(hmac);
silc_packet_context_free(packet);
}
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
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;
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;
!= 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) {
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);
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 */
/* 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);
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) {
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);
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;
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);
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);
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 */
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)
{
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);
if (cmd->argc < 2) {
SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /KILL <nickname> [<comment>]");
+ "Usage: /KILL <nickname> [<comment>] [-pubkey]");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
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);
{
SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcBuffer buffer;
+ SilcBuffer buffer, idp;
void *id;
int i;
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);
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);
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;
/* 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) {
/* 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 */
*
* SYNOPSIS
*
- * int silc_client_init(SilcClient client);
+ * bool silc_client_init(SilcClient client);
*
* DESCRIPTION
*
* 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
*
*
* 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);
*
* 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
*
* SilcMessageFlags flags,
* unsigned char *data,
* SilcUInt32 data_len,
- * int force_send);
+ * bool_force_send);
*
* DESCRIPTION
*
SilcMessageFlags flags,
unsigned char *data,
SilcUInt32 data_len,
- int force_send);
+ bool force_send);
/****f* silcclient/SilcClientAPI/silc_client_send_private_message
*
* SilcMessageFlags flags,
* unsigned char *data,
* SilcUInt32 data_len,
- * int force_send);
+ * bool force_send);
*
* DESCRIPTION
*
SilcMessageFlags flags,
unsigned char *data,
SilcUInt32 data_len,
- int force_send);
+ bool force_send);
/* Client and Channel entry retrieval (idlist.c) */
*
* SYNOPSIS
*
- * void silc_client_command_call(SilcClient client,
+ * bool silc_client_command_call(SilcClient client,
* SilcClientConnection conn,
* const char *command_line, ...);
*
*
* 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
*
* 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
* 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
*
* 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
*
*
* 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
*
* 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
*
* 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);
* 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
*
Author: Pekka Riikonen <priikone@silcnet.org>
- 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
Author: Pekka Riikonen <priikone@silcnet.org>
- 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
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;
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;
*/
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;
/*
- silcauth.c
+ silcauth.c
Author: Pekka Riikonen <priikone@silcnet.org>
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
#include "silcincludes.h"
#include "silcauth.h"
+#include "silcchannel_i.h"
+#include "silcprivate_i.h"
/******************************************************************************
if (ret_len)
*ret_len = buf->len;
+ silc_buffer_clear(buf);
silc_buffer_free(buf);
silc_free(id_data);
silc_free(pk);
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;
{
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;
+}
/*
- silcauth.h
-
+ silcauth.h
+
Author: Pekka Riikonen <priikone@silcnet.org>
-
- 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
* 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
#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
*
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
***/
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
#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. */
******************************************************************************/
-/* 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,
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"));
goto err;
}
+ newp->iv_len = iv_len;
+
return newp;
err:
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,
******************************************************************************/
-/* 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
*
* 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,
* 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,
--- /dev/null
+/*
+
+ silcchannel_i.h
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ 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 */
/* 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
*
* 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
* 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 */
#include "silcincludes.h"
#include "silcprivate.h"
+#include "silcprivate_i.h"
/******************************************************************************
******************************************************************************/
-/* 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;
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"));
/* 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 */
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;
return payload->message;
}
+
+/* Return MAC. Caller knows its length */
+
+unsigned char *
+silc_private_message_get_mac(SilcPrivateMessagePayload payload)
+{
+ return payload->mac;
+}
* 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
*
* 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
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
--- /dev/null
+/*
+
+ silcprivate_i.h
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ 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 */
#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)
*
* 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
*
* 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
*
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))) {
(*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);
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. */
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;
}
* SOURCE
*/
typedef struct {
+ SilcUInt16 pk_type; /* Public key type (SilcSKEPKType) */
SilcUInt32 len;
char *name;
char *identifier;
*
* 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
*
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
fail:
SILC_LOG_DEBUG(("Error occured while formatting data"));
+ len = dst->data - start_ptr;
+ silc_buffer_push(dst, len);
return -1;
ok:
fail:
SILC_LOG_DEBUG(("Error occured while unformatting buffer"));
+ len = src->data - start_ptr;
+ silc_buffer_push(src, len);
return -1;
ok:
{ 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 }
};
#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__)
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