From 9621b64787287e7cc67061754d80566782cc76ea Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Wed, 4 Apr 2001 14:36:20 +0000 Subject: [PATCH] updates. --- CHANGES | 25 +++ apps/silc/local_command.c | 7 - apps/silcd/idlist.c | 20 +- apps/silcd/idlist.h | 30 ++- apps/silcd/packet_receive.c | 29 +++ apps/silcd/packet_receive.h | 3 + apps/silcd/protocol.c | 274 +++++++++++++++++++++-- apps/silcd/protocol.h | 29 ++- apps/silcd/server.c | 152 ++++++++++++- apps/silcd/server_internal.h | 49 ++-- doc/draft-riikonen-silc-ke-auth-02.nroff | 51 +++-- doc/draft-riikonen-silc-pp-02.nroff | 27 --- doc/draft-riikonen-silc-spec-02.nroff | 21 +- lib/silccore/silcpacket.h | 2 +- 14 files changed, 582 insertions(+), 137 deletions(-) diff --git a/CHANGES b/CHANGES index f4fff9d6..6a860723 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,28 @@ +Wed Apr 4 16:32:31 EEST 2001 Pekka Riikonen + + * 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 * Defined uint8, int8, uint16, int16, uint32, int32, uint64 and diff --git a/apps/silc/local_command.c b/apps/silc/local_command.c index db1f9c6d..fae582a7 100644 --- a/apps/silc/local_command.c +++ b/apps/silc/local_command.c @@ -302,13 +302,6 @@ static void keyagr_completion(SilcClient client, 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, diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index 7e4aa752..ba9eaf66 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -36,10 +36,9 @@ void silc_idlist_add_data(void *entry, SilcIDListData idata) SilcIDListData data = (SilcIDListData)entry; data->send_key = idata->send_key; data->receive_key = idata->receive_key; + data->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; @@ -55,12 +54,15 @@ void silc_idlist_del_data(void *entry) 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); } @@ -250,6 +252,8 @@ silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id, int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry) { + SILC_LOG_DEBUG(("Start")); + if (entry) { /* Remove from cache */ if (entry->id) @@ -321,6 +325,8 @@ silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname, int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry) { + SILC_LOG_DEBUG(("Start")); + if (entry) { /* Remove from cache */ if (entry->id) @@ -609,6 +615,8 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode, int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry) { + SILC_LOG_DEBUG(("Start")); + if (entry) { SilcChannelClientEntry chl; diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h index eff107b6..803392f2 100644 --- a/apps/silcd/idlist.h +++ b/apps/silcd/idlist.h @@ -40,6 +40,17 @@ typedef struct { 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. @@ -58,20 +69,21 @@ typedef struct { 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; /* @@ -264,7 +276,7 @@ typedef struct SilcChannelClientEntryStruct { 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 @@ -299,7 +311,7 @@ struct SilcClientEntryStruct { int mode; long last_command; - char fast_command; + uint8 fast_command; /* Pointer to the router */ SilcServerEntry router; @@ -343,7 +355,7 @@ struct SilcClientEntryStruct { 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 @@ -410,7 +422,7 @@ struct SilcChannelEntryStruct { char *channel_name; uint32 mode; SilcChannelID *id; - int global_users; + bool global_users; char *topic; char *cipher; char *hmac_name; diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 2f61ac89..2d254cfd 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -2026,3 +2026,32 @@ void silc_server_connection_auth_request(SilcServer server, 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); +} diff --git a/apps/silcd/packet_receive.h b/apps/silcd/packet_receive.h index 956c4223..0f14ce04 100644 --- a/apps/silcd/packet_receive.h +++ b/apps/silcd/packet_receive.h @@ -72,5 +72,8 @@ void silc_server_key_agreement(SilcServer server, void silc_server_connection_auth_request(SilcServer server, SilcSocketConnection sock, SilcPacketContext *packet); +void silc_server_rekey(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet); #endif diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c index 5faa3248..339f9881 100644 --- a/apps/silcd/protocol.c +++ b/apps/silcd/protocol.c @@ -61,7 +61,7 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske, SilcPKCS pkcs, SilcHash hash, SilcHmac hmac, - int is_responder) + bool is_responder) { SilcUnknownEntry conn_data; SilcIDListData idata; @@ -82,26 +82,33 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske, } 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); @@ -919,7 +926,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) 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); @@ -986,6 +993,231 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) } } +/* + * 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) @@ -994,6 +1226,8 @@ 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 */ @@ -1004,4 +1238,6 @@ void silc_server_protocols_unregister(void) 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); } diff --git a/apps/silcd/protocol.h b/apps/silcd/protocol.h index e26a58e0..1977bf8a 100644 --- a/apps/silcd/protocol.h +++ b/apps/silcd/protocol.h @@ -22,10 +22,11 @@ #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 { @@ -35,7 +36,7 @@ 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. */ @@ -55,7 +56,7 @@ typedef struct { SilcSocketConnection sock; /* TRUE if we are receiving part of the protocol */ - int responder; + bool responder; /* SKE object from Key Exchange protocol. */ SilcSKE ske; @@ -80,6 +81,18 @@ typedef struct { 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); @@ -90,6 +103,8 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske, SilcPKCS pkcs, SilcHash hash, SilcHmac hmac, - int is_responder); + bool is_responder); +void silc_server_protocol_rekey_generate(SilcServer server, + SilcServerRekeyInternalContext *ctx); #endif diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 3ef61613..1ba577a4 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -39,6 +39,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process); 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 @@ -709,7 +710,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) (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; @@ -719,6 +720,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) 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); @@ -744,6 +746,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) 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); @@ -765,7 +768,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) 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; @@ -786,6 +789,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) 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) @@ -845,6 +849,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) SilcBuffer packet; SilcServerHBContext hb_context; unsigned char *id_string; + SilcIDListData idata; SILC_LOG_DEBUG(("Start")); @@ -909,7 +914,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) 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 @@ -920,6 +926,14 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) 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); @@ -1049,7 +1063,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second) 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")); @@ -1058,6 +1072,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second) 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); @@ -1084,6 +1099,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second) 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); @@ -1105,7 +1121,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second) 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; @@ -1157,6 +1173,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) 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) @@ -1902,6 +1919,46 @@ void silc_server_packet_parse_type(SilcServer server, 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; @@ -3541,3 +3598,88 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server, 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); +} diff --git a/apps/silcd/server_internal.h b/apps/silcd/server_internal.h index 93d046ad..bc215e07 100644 --- a/apps/silcd/server_internal.h +++ b/apps/silcd/server_internal.h @@ -25,35 +25,35 @@ 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 { @@ -187,5 +187,6 @@ do { \ } while(0) /* Prototypes */ +SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final); #endif diff --git a/doc/draft-riikonen-silc-ke-auth-02.nroff b/doc/draft-riikonen-silc-ke-auth-02.nroff index 34dbe96c..0a63644b 100644 --- a/doc/draft-riikonen-silc-ke-auth-02.nroff +++ b/doc/draft-riikonen-silc-ke-auth-02.nroff @@ -134,7 +134,7 @@ This document refers constantly to other SILC protocol specification 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 @@ -158,7 +158,7 @@ The purpose of SILC Key Exchange protocol is to create session keys to 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 @@ -195,16 +195,14 @@ by responder must include only one chosen property per list. 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 @@ -307,12 +305,15 @@ o Flags (1 byte) - Indicates flags to be used in the key 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 @@ -324,6 +325,9 @@ o Flags (1 byte) - Indicates flags to be used in the key 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. @@ -488,7 +492,7 @@ o Signature Data (variable length) - The signature signed 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: @@ -651,7 +655,7 @@ first group diffie-hellman-group1 is mandatory, other groups maybe 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 @@ -683,7 +687,7 @@ 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. @@ -721,7 +725,7 @@ C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F 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. @@ -735,7 +739,7 @@ returned in the SILC_PACKET_SUCCESS or SILC_PACKET_FAILURE packets to 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 @@ -789,7 +793,7 @@ defined: Provided signature was incorrect. -10 SILC_SKE_STATUS_BAD_VERSION +10 SILC_SKE_STATUS_BAD_VERSION Provided version string was not acceptable. .in 3 @@ -1059,5 +1063,4 @@ Finland 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 diff --git a/doc/draft-riikonen-silc-pp-02.nroff b/doc/draft-riikonen-silc-pp-02.nroff index 1e734c33..03d1f40e 100644 --- a/doc/draft-riikonen-silc-pp-02.nroff +++ b/doc/draft-riikonen-silc-pp-02.nroff @@ -111,7 +111,6 @@ Table of Contents 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 @@ -315,14 +314,6 @@ o Flags (1 byte) - Indicates flags to be used in packet 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 @@ -2558,24 +2549,6 @@ about newly registered clients, servers, channels etc. so that all the 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 diff --git a/doc/draft-riikonen-silc-spec-02.nroff b/doc/draft-riikonen-silc-spec-02.nroff index 6c6f800d..734a32c3 100644 --- a/doc/draft-riikonen-silc-spec-02.nroff +++ b/doc/draft-riikonen-silc-spec-02.nroff @@ -1777,7 +1777,8 @@ process. 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 @@ -1788,13 +1789,17 @@ will perform the SKE protocol. 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 diff --git a/lib/silccore/silcpacket.h b/lib/silccore/silcpacket.h index 7bc8a8a9..30a9cc51 100644 --- a/lib/silccore/silcpacket.h +++ b/lib/silccore/silcpacket.h @@ -61,8 +61,8 @@ typedef unsigned char SilcPacketFlags; #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 -- 2.24.0