+Wed Apr 4 16:32:31 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Do not ask whether user wants to use the negotiated private key
+ for private messages, just use it. Affected file is
+ silc/local_command.c.
+
+ * Added `send_enc_key' and `enc_key_len' fields to the
+ SilcIDListData structure since they are needed in the re-key
+ phase. Affected file is silcd/idlist.[ch].
+
+ * Implemented the simple re-key protocol into the server.
+ Affected files silcd/server.c and silcd/protocol.[ch]. The
+ re-key will be performed once in an hour, by default.
+
+ Added new protocol type SILC_PROTOCOL_SERVER_REKEY.
+ Added silc_server_rekey, silc_server_rekey_callback and
+ silc_server_rekey_final.
+
+ * Removed Tunneled flag from the protocol. Updated the code
+ and the specifications.
+
+ * Adde `pfs' field to the SilcIDListData to indicate whether
+ the PFS is to be performed in the re-key. Affected file is
+ silcd/idlist.h.
+
Tue Apr 3 21:52:42 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
* Defined uint8, int8, uint16, int16, uint32, int32, uint64 and
client_entry->nickname);;
if (i->type == 1) {
- if (!silc_client_ask_yes_no(client,
- "Would you like to use the key with private messages (y/n)? ")) {
- silc_say(client, conn, "You can set the key material into use later by giving /KEY msg set command");
- curr_key = key;
- break;
- }
-
/* 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,
SilcIDListData data = (SilcIDListData)entry;
data->send_key = idata->send_key;
data->receive_key = idata->receive_key;
+ data->rekey = idata->rekey;
data->hash = idata->hash;
data->hmac = idata->hmac;
- data->hmac_key = idata->hmac_key;
- data->hmac_key_len = idata->hmac_key_len;
data->public_key = idata->public_key;
data->last_receive = idata->last_receive;
data->last_sent = idata->last_sent;
silc_cipher_free(idata->send_key);
if (idata->receive_key)
silc_cipher_free(idata->receive_key);
+ if (idata->rekey) {
+ if (idata->rekey->send_enc_key) {
+ memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
+ silc_free(idata->rekey->send_enc_key);
+ }
+ silc_free(idata->rekey);
+ }
if (idata->hmac)
silc_hmac_free(idata->hmac);
- if (idata->hmac_key) {
- memset(idata->hmac_key, 0, idata->hmac_key_len);
- silc_free(idata->hmac_key);
- }
if (idata->public_key)
silc_pkcs_public_key_free(idata->public_key);
}
int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
{
+ SILC_LOG_DEBUG(("Start"));
+
if (entry) {
/* Remove from cache */
if (entry->id)
int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
{
+ SILC_LOG_DEBUG(("Start"));
+
if (entry) {
/* Remove from cache */
if (entry->id)
int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
{
+ SILC_LOG_DEBUG(("Start"));
+
if (entry) {
SilcChannelClientEntry chl;
uint32 key_len;
} *SilcServerChannelRekey;
+/* Generic rekey context for connections */
+typedef struct {
+ /* Current sending encryption key, provided for re-key. The `pfs'
+ is TRUE if the Perfect Forward Secrecy is performed in re-key. */
+ unsigned char *send_enc_key;
+ uint32 enc_key_len;
+ bool pfs;
+ uint32 timeout;
+ void *context;
+} *SilcServerRekey;
+
/*
Generic ID list data structure.
SilcCipher send_key;
SilcCipher receive_key;
+ /* Re-key context */
+ SilcServerRekey rekey;
+
/* Hash selected in the SKE protocol, NULL if not needed at all */
SilcHash hash;
- /* HMAC and raw key data */
+ /* HMAC */
SilcHmac hmac;
- unsigned char *hmac_key;
- uint32 hmac_key_len;
- /* public key */
+ /* Public key */
SilcPublicKey public_key;
long last_receive; /* Time last received data */
long last_sent; /* Time last sent data */
- unsigned char registered; /* Boolean whether connection is registered */
+ bool registered; /* Boolean whether connection is registered */
} *SilcIDListData, SilcIDListDataStruct;
/*
not allow any command to be exeucted more than once in about
2 seconds. This is result of normal time().
- char fast_command
+ uint8 fast_command
Counter to check command bursts. By default, up to 5 commands
are allowed before limiting the execution. See command flags
int mode;
long last_command;
- char fast_command;
+ uint8 fast_command;
/* Pointer to the router */
SilcServerEntry router;
ID of the channel. This includes all the information SILC will ever
need.
- int global_users
+ bool global_users
Boolean value to tell whether there are users outside this server
on this channel. This is set to TRUE if router sends message to
char *channel_name;
uint32 mode;
SilcChannelID *id;
- int global_users;
+ bool global_users;
char *topic;
char *cipher;
char *hmac_name;
conn_type,
auth_meth);
}
+
+/* Received REKEY packet. The sender of the packet wants to regenerate
+ its session keys. This starts the REKEY protocol. */
+
+void silc_server_rekey(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcProtocol protocol;
+ SilcServerRekeyInternalContext *proto_ctx;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Allocate internal protocol context. This is sent as context
+ to the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = (void *)server;
+ proto_ctx->sock = sock;
+ proto_ctx->responder = TRUE;
+
+ /* Perform rekey protocol. Will call the final callback after the
+ protocol is over. */
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_REKEY,
+ &protocol, proto_ctx, silc_server_rekey_final);
+ sock->protocol = protocol;
+
+ /* Run the protocol */
+ protocol->execute(server->timeout_queue, 0, protocol, sock->sock, 0, 0);
+}
void silc_server_connection_auth_request(SilcServer server,
SilcSocketConnection sock,
SilcPacketContext *packet);
+void silc_server_rekey(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
#endif
SilcPKCS pkcs,
SilcHash hash,
SilcHmac hmac,
- int is_responder)
+ bool is_responder)
{
SilcUnknownEntry conn_data;
SilcIDListData idata;
}
if (is_responder == TRUE) {
- idata->send_key->cipher->set_key(idata->send_key->context,
- keymat->receive_enc_key,
- keymat->enc_key_len);
- idata->send_key->set_iv(idata->send_key, keymat->receive_iv);
- idata->receive_key->cipher->set_key(idata->receive_key->context,
- keymat->send_enc_key,
- keymat->enc_key_len);
- idata->receive_key->set_iv(idata->receive_key, keymat->send_iv);
-
+ silc_cipher_set_key(idata->send_key, keymat->receive_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(idata->send_key, keymat->receive_iv);
+ silc_cipher_set_key(idata->receive_key, keymat->send_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(idata->receive_key, keymat->send_iv);
} else {
- idata->send_key->cipher->set_key(idata->send_key->context,
- keymat->send_enc_key,
- keymat->enc_key_len);
- idata->send_key->set_iv(idata->send_key, keymat->send_iv);
- idata->receive_key->cipher->set_key(idata->receive_key->context,
- keymat->receive_enc_key,
- keymat->enc_key_len);
- idata->receive_key->set_iv(idata->receive_key, keymat->receive_iv);
+ silc_cipher_set_key(idata->send_key, keymat->send_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(idata->send_key, keymat->send_iv);
+ silc_cipher_set_key(idata->receive_key, keymat->receive_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(idata->receive_key, keymat->receive_iv);
}
+ /* Note that for responder the initiator's sending key is receiving key */
+ idata->rekey = silc_calloc(1, sizeof(*idata->rekey));
+ idata->rekey->send_enc_key =
+ silc_calloc(keymat->enc_key_len / 8,
+ sizeof(*idata->rekey->send_enc_key));
+ memcpy(idata->rekey->send_enc_key,
+ keymat->send_enc_key, keymat->enc_key_len / 8);
+ idata->rekey->enc_key_len = keymat->enc_key_len / 8;
+
+ if (ske->start_payload->flags & SILC_SKE_SP_FLAG_PFS)
+ idata->rekey->pfs = TRUE;
+
/* Save the remote host's public key */
silc_pkcs_public_key_decode(ske->ke1_payload->pk_data,
ske->ke1_payload->pk_len, &idata->public_key);
SILC_PUT32_MSB(SILC_AUTH_OK, ok);
- /* Authentication failed */
+ /* Authentication successful */
silc_server_packet_send(server, ctx->sock, SILC_PACKET_SUCCESS,
0, ok, 4, TRUE);
}
}
+/*
+ * Re-key protocol routines
+ */
+
+/* This function actually re-generates (when not using PFS) the keys and
+ takes them into use. */
+
+void silc_server_protocol_rekey_generate(SilcServer server,
+ SilcServerRekeyInternalContext *ctx)
+{
+ SilcIDListData idata = (SilcIDListData)ctx->sock->user_data;
+ SilcSKEKeyMaterial *keymat;
+ uint32 key_len = silc_cipher_get_key_len(idata->send_key);
+ uint32 hash_len = idata->hash->hash->hash_len;
+
+ SILC_LOG_DEBUG(("Generating new session keys (no PFS)"));
+
+ /* Generate the new key */
+ keymat = silc_calloc(1, sizeof(*keymat));
+ silc_ske_process_key_material_data(idata->rekey->send_enc_key,
+ idata->rekey->enc_key_len,
+ 16, key_len, hash_len,
+ idata->hash, keymat);
+
+ /* Set the keys into use */
+
+ if (ctx->responder == TRUE) {
+ silc_cipher_set_key(idata->send_key, keymat->receive_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(idata->send_key, keymat->receive_iv);
+ silc_cipher_set_key(idata->receive_key, keymat->send_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(idata->receive_key, keymat->send_iv);
+ } else {
+ silc_cipher_set_key(idata->send_key, keymat->send_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(idata->send_key, keymat->send_iv);
+ silc_cipher_set_key(idata->receive_key, keymat->receive_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(idata->receive_key, keymat->receive_iv);
+ }
+
+ silc_hmac_set_key(idata->hmac, keymat->hmac_key, keymat->hmac_key_len);
+
+ /* Save the current sending encryption key */
+ memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
+ silc_free(idata->rekey->send_enc_key);
+ idata->rekey->send_enc_key =
+ silc_calloc(keymat->enc_key_len / 8,
+ sizeof(*idata->rekey->send_enc_key));
+ memcpy(idata->rekey->send_enc_key, keymat->send_enc_key,
+ keymat->enc_key_len / 8);
+ idata->rekey->enc_key_len = keymat->enc_key_len / 8;
+
+ silc_ske_free_key_material(keymat);
+}
+
+/* Performs re-key as defined the SILC protocol specification. */
+
+SILC_TASK_CALLBACK(silc_server_protocol_rekey)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerRekeyInternalContext *ctx =
+ (SilcServerRekeyInternalContext *)protocol->context;
+ SilcServer server = (SilcServer)ctx->server;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
+ protocol->state = SILC_PROTOCOL_STATE_START;
+
+ SILC_LOG_DEBUG(("State=%d", protocol->state));
+
+ switch(protocol->state) {
+ case SILC_PROTOCOL_STATE_START:
+ {
+ /*
+ * Start protocol.
+ */
+
+ if (ctx->responder == TRUE) {
+ /*
+ * We are receiving party
+ */
+
+ if (ctx->pfs == TRUE) {
+ /*
+ * Use Perfect Forward Secrecy, ie. negotiate the key material
+ * using the SKE protocol.
+ */
+
+ } else {
+ /*
+ * Do normal and simple re-key.
+ */
+
+ /* Send the REKEY_DONE to indicate we will take new keys into use */
+ silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY_DONE,
+ 0, NULL, 0, TRUE);
+
+ /* The protocol ends in next stage. */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ }
+
+ } else {
+ /*
+ * We are the initiator of this protocol
+ */
+
+ if (ctx->pfs == TRUE) {
+ /*
+ * Use Perfect Forward Secrecy, ie. negotiate the key material
+ * using the SKE protocol.
+ */
+
+ } else {
+ /*
+ * Do normal and simple re-key.
+ */
+
+ /* Start the re-key by sending the REKEY packet */
+ silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY,
+ 0, NULL, 0, TRUE);
+
+ /* The protocol ends in next stage. */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ }
+ }
+
+ }
+ break;
+
+ case SILC_PROTOCOL_STATE_END:
+ /*
+ * End protocol
+ */
+
+ if (ctx->responder == TRUE) {
+
+ if (ctx->pfs == TRUE) {
+ /*
+ *
+ */
+
+ } else {
+ /*
+ * We must have received the REKEY_DONE from the initiator.
+ */
+
+ if (ctx->packet->type != SILC_PACKET_REKEY_DONE) {
+ /* Error in protocol */
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 0);
+ }
+ }
+
+ } else {
+
+ if (ctx->pfs == TRUE) {
+ /*
+ *
+ */
+
+ } else {
+ /*
+ * We must have received the REKEY_DONE from the responder.
+ */
+
+ if (ctx->packet->type != SILC_PACKET_REKEY_DONE) {
+ /* Error in protocol */
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 0);
+ }
+
+ /* Send the REKEY_DONE to indicate we will take new keys into use
+ now. */
+ silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY_DONE,
+ 0, NULL, 0, TRUE);
+ }
+ }
+
+ /* Protocol has ended, call the final callback */
+ if (protocol->final_callback)
+ protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ break;
+
+ case SILC_PROTOCOL_STATE_ERROR:
+ /*
+ * Error occured
+ */
+
+ if (ctx->pfs == TRUE) {
+ /* Send abort notification */
+ silc_ske_abort(ctx->ske, ctx->ske->status,
+ silc_server_protocol_ke_send_packet,
+ context);
+ }
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ break;
+
+ case SILC_PROTOCOL_STATE_FAILURE:
+ /*
+ * We have received failure from remote
+ */
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ break;
+
+ case SILC_PROTOCOL_STATE_UNKNOWN:
+ break;
+ }
+
+}
+
/* Registers protocols used in server. */
void silc_server_protocols_register(void)
silc_server_protocol_connection_auth);
silc_protocol_register(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
silc_server_protocol_key_exchange);
+ silc_protocol_register(SILC_PROTOCOL_SERVER_REKEY,
+ silc_server_protocol_rekey);
}
/* Unregisters protocols */
silc_server_protocol_connection_auth);
silc_protocol_unregister(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
silc_server_protocol_key_exchange);
+ silc_protocol_unregister(SILC_PROTOCOL_SERVER_REKEY,
+ silc_server_protocol_rekey);
}
#define PROTOCOL_H
/* SILC client protocol types */
-#define SILC_PROTOCOL_SERVER_NONE 0
-#define SILC_PROTOCOL_SERVER_CONNECTION_AUTH 1
-#define SILC_PROTOCOL_SERVER_KEY_EXCHANGE 2
-/* #define SILC_PROTOCOL_SERVER_MAX 255 */
+#define SILC_PROTOCOL_SERVER_NONE 0
+#define SILC_PROTOCOL_SERVER_CONNECTION_AUTH 1
+#define SILC_PROTOCOL_SERVER_KEY_EXCHANGE 2
+#define SILC_PROTOCOL_SERVER_REKEY 3
+/* #define SILC_PROTOCOL_SERVER_MAX 255 */
/* Internal context for Key Exchange protocol. */
typedef struct {
SilcRng rng;
/* TRUE if we are receiveing part of the protocol */
- int responder;
+ bool responder;
/* Destinations ID taken from authenticataed packet so that we can
get the destinations ID. */
SilcSocketConnection sock;
/* TRUE if we are receiving part of the protocol */
- int responder;
+ bool responder;
/* SKE object from Key Exchange protocol. */
SilcSKE ske;
uint16 conn_type;
} SilcServerConnAuthInternalContext;
+/* Internal context for the rekey protocol */
+typedef struct {
+ void *server;
+ void *context;
+ SilcSocketConnection sock;
+ bool responder; /* TRUE if we are receiving party */
+ bool pfs; /* TRUE if PFS is to be used */
+ SilcSKE ske; /* Defined if PFS is used */
+ SilcSKEKeyMaterial *keymat; /* Defined if PFS is used */
+ SilcPacketContext *packet;
+} SilcServerRekeyInternalContext;
+
/* Prototypes */
void silc_server_protocols_register(void);
void silc_server_protocols_unregister(void);
SilcPKCS pkcs,
SilcHash hash,
SilcHmac hmac,
- int is_responder);
+ bool is_responder);
+void silc_server_protocol_rekey_generate(SilcServer server,
+ SilcServerRekeyInternalContext *ctx);
#endif
SILC_TASK_CALLBACK(silc_server_packet_parse_real);
SILC_TASK_CALLBACK(silc_server_timeout_remote);
SILC_TASK_CALLBACK(silc_server_failure_callback);
+SILC_TASK_CALLBACK(silc_server_rekey_callback);
/* Allocates a new SILC server object. This has to be done before the server
can be used. After allocation one must call silc_server_init to initialize
(SilcServerKEInternalContext *)protocol->context;
SilcServer server = (SilcServer)ctx->server;
SilcServerConnection sconn = (SilcServerConnection)ctx->context;
- SilcSocketConnection sock = NULL;
+ SilcSocketConnection sock = server->sockets[fd];
SilcServerConnAuthInternalContext *proto_ctx;
SilcServerConfigSectionServerConnection *conn = NULL;
protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
silc_protocol_free(protocol);
+ sock->protocol = NULL;
silc_ske_free_key_material(ctx->keymat);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
ctx->ske->prop->hmac,
ctx->responder)) {
silc_protocol_free(protocol);
+ sock->protocol = NULL;
silc_ske_free_key_material(ctx->keymat);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
proto_ctx->server = (void *)server;
proto_ctx->context = (void *)sconn;
- proto_ctx->sock = sock = server->sockets[fd];
+ proto_ctx->sock = sock;
proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
proto_ctx->dest_id_type = ctx->dest_id_type;
proto_ctx->dest_id = ctx->dest_id;
SILC_LOG_ERROR(("Could not find connection data for %s (%s) on port",
sock->hostname, sock->ip, sock->port));
silc_protocol_free(protocol);
+ sock->protocol = NULL;
if (ctx->packet)
silc_packet_context_free(ctx->packet);
if (ctx->ske)
SilcBuffer packet;
SilcServerHBContext hb_context;
unsigned char *id_string;
+ SilcIDListData idata;
SILC_LOG_DEBUG(("Start"));
sock->type = SILC_SOCKET_TYPE_ROUTER;
server->id_entry->router = id_entry;
server->router = id_entry;
- server->router->data.registered = TRUE;
+ idata = (SilcIDListData)sock->user_data;
+ idata->registered = TRUE;
/* Perform keepalive. The `hb_context' will be freed automatically
when finally calling the silc_socket_free function. XXX hardcoded
silc_server_perform_heartbeat,
server->timeout_queue);
+ /* Register re-key timeout */
+ idata->rekey->timeout = 60; /* XXX hardcoded */
+ idata->rekey->context = (void *)server;
+ silc_task_register(server->timeout_queue, sock->sock,
+ silc_server_rekey_callback,
+ (void *)sock, idata->rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
/* If we are router then announce our possible servers. */
if (server->server_type == SILC_ROUTER)
silc_server_announce_servers(server);
SilcServerKEInternalContext *ctx =
(SilcServerKEInternalContext *)protocol->context;
SilcServer server = (SilcServer)ctx->server;
- SilcSocketConnection sock = NULL;
+ SilcSocketConnection sock = server->sockets[fd];
SilcServerConnAuthInternalContext *proto_ctx;
SILC_LOG_DEBUG(("Start"));
protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
silc_protocol_free(protocol);
+ sock->protocol = NULL;
silc_ske_free_key_material(ctx->keymat);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
ctx->ske->prop->hmac,
ctx->responder)) {
silc_protocol_free(protocol);
+ sock->protocol = NULL;
silc_ske_free_key_material(ctx->keymat);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
is sent as context for the protocol. */
proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
proto_ctx->server = (void *)server;
- proto_ctx->sock = sock = server->sockets[fd];
+ proto_ctx->sock = sock;
proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
proto_ctx->responder = TRUE;
proto_ctx->dest_id_type = ctx->dest_id_type;
protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
silc_protocol_free(protocol);
+ sock->protocol = NULL;
if (ctx->packet)
silc_packet_context_free(ctx->packet);
if (ctx->ske)
silc_server_key_agreement(server, sock, packet);
break;
+ case SILC_PACKET_REKEY:
+ /*
+ * Received re-key packet. The sender wants to regenerate the session
+ * keys.
+ */
+ SILC_LOG_DEBUG(("Re-key packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ silc_server_rekey(server, sock, packet);
+ break;
+
+ case SILC_PACKET_REKEY_DONE:
+ /*
+ * The re-key is done.
+ */
+ SILC_LOG_DEBUG(("Re-key done packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+
+ if (sock->protocol && sock->protocol->protocol &&
+ sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY) {
+
+ SilcServerRekeyInternalContext *proto_ctx =
+ (SilcServerRekeyInternalContext *)sock->protocol->context;
+
+ if (proto_ctx->packet)
+ silc_packet_context_free(proto_ctx->packet);
+
+ proto_ctx->packet = silc_packet_context_dup(packet);
+
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock,
+ 0, 100000);
+ } else {
+ SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
+ "protocol active, packet dropped."));
+ }
+ break;
+
default:
SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type));
break;
return client;
}
+
+/* A timeout callback for the re-key. We will be the initiator of the
+ re-key protocol. */
+
+SILC_TASK_CALLBACK(silc_server_rekey_callback)
+{
+ SilcSocketConnection sock = (SilcSocketConnection)context;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
+ SilcServer server = (SilcServer)idata->rekey->context;
+ SilcProtocol protocol;
+ SilcServerRekeyInternalContext *proto_ctx;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Allocate internal protocol context. This is sent as context
+ to the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = (void *)server;
+ proto_ctx->sock = sock;
+ proto_ctx->responder = FALSE;
+
+ /* Perform rekey protocol. Will call the final callback after the
+ protocol is over. */
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_REKEY,
+ &protocol, proto_ctx, silc_server_rekey_final);
+ sock->protocol = protocol;
+
+ /* Run the protocol */
+ protocol->execute(server->timeout_queue, 0, protocol,
+ sock->sock, 0, 0);
+
+ /* Re-register re-key timeout */
+ silc_task_register(server->timeout_queue, sock->sock,
+ silc_server_rekey_callback,
+ context, idata->rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+}
+
+/* The final callback for the REKEY protocol. This will actually take the
+ new key material into use. */
+
+SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerRekeyInternalContext *ctx =
+ (SilcServerRekeyInternalContext *)protocol->context;
+ SilcServer server = (SilcServer)ctx->server;
+ SilcSocketConnection sock = ctx->sock;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+ /* Error occured during protocol */
+ silc_protocol_free(protocol);
+ sock->protocol = NULL;
+ if (ctx->keymat)
+ silc_ske_free_key_material(ctx->keymat);
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_free(ctx);
+ return;
+ }
+
+ /* Take the keys into use */
+ if (ctx->pfs == TRUE) {
+
+ } else {
+ /* Then just generate the new keys and take them into use */
+ silc_server_protocol_rekey_generate(server, ctx);
+ }
+
+ /* Cleanup */
+ silc_protocol_free(protocol);
+ sock->protocol = NULL;
+ if (ctx->keymat)
+ silc_ske_free_key_material(ctx->keymat);
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_free(ctx);
+}
various things. */
typedef struct {
/* Local stats (server and router) */
- uint32 my_clients; /* Locally connected clients */
- uint32 my_servers; /* Locally connected servers */
- uint32 my_routers; /* Locally connected routers */
- uint32 my_channels; /* Locally created channels */
+ uint32 my_clients; /* Locally connected clients */
+ uint32 my_servers; /* Locally connected servers */
+ uint32 my_routers; /* Locally connected routers */
+ uint32 my_channels; /* Locally created channels */
uint32 my_chanclients; /* Local clients on local channels */
- uint32 my_aways; /* Local clients away (XXX) */
- uint32 my_server_ops; /* Local server operators */
- uint32 my_router_ops; /* Local router operators */
+ uint32 my_aways; /* Local clients away (XXX) */
+ uint32 my_server_ops; /* Local server operators */
+ uint32 my_router_ops; /* Local router operators */
/* Global stats (mainly for router) */
- uint32 cell_clients; /* All clients in cell */
- uint32 cell_servers; /* All servers in cell */
- uint32 cell_channels; /* All channels in cell */
- uint32 cell_chanclients; /* All clients on cell's channels */
- uint32 clients; /* All clients */
- uint32 servers; /* All servers */
- uint32 routers; /* All routers */
- uint32 channels; /* All channels */
- uint32 chanclients; /* All clients on channels */
- uint32 server_ops; /* All server operators */
- uint32 router_ops; /* All router operators */
+ uint32 cell_clients; /* All clients in cell */
+ uint32 cell_servers; /* All servers in cell */
+ uint32 cell_channels; /* All channels in cell */
+ uint32 cell_chanclients; /* All clients on cell's channels */
+ uint32 clients; /* All clients */
+ uint32 servers; /* All servers */
+ uint32 routers; /* All routers */
+ uint32 channels; /* All channels */
+ uint32 chanclients; /* All clients on channels */
+ uint32 server_ops; /* All server operators */
+ uint32 router_ops; /* All router operators */
/* General */
- uint32 conn_attempts; /* Connection attempts */
- uint32 conn_failures; /* Connection failure */
- uint32 auth_attempts; /* Authentication attempts */
- uint32 auth_failures; /* Authentication failures */
- uint32 packets_sent; /* Sent packets */
- uint32 packets_received; /* Received packets */
+ uint32 conn_attempts; /* Connection attempts */
+ uint32 conn_failures; /* Connection failure */
+ uint32 auth_attempts; /* Authentication attempts */
+ uint32 auth_failures; /* Authentication failures */
+ uint32 packets_sent; /* Sent packets */
+ uint32 packets_received; /* Received packets */
} SilcServerStatistics;
typedef struct {
} while(0)
/* Prototypes */
+SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final);
#endif
Internet Drafts that are a must read for those who wants to understand
the function of these protocols. The most important references are
the Secure Internet Live Conferencing, Protocol Specification [SILC1]
-and SILC Packet Protocol [SILC2] Internet Drafts.
+and the SILC Packet Protocol [SILC2] Internet Drafts.
The protocol is intended to be used with the SILC protocol thus it
does not define own framework that could be used. The framework is
be used in current SILC session. The keys are valid only for some period
of time (usually an hour) or at most until the session ends. These keys
are used to protect packets like commands, command replies and other
-communication between two entities. If connection is server to server
+communication between two entities. If connection is server to router
connection, the keys are used to protect all traffic between those
servers. In client connections usually all the packets are protected
with this key except channel messages; channels has their own keys and
The Key Exchange Start Payload is used to tell connecting entities what
security properties and algorithms should be used in the communication.
-If perfect forward secrecy (PFS) is not desired (PFS is undefined by
-default) Key Exchange Start Payload is sent only once per session, thus,
-for example, re-keying will not cause sending of a new payload. If PFS
-is desired, re-keying will always cause new key exchange thus causes
-sending of a new Key Exchange Start Payload.
+The Key Exchange Start Payload is sent only once per session. Even if
+the PFS (Perfect Forward Secrecy) flag is se the Key Exchange Start Payload
+is not re-sent. When PFS is desired the Key Exchange Payloads are sent
+to negotiate new key material. The procedure is equivalent to the very
+first negotiation except that the Key Exchange Start Payload is not sent.
-When performing first key exchange this payload is never encrypted, as
-there are no existing keys to encrypt it with. If performing re-keying
-(PFS was selected) this payload is encrypted with the existing key and
-encryption algorithm.
+As this payload is used only with the very first key exchnage the payload
+is never encrypted, as there are no keys to encrypt it with.
A cookie is also sent in this payload. A cookie is used to uniform the
payload so that none of the key exchange parties can determine this
Perfect Forward Secrecy (PFS) to be used in the
key exchange protocol. If not set, re-keying
- is performed using the old key. When PFS is used,
+ is performed using the old key. See the [SILC1]
+ for more information on this issue. When PFS is used,
re-keying and creating new keys for any particular
- purpose will cause new key exchange.
-
- Rest of the flags are reserved for the future and
- must not be set.
+ purpose will cause new key exchange. In this key
+ exchange only the Key Exchange Payload is sent and
+ the Key Exchange Start Payload must not be sent.
+ When doing PFS the Key Exchange Payloads are
+ encrypted with the old keys. With the PFS, the
+ Mutual Authentication flag must be ignored.
Mutual Authentication 0x04
set this but also responder may set this even if
initiator did not set it.
+ Rest of the flags are reserved for the future and
+ must not be set.
+
o Payload Length (2 bytes) - Length of the entire Key Exchange
Start payload, not including any other field.
The key exchange begins by sending SILC_PACKET_KEY_EXCHANGE packet with
Key Exchange Start Payload to select the security properties to be used
-in the key exchange and later in the communication.
+in the key exchange and later in the communication.
After Key Exchange Start Payload has been processed by both of the
parties the protocol proceeds as follows:
negotiated to be used in the connection with Key Exchange Start Payload
and SILC_PACKET_KEY_EXCHANGE packet. However, the first group must be
proposed in the Key Exchange Start Payload regardless of any other
-requested group (however, it does not have to be the first on the list).
+requested group (however, it does not have to be the first in the list).
.ti 0
.in 3
-The generator used with this prime is g = 2. The group order q is
+The generator used with this prime is g = 2. The group order q is
(p - 1) / 2.
This group was taken from the OAKLEY specification.
670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF
.in 3
-The generator used with this prime is g = 2. The group order q is
+The generator used with this prime is g = 2. The group order q is
(p - 1) / 2.
This group was taken from the OAKLEY specification.
indicate the status of the protocol. Implementations may map the
status types to human readable error message. All types except the
SILC_SKE_STATUS_OK type must be sent in SILC_PACKET_FAILURE packet.
-The length of status is 32 bits (4 bytes). Following status types are
+The length of status is 32 bits (4 bytes). Following status types are
defined:
.in 6
Provided signature was incorrect.
-10 SILC_SKE_STATUS_BAD_VERSION
+10 SILC_SKE_STATUS_BAD_VERSION
Provided version string was not acceptable.
.in 3
EMail: priikone@poseidon.pspt.fi
-This Internet-Draft expires 6 Jun 2001
-
+This Internet-Draft expires 6 Jun 2001
\ No newline at end of file
2.10 Packet Reception ......................................... 43
2.11 Packet Routing ........................................... 44
2.12 Packet Broadcasting ...................................... 45
- 2.13 Packet Tunneling ......................................... 45
3 Security Considerations ....................................... 46
4 References .................................................... 46
5 Author's Address .............................................. 47
section 2.13 Packet Broadcasting for description of
packet broadcasting.
-
- Tunneled 0x08
-
- Marks that the packet is tunneled. Tunneling means
- that extra SILC Packet Header has been applied to the
- original packet. The outer header has this flag
- set. See section 2.14 Packet Tunneling for more
- information.
.in 3
routers may keep these informations up to date.
-.ti 0
-2.13 Packet Tunneling
-
-Tunneling is a feature that is available in SILC protocol. Tunneling
-means that extra SILC Packet Header is applied to the original packet
-and thus hiding the original packet entirely. There can be some
-interesting applications using tunneling, such as, using ID's based on
-private network IP addresses inside in the tunneled packet. This can
-open many interesting features relating to connecting to private network
-from the Internet with SILC and many more. However, this feature is
-optional currently in SILC as there does not exist thorough analysis of
-this feature. It is with out a doubt that there will be many more
-applications that has not yet been discovered. Thus, it is left
-to Internet Community to investigate the use of tunneling in SILC
-protocol. This document is updated according those investigations
-and additional documents on the issue may be written.
-
-
.ti 0
3 Security Considerations
Session keys should be regenerated periodically, say, once in an hour.
The re-key process is started by sending SILC_PACKET_REKEY packet to
-other end, to indicate that re-key must be performed.
+other end, to indicate that re-key must be performed. The initiator
+of the connection should perform the re-key.
If perfect forward secrecy (PFS) flag was selected in the SILC Key
Exchange protocol [SILC3] the re-key must cause new key exchange with
If PFS flag was not set, which is the default case, then re-key is done
without executing SKE protocol. In this case, the new key is created by
-hashing the old key with hash function selected earlier in the SKE
-protocol. If the digest length of the hash function is too short for the
-key, then the key is distributed as described in section Processing the
-Key Material in [SILC3]. After both parties has regenerated the session
-key, both send SILC_PACKET_REKEY_DONE packet to each other. These packets
-are still secured with the old key. After these packets, the following
-packets must be protected with the new key.
+providing the current sending encryption key to the SKE protocol's key
+processing function. The process is described in the section Processing
+the Key Material in [SILC3]. The difference in the processing is that
+the initial data for the hash function is the current sending encryption
+key and not the SKE's KEY and HASH values. Other than that, the key
+processing is equivalent to normal SKE negotiation.
+
+After both parties has regenerated the session key, both send
+SILC_PACKET_REKEY_DONE packet to each other. These packets are still
+secured with the old key. After these packets, the subsequent packets
+must be protected with the new key.
.ti 0
#define SILC_PACKET_FLAG_PRIVMSG_KEY 0x01
#define SILC_PACKET_FLAG_LIST 0x02
#define SILC_PACKET_FLAG_BROADCAST 0x04
-#define SILC_PACKET_FLAG_TUNNELED 0x08
/* Rest of flags still available
+#define SILC_PACKET_FLAG_XXX 0x08
#define SILC_PACKET_FLAG_XXX 0x10
#define SILC_PACKET_FLAG_XXX 0x20
#define SILC_PACKET_FLAG_XXX 0x40