+Thu Apr 5 17:42:30 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added the PFS support as defined in the specification to the
+ SKE protocol. Affected files lib/silcske/*.c.
+
+ * Added `ske_group' field to the SilcServerRekey context to hold
+ the number of the SKE group that is used with PFS in re-key.
+ Affected file silcd/idlist.h.
+
+ * Added PFS re-key support to the server. Affected file is
+ silcd/protocol.c.
+
+ * Added silc_protocol_cancel to cancel execution of the next
+ state of the protocol. Affected file is
+ lib/silccore/silcprotocol.[ch].
+
+ * Added the re-key support with and without PFS to the client
+ library. Re-key is performed once in an hour, by default.
+
+ * Removed the `hmac_key' and `hmac_key_len' fields from the
+ SilcClientConnection structure; not needed. Affected file is
+ lib/silcclient/client.h.
+
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
SilcPKCS pkcs,
SilcHash hash,
SilcHmac hmac,
+ SilcSKEDiffieHellmanGroup group,
bool is_responder);
void silc_server_protocol_rekey_generate(SilcServer server,
SilcServerRekeyInternalContext *ctx);
+void
+silc_server_protocol_rekey_generate_pfs(SilcServer server,
+ SilcServerRekeyInternalContext *ctx);
#endif
ctx->ske->prop->pkcs,
ctx->ske->prop->hash,
ctx->ske->prop->hmac,
+ ctx->ske->prop->group,
ctx->responder)) {
silc_protocol_free(protocol);
sock->protocol = NULL;
SilcServerEntry id_entry;
SilcBuffer packet;
SilcServerHBContext hb_context;
- SilcServerRekeyContext rekey;
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
server->timeout_queue);
/* Register re-key timeout */
- /* XXX this leaks memory as this is not freed anywhere, currently */
- rekey = silc_calloc(1, sizeof(*rekey));
- rekey->server = server;
- rekey->sock = sock;
- rekey->timeout = 3600; /* XXX hardcoded */
+ idata->rekey->timeout = 3600; /* XXX hardcoded */
+ idata->rekey->context = (void *)server;
silc_task_register(server->timeout_queue, sock->sock,
silc_server_rekey_callback,
- (void *)rekey, rekey->timeout, 0,
+ (void *)sock, idata->rekey->timeout, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
/* If we are router then announce our possible servers. */
ctx->ske->prop->pkcs,
ctx->ske->prop->hash,
ctx->ske->prop->hmac,
+ ctx->ske->prop->group,
ctx->responder)) {
silc_protocol_free(protocol);
sock->protocol = NULL;
break;
if (sock->protocol && sock->protocol->protocol &&
- sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
-
- SilcServerKEInternalContext *proto_ctx =
- (SilcServerKEInternalContext *)sock->protocol->context;
+ (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
+ sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
- if (proto_ctx->packet)
- silc_packet_context_free(proto_ctx->packet);
+ if (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);
- proto_ctx->packet = silc_packet_context_dup(packet);
- proto_ctx->dest_id_type = packet->src_id_type;
- proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
- packet->src_id_type);
- if (!proto_ctx->dest_id)
- break;
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ } else {
+ SilcServerKEInternalContext *proto_ctx =
+ (SilcServerKEInternalContext *)sock->protocol->context;
+
+ if (proto_ctx->packet)
+ silc_packet_context_free(proto_ctx->packet);
+
+ proto_ctx->packet = silc_packet_context_dup(packet);
+ proto_ctx->dest_id_type = packet->src_id_type;
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!proto_ctx->dest_id)
+ break;
- /* Let the protocol handle the packet */
- sock->protocol->execute(server->timeout_queue, 0,
- sock->protocol, sock->sock,
- 0, 100000);
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock,
+ 0, 100000);
+ }
} else {
SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
"protocol active, packet dropped."));
break;
if (sock->protocol && sock->protocol->protocol &&
- sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
+ (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
+ sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
- SilcServerKEInternalContext *proto_ctx =
- (SilcServerKEInternalContext *)sock->protocol->context;
-
- if (proto_ctx->packet)
- silc_packet_context_free(proto_ctx->packet);
+ if (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);
- proto_ctx->packet = silc_packet_context_dup(packet);
- proto_ctx->dest_id_type = packet->src_id_type;
- proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
- packet->src_id_type);
- if (!proto_ctx->dest_id)
- break;
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ } else {
+ SilcServerKEInternalContext *proto_ctx =
+ (SilcServerKEInternalContext *)sock->protocol->context;
+
+ if (proto_ctx->packet)
+ silc_packet_context_free(proto_ctx->packet);
+
+ proto_ctx->packet = silc_packet_context_dup(packet);
+ proto_ctx->dest_id_type = packet->src_id_type;
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!proto_ctx->dest_id)
+ break;
- /* Let the protocol handle the packet */
- sock->protocol->execute(server->timeout_queue, 0,
- sock->protocol, sock->sock,
- 0, 100000);
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock,
+ 0, 100000);
+ }
} else {
SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
"protocol active, packet dropped."));
SILC_TASK_CALLBACK(silc_server_rekey_callback)
{
- SilcServerRekeyContext rekey = (SilcServerRekeyContext)context;
- SilcServer server = rekey->server;
+ SilcSocketConnection sock = (SilcSocketConnection)context;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
+ SilcServer server = (SilcServer)idata->rekey->context;
SilcProtocol protocol;
SilcServerRekeyInternalContext *proto_ctx;
to the protocol. */
proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
proto_ctx->server = (void *)server;
- proto_ctx->context = context;
- proto_ctx->sock = rekey->sock;
+ proto_ctx->sock = sock;
proto_ctx->responder = FALSE;
+ proto_ctx->pfs = idata->rekey->pfs;
/* 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);
- rekey->sock->protocol = protocol;
+ sock->protocol = protocol;
/* Run the protocol */
protocol->execute(server->timeout_queue, 0, protocol,
- rekey->sock->sock, 0, 0);
+ sock->sock, 0, 0);
/* Re-register re-key timeout */
- silc_task_register(server->timeout_queue, 0,
+ silc_task_register(server->timeout_queue, sock->sock,
silc_server_rekey_callback,
- context, rekey->timeout, 0,
+ context, idata->rekey->timeout, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
+ silc_protocol_cancel(server->timeout_queue, protocol);
silc_protocol_free(protocol);
sock->protocol = NULL;
if (ctx->keymat)
}
/* Take the keys into use */
- if (ctx->pfs == TRUE) {
-
- } else {
- /* Then just generate the new keys and take them into use */
+ if (ctx->pfs == TRUE)
+ silc_server_protocol_rekey_generate_pfs(server, ctx);
+ else
silc_server_protocol_rekey_generate(server, ctx);
- }
/* Cleanup */
silc_protocol_free(protocol);
SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
SILC_TASK_CALLBACK(silc_client_packet_parse_real);
+SILC_TASK_CALLBACK(silc_client_rekey_callback);
+SILC_TASK_CALLBACK(silc_client_rekey_final);
static void silc_client_packet_parse(SilcPacketParserContext *parser_context);
static void silc_client_packet_parse_type(SilcClient client,
ctx->ske->prop->cipher,
ctx->ske->prop->pkcs,
ctx->ske->prop->hash,
- ctx->ske->prop->hmac);
+ ctx->ske->prop->hmac,
+ ctx->ske->prop->group);
silc_ske_free_key_material(ctx->keymat);
/* Allocate internal context for the authentication protocol. This
conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
conn->remote_id_data_len = SILC_ID_SERVER_LEN;
+ /* Register re-key timeout */
+ conn->rekey->timeout = 3600; /* XXX hardcoded */
+ conn->rekey->context = (void *)client;
+ silc_task_register(client->timeout_queue, conn->sock->sock,
+ silc_client_rekey_callback,
+ (void *)conn->sock, conn->rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
silc_task_unregister_by_callback(client->timeout_queue,
silc_client_failure_callback);
silc_protocol_free(protocol);
case SILC_PACKET_KEY_EXCHANGE_1:
if (sock->protocol && sock->protocol->protocol &&
- sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
- SilcClientKEInternalContext *proto_ctx =
- (SilcClientKEInternalContext *)sock->protocol->context;
-
- if (proto_ctx->packet)
- silc_packet_context_free(proto_ctx->packet);
-
- proto_ctx->packet = silc_packet_context_dup(packet);
- proto_ctx->dest_id_type = packet->src_id_type;
- proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
- packet->src_id_type);
- if (!proto_ctx->dest_id)
- break;
-
- /* Let the protocol handle the packet */
- sock->protocol->execute(client->timeout_queue, 0,
- sock->protocol, sock->sock, 0, 0);
+ (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
+
+ if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
+ SilcClientRekeyInternalContext *proto_ctx =
+ (SilcClientRekeyInternalContext *)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(client->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ } else {
+ SilcClientKEInternalContext *proto_ctx =
+ (SilcClientKEInternalContext *)sock->protocol->context;
+
+ if (proto_ctx->packet)
+ silc_packet_context_free(proto_ctx->packet);
+
+ proto_ctx->packet = silc_packet_context_dup(packet);
+ proto_ctx->dest_id_type = packet->src_id_type;
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!proto_ctx->dest_id)
+ break;
+
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(client->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ }
} else {
SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
"protocol active, packet dropped."));
break;
case SILC_PACKET_KEY_EXCHANGE_2:
if (sock->protocol && sock->protocol->protocol &&
- sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
- SilcClientKEInternalContext *proto_ctx =
- (SilcClientKEInternalContext *)sock->protocol->context;
-
- if (proto_ctx->packet)
- silc_packet_context_free(proto_ctx->packet);
-
- proto_ctx->packet = silc_packet_context_dup(packet);
- proto_ctx->dest_id_type = packet->src_id_type;
- proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
- packet->src_id_type);
- if (!proto_ctx->dest_id)
- break;
-
- /* Let the protocol handle the packet */
- sock->protocol->execute(client->timeout_queue, 0,
- sock->protocol, sock->sock, 0, 0);
+ (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
+
+ if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
+ SilcClientRekeyInternalContext *proto_ctx =
+ (SilcClientRekeyInternalContext *)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(client->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ } else {
+ SilcClientKEInternalContext *proto_ctx =
+ (SilcClientKEInternalContext *)sock->protocol->context;
+
+ if (proto_ctx->packet)
+ silc_packet_context_free(proto_ctx->packet);
+
+ proto_ctx->packet = silc_packet_context_dup(packet);
+ proto_ctx->dest_id_type = packet->src_id_type;
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!proto_ctx->dest_id)
+ break;
+
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(client->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ }
} else {
SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
"protocol active, packet dropped."));
silc_client_key_agreement(client, sock, packet);
break;
+ case SILC_PACKET_REKEY:
+ SILC_LOG_DEBUG(("Re-key packet"));
+ /* We ignore this for now */
+ break;
+
+ case SILC_PACKET_REKEY_DONE:
+ SILC_LOG_DEBUG(("Re-key done packet"));
+
+ if (sock->protocol && sock->protocol->protocol &&
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
+
+ SilcClientRekeyInternalContext *proto_ctx =
+ (SilcClientRekeyInternalContext *)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(client->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_DEBUG(("Incorrect packet type %d, packet dropped", type));
break;
silc_cipher_free(conn->receive_key);
if (conn->hmac)
silc_hmac_free(conn->hmac);
- if (conn->hmac_key) {
- memset(conn->hmac_key, 0, conn->hmac_key_len);
- silc_free(conn->hmac_key);
- }
if (conn->pending_commands)
silc_dlist_uninit(conn->pending_commands);
+ if (conn->rekey)
+ silc_free(conn->rekey);
conn->sock = NULL;
conn->remote_port = 0;
conn->send_key = NULL;
conn->receive_key = NULL;
conn->hmac = NULL;
- conn->hmac_key = NULL;
- conn->hmac_key_len = 0;
conn->local_id = NULL;
conn->local_id_data = NULL;
conn->remote_host = NULL;
conn->current_channel = NULL;
conn->pending_commands = NULL;
+ conn->rekey = NULL;
silc_client_del_connection(client, conn);
}
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
}
+
+/* A timeout callback for the re-key. We will be the initiator of the
+ re-key protocol. */
+
+SILC_TASK_CALLBACK(silc_client_rekey_callback)
+{
+ SilcSocketConnection sock = (SilcSocketConnection)context;
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+ SilcClient client = (SilcClient)conn->rekey->context;
+ SilcProtocol protocol;
+ SilcClientRekeyInternalContext *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->client = (void *)client;
+ proto_ctx->sock = sock;
+ proto_ctx->responder = FALSE;
+ proto_ctx->pfs = conn->rekey->pfs;
+
+ /* Perform rekey protocol. Will call the final callback after the
+ protocol is over. */
+ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
+ &protocol, proto_ctx, silc_client_rekey_final);
+ sock->protocol = protocol;
+
+ /* Run the protocol */
+ protocol->execute(client->timeout_queue, 0, protocol,
+ sock->sock, 0, 0);
+
+ /* Re-register re-key timeout */
+ silc_task_register(client->timeout_queue, sock->sock,
+ silc_client_rekey_callback,
+ context, conn->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(silc_client_rekey_final)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientRekeyInternalContext *ctx =
+ (SilcClientRekeyInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ 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_cancel(client->timeout_queue, 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)
+ silc_client_protocol_rekey_generate_pfs(client, ctx);
+ else
+ silc_client_protocol_rekey_generate(client, 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);
+}
#define SILC_PROTOCOL_CLIENT_NONE 0
#define SILC_PROTOCOL_CLIENT_CONNECTION_AUTH 1
#define SILC_PROTOCOL_CLIENT_KEY_EXCHANGE 2
+#define SILC_PROTOCOL_CLIENT_REKEY 3
/* #define SILC_PROTOCOL_CLIENT_MAX 255 */
/* Internal context for key exchange protocol */
SilcTask timeout_task;
} SilcClientConnAuthInternalContext;
+/* Internal context for the rekey protocol */
+typedef struct {
+ void *client;
+ 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;
+} SilcClientRekeyInternalContext;
+
/* Prototypes */
void silc_client_protocols_register(void);
void silc_client_protocols_unregister(void);
SilcCipher cipher,
SilcPKCS pkcs,
SilcHash hash,
- SilcHmac hmac);
+ SilcHmac hmac,
+ SilcSKEDiffieHellmanGroup group);
+void silc_client_protocol_rekey_generate(SilcClient client,
+ SilcClientRekeyInternalContext *ctx);
+void
+silc_client_protocol_rekey_generate_pfs(SilcClient client,
+ SilcClientRekeyInternalContext *ctx);
#endif