/* $Id$ */
#include "clientlibincludes.h"
+#include "client_internal.h"
SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
+SILC_TASK_CALLBACK(silc_client_protocol_rekey);
extern char *silc_version_string;
/* Function that is called when SKE protocol sends packets to network. */
-static void silc_client_protocol_ke_send_packet(SilcSKE ske,
- SilcBuffer packet,
- SilcPacketType type,
- void *context)
+void silc_client_protocol_ke_send_packet(SilcSKE ske,
+ SilcBuffer packet,
+ SilcPacketType type,
+ void *context)
{
SilcProtocol protocol = (SilcProtocol)context;
SilcClientKEInternalContext *ctx =
/* Send the packet immediately */
silc_client_packet_send(client, ske->sock, type, NULL, 0, NULL, NULL,
packet->data, packet->len, TRUE);
-
}
/* Callback that is called when we have received KE2 payload from
responder. We try to verify the public key now. */
-static SilcSKEStatus
-silc_client_protocol_ke_verify_key(SilcSKE ske,
- unsigned char *pk_data,
- unsigned int pk_len,
- SilcSKEPKType pk_type,
- void *context)
+SilcSKEStatus silc_client_protocol_ke_verify_key(SilcSKE ske,
+ unsigned char *pk_data,
+ uint32 pk_len,
+ SilcSKEPKType pk_type,
+ void *context)
{
SilcProtocol protocol = (SilcProtocol)context;
SilcClientKEInternalContext *ctx =
SILC_LOG_DEBUG(("Start"));
- /* Verify server key from user. */
- if (!client->ops->verify_server_key(client, ctx->sock->user_data,
+ /* Verify public key from user. */
+ if (!client->ops->verify_public_key(client, ctx->sock->user_data,
+ ctx->sock->type,
pk_data, pk_len, pk_type))
return SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
/* Sets the negotiated key material into use for particular connection. */
-static void silc_client_protocol_ke_set_keys(SilcSKE ske,
- SilcSocketConnection sock,
- SilcSKEKeyMaterial *keymat,
- SilcCipher cipher,
- SilcPKCS pkcs,
- SilcHash hash)
+void silc_client_protocol_ke_set_keys(SilcSKE ske,
+ SilcSocketConnection sock,
+ SilcSKEKeyMaterial *keymat,
+ SilcCipher cipher,
+ SilcPKCS pkcs,
+ SilcHash hash,
+ SilcHmac hmac,
+ SilcSKEDiffieHellmanGroup group)
{
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
- SilcHash nhash;
SILC_LOG_DEBUG(("Setting new keys into use"));
ske->ke2_payload->pk_len);
#endif
+ conn->rekey = silc_calloc(1, sizeof(*conn->rekey));
+ conn->rekey->send_enc_key =
+ silc_calloc(keymat->enc_key_len / 8,
+ sizeof(*conn->rekey->send_enc_key));
+ memcpy(conn->rekey->send_enc_key,
+ keymat->send_enc_key, keymat->enc_key_len / 8);
+ conn->rekey->enc_key_len = keymat->enc_key_len / 8;
+
+ if (ske->start_payload->flags & SILC_SKE_SP_FLAG_PFS)
+ conn->rekey->pfs = TRUE;
+ conn->rekey->ske_group = silc_ske_group_get_number(group);
+
/* Save HMAC key to be used in the communication. */
- silc_hash_alloc(hash->hash->name, &nhash);
- silc_hmac_alloc(nhash, &conn->hmac);
+ silc_hmac_alloc(hmac->hmac->name, NULL, &conn->hmac);
silc_hmac_set_key(conn->hmac, keymat->hmac_key, keymat->hmac_key_len);
+
+ /* Save the HASH function */
+ silc_hash_alloc(hash->hash->name, &conn->hash);
}
/* Checks the version string of the server. */
SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
- unsigned int len)
+ uint32 len)
{
SilcClientConnection conn = (SilcClientConnection)ske->sock->user_data;
SilcClient client = (SilcClient)ske->user_data;
ske->user_data = (void *)client;
if (ctx->responder == TRUE) {
-#if 0
- SilcBuffer start_payload;
-
-
/* Start the key exchange by processing the received security
properties packet from initiator. */
status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
- start_payload,
- silc_client_protocol_ke_send_packet,
- context);
-#endif
+ silc_version_string,
+ ctx->packet->buffer, TRUE,
+ NULL, NULL);
} else {
SilcSKEStartPayload *start_payload;
to the remote end. */
status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
start_payload,
- silc_client_protocol_ke_send_packet,
+ ctx->send_packet,
context);
}
return;
}
- /* Advance the state of the protocol. */
+ /* Advance protocol state and call the next state if we are responder */
protocol->state++;
+ if (ctx->responder == TRUE)
+ protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 100000);
}
break;
case 2:
* Phase 1
*/
if (ctx->responder == TRUE) {
-#if 0
+ /* Sends the selected security properties to the initiator. */
status =
silc_ske_responder_phase_1(ctx->ske,
ctx->ske->start_payload,
- silc_server_protocol_ke_send_packet,
+ ctx->send_packet,
context);
-#endif
} else {
/* Call Phase-1 function. This processes the Key Exchange Start
paylaod reply we just got from the responder. The callback
return;
}
- /* Advance the state of the protocol and call the next state. */
+ /* Advance protocol state and call next state if we are initiator */
protocol->state++;
- protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+ if (ctx->responder == FALSE)
+ protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 100000);
}
break;
case 3:
* Phase 2
*/
if (ctx->responder == TRUE) {
-#if 0
- status =
- silc_ske_responder_phase_2(ctx->ske,
- ctx->ske->start_payload,
- silc_server_protocol_ke_send_packet,
- context);
-#endif
+ /* Process the received Key Exchange 1 Payload packet from
+ the initiator. This also creates our parts of the Diffie
+ Hellman algorithm. */
+ status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer,
+ ctx->verify, context, NULL, NULL);
} else {
/* Call the Phase-2 function. This creates Diffie Hellman
key exchange parameters and sends our public part inside
Key Exhange 1 Payload to the responder. */
- status =
- silc_ske_initiator_phase_2(ctx->ske,
- client->public_key,
- silc_client_protocol_ke_send_packet,
- context);
+ status = silc_ske_initiator_phase_2(ctx->ske,
+ client->public_key,
+ client->private_key,
+ ctx->send_packet,
+ context);
}
if (status != SILC_SKE_STATUS_OK) {
return;
}
- /* Advance the state of the protocol. */
+ /* Advance protocol state and call the next state if we are responder */
protocol->state++;
+ if (ctx->responder == TRUE)
+ protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 100000);
}
break;
case 4:
* Finish protocol
*/
if (ctx->responder == TRUE) {
- status = 0;
-#if 0
+ /* This creates the key exchange material and sends our
+ public parts to the initiator inside Key Exchange 2 Payload. */
status =
- silc_ske_responder_phase_2(ctx->ske,
- ctx->ske->start_payload,
- silc_server_protocol_ke_send_packet,
- context);
-#endif
+ silc_ske_responder_finish(ctx->ske,
+ client->public_key, client->private_key,
+ SILC_SKE_PK_TYPE_SILC,
+ ctx->send_packet,
+ context);
+ status = 0;
} else {
/* Finish the protocol. This verifies the Key Exchange 2 payload
sent by responder. */
status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer,
- silc_client_protocol_ke_verify_key,
- context, NULL, NULL);
+ ctx->verify, context, NULL, NULL);
}
if (status != SILC_SKE_STATUS_OK) {
/* Send Ok to the other end. We will end the protocol as server
sends Ok to us when we will take the new keys into use. */
- silc_ske_end(ctx->ske, silc_client_protocol_ke_send_packet, context);
+ if (ctx->responder == FALSE)
+ silc_ske_end(ctx->ske, ctx->send_packet, context);
/* End the protocol on the next round */
protocol->state = SILC_PROTOCOL_STATE_END;
* End protocol
*/
SilcSKEKeyMaterial *keymat;
- int key_len = silc_cipher_get_key_len(ctx->ske->prop->cipher, NULL);
+ int key_len = silc_cipher_get_key_len(ctx->ske->prop->cipher);
int hash_len = ctx->ske->prop->hash->hash->hash_len;
/* Process the key material */
keymat = silc_calloc(1, sizeof(*keymat));
- silc_ske_process_key_material(ctx->ske, 16, key_len, hash_len,
- keymat);
+ status = silc_ske_process_key_material(ctx->ske, 16, key_len, hash_len,
+ keymat);
+ if (status != SILC_SKE_STATUS_OK) {
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 300000);
+ silc_ske_free_key_material(keymat);
+ return;
+ }
+ ctx->keymat = keymat;
- /* Take the negotiated keys into use. */
- silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, keymat,
- ctx->ske->prop->cipher,
- ctx->ske->prop->pkcs,
- ctx->ske->prop->hash);
+ /* Send Ok to the other end if we are responder. If we are initiator
+ we have sent this already. */
+ if (ctx->responder == TRUE)
+ silc_ske_end(ctx->ske, ctx->send_packet, context);
- silc_ske_free_key_material(keymat);
+ /* Unregister the timeout task since the protocol has ended.
+ This was the timeout task to be executed if the protocol is
+ not completed fast enough. */
+ if (ctx->timeout_task)
+ silc_task_unregister(client->timeout_queue, ctx->timeout_task);
/* Protocol has ended, call the final callback */
if (protocol->final_callback)
/* Send abort notification */
silc_ske_abort(ctx->ske, ctx->ske->status,
- silc_client_protocol_ke_send_packet,
- context);
+ ctx->send_packet, context);
/* On error the final callback is always called. */
if (protocol->final_callback)
* Received failure from remote.
*/
+ /* Unregister the timeout task since the protocol has ended.
+ This was the timeout task to be executed if the protocol is
+ not completed fast enough. */
+ if (ctx->timeout_task)
+ silc_task_unregister(client->timeout_queue, ctx->timeout_task);
+
/* On error the final callback is always called. */
if (protocol->final_callback)
protocol->execute_final(client->timeout_queue, 0, protocol, fd);
* Connection Authentication protocol functions
*/
+static int
+silc_client_get_public_key_auth(SilcClient client,
+ char *filepath,
+ unsigned char *auth_data,
+ uint32 *auth_data_len,
+ SilcSKE ske)
+{
+ int len;
+ SilcPKCS pkcs;
+ SilcBuffer auth;
+ SilcPublicKey pub_key;
+
+ if (!silc_pkcs_load_public_key(filepath,&pub_key, SILC_PKCS_FILE_PEM))
+ if (!silc_pkcs_load_public_key(filepath, &pub_key, SILC_PKCS_FILE_BIN))
+ return FALSE;
+
+ silc_pkcs_alloc(pub_key->name, &pkcs);
+ if (!silc_pkcs_public_key_set(pkcs, pub_key)) {
+ silc_pkcs_free(pkcs);
+ silc_pkcs_public_key_free(pub_key);
+ return FALSE;
+ }
+
+ /* Make the authentication data. Protocol says it is HASH plus
+ KE Start Payload. */
+ len = ske->hash_len + ske->start_payload_copy->len;
+ auth = silc_buffer_alloc(len);
+ silc_buffer_pull_tail(auth, len);
+ silc_buffer_format(auth,
+ SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
+ SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
+ ske->start_payload_copy->len),
+ SILC_STR_END);
+
+ if (silc_pkcs_sign(pkcs, auth->data, auth->len, auth_data, auth_data_len)) {
+ silc_pkcs_free(pkcs);
+ silc_buffer_free(auth);
+ silc_pkcs_public_key_free(pub_key);
+ return TRUE;
+ }
+
+ silc_pkcs_free(pkcs);
+ silc_buffer_free(auth);
+ silc_pkcs_public_key_free(pub_key);
+ return FALSE;
+}
+
SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
{
SilcProtocol protocol = (SilcProtocol)context;
SilcBuffer packet;
int payload_len = 0;
unsigned char *auth_data = NULL;
- unsigned int auth_data_len = 0;
+ uint32 auth_data_len = 0;
switch(ctx->auth_meth) {
case SILC_AUTH_NONE:
break;
case SILC_AUTH_PUBLIC_KEY:
- /* XXX */
- break;
+ {
+ unsigned char sign[1024];
+
+ /* Public key authentication */
+ silc_client_get_public_key_auth(client, ctx->auth_data,
+ sign, &auth_data_len,
+ ctx->ske);
+ auth_data = silc_calloc(auth_data_len, sizeof(*auth_data));
+ memcpy(auth_data, sign, auth_data_len);
+ break;
+ }
}
payload_len = 4 + auth_data_len;
}
}
+/*
+ * Re-key protocol routines
+ */
+
+/* Actually takes the new keys into use. */
+
+static void
+silc_client_protocol_rekey_validate(SilcClient client,
+ SilcClientRekeyInternalContext *ctx,
+ SilcSocketConnection sock,
+ SilcSKEKeyMaterial *keymat)
+{
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+
+ if (ctx->responder == TRUE) {
+ silc_cipher_set_key(conn->send_key, keymat->receive_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(conn->send_key, keymat->receive_iv);
+ silc_cipher_set_key(conn->receive_key, keymat->send_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(conn->receive_key, keymat->send_iv);
+ } else {
+ silc_cipher_set_key(conn->send_key, keymat->send_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(conn->send_key, keymat->send_iv);
+ silc_cipher_set_key(conn->receive_key, keymat->receive_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(conn->receive_key, keymat->receive_iv);
+ }
+
+ silc_hmac_set_key(conn->hmac, keymat->hmac_key, keymat->hmac_key_len);
+
+ /* Save the current sending encryption key */
+ memset(conn->rekey->send_enc_key, 0, conn->rekey->enc_key_len);
+ silc_free(conn->rekey->send_enc_key);
+ conn->rekey->send_enc_key =
+ silc_calloc(keymat->enc_key_len / 8,
+ sizeof(*conn->rekey->send_enc_key));
+ memcpy(conn->rekey->send_enc_key, keymat->send_enc_key,
+ keymat->enc_key_len / 8);
+ conn->rekey->enc_key_len = keymat->enc_key_len / 8;
+}
+
+/* This function actually re-generates (when not using PFS) the keys and
+ takes them into use. */
+
+void silc_client_protocol_rekey_generate(SilcClient client,
+ SilcClientRekeyInternalContext *ctx)
+{
+ SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
+ SilcSKEKeyMaterial *keymat;
+ uint32 key_len = silc_cipher_get_key_len(conn->send_key);
+ uint32 hash_len = conn->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(conn->rekey->send_enc_key,
+ conn->rekey->enc_key_len,
+ 16, key_len, hash_len,
+ conn->hash, keymat);
+
+ /* Set the keys into use */
+ silc_client_protocol_rekey_validate(client, ctx, ctx->sock, keymat);
+
+ silc_ske_free_key_material(keymat);
+}
+
+/* This function actually re-generates (with PFS) the keys and
+ takes them into use. */
+
+void
+silc_client_protocol_rekey_generate_pfs(SilcClient client,
+ SilcClientRekeyInternalContext *ctx)
+{
+ SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
+ SilcSKEKeyMaterial *keymat;
+ uint32 key_len = silc_cipher_get_key_len(conn->send_key);
+ uint32 hash_len = conn->hash->hash->hash_len;
+ unsigned char *tmpbuf;
+ uint32 klen;
+
+ SILC_LOG_DEBUG(("Generating new session keys (with PFS)"));
+
+ /* Encode KEY to binary data */
+ tmpbuf = silc_mp_mp2bin(ctx->ske->KEY, 0, &klen);
+
+ /* Generate the new key */
+ keymat = silc_calloc(1, sizeof(*keymat));
+ silc_ske_process_key_material_data(tmpbuf, klen, 16, key_len, hash_len,
+ conn->hash, keymat);
+
+ /* Set the keys into use */
+ silc_client_protocol_rekey_validate(client, ctx, ctx->sock, keymat);
+
+ memset(tmpbuf, 0, klen);
+ silc_free(tmpbuf);
+ silc_ske_free_key_material(keymat);
+}
+
+/* Packet sending callback. This function is provided as packet sending
+ routine to the Key Exchange functions. */
+
+static void
+silc_client_protocol_rekey_send_packet(SilcSKE ske,
+ SilcBuffer packet,
+ SilcPacketType type,
+ void *context)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientRekeyInternalContext *ctx =
+ (SilcClientRekeyInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+
+ /* Send the packet immediately */
+ silc_client_packet_send(client, ctx->sock, type, NULL, 0, NULL, NULL,
+ packet->data, packet->len, TRUE);
+}
+
+/* Performs re-key as defined in the SILC protocol specification. */
+
+SILC_TASK_CALLBACK(silc_client_protocol_rekey)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientRekeyInternalContext *ctx =
+ (SilcClientRekeyInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
+ SilcSKEStatus status;
+
+ 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.
+ */
+
+ if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_1) {
+ /* Error in protocol */
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(client->timeout_queue, 0, protocol, fd,
+ 0, 300000);
+ }
+
+ ctx->ske = silc_ske_alloc();
+ ctx->ske->rng = client->rng;
+ ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop));
+ silc_ske_get_group_by_number(conn->rekey->ske_group,
+ &ctx->ske->prop->group);
+
+ status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer,
+ NULL, NULL, NULL, NULL);
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(client->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+
+ /* Advance the protocol state */
+ protocol->state++;
+ protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+ } else {
+ /*
+ * Do normal and simple re-key.
+ */
+
+ /* Send the REKEY_DONE to indicate we will take new keys into use */
+ silc_client_packet_send(client, ctx->sock,
+ SILC_PACKET_REKEY_DONE,
+ NULL, 0, NULL, NULL, NULL, 0, TRUE);
+
+ /* The protocol ends in next stage. */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ }
+
+ } else {
+ /*
+ * We are the initiator of this protocol
+ */
+
+ /* Start the re-key by sending the REKEY packet */
+ silc_client_packet_send(client, ctx->sock, SILC_PACKET_REKEY,
+ NULL, 0, NULL, NULL, NULL, 0, TRUE);
+
+ if (ctx->pfs == TRUE) {
+ /*
+ * Use Perfect Forward Secrecy, ie. negotiate the key material
+ * using the SKE protocol.
+ */
+ ctx->ske = silc_ske_alloc();
+ ctx->ske->rng = client->rng;
+ ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop));
+ silc_ske_get_group_by_number(conn->rekey->ske_group,
+ &ctx->ske->prop->group);
+
+ status =
+ silc_ske_initiator_phase_2(ctx->ske, NULL, NULL,
+ silc_client_protocol_rekey_send_packet,
+ context);
+
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(client->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+
+ /* Advance the protocol state */
+ protocol->state++;
+ } else {
+ /*
+ * Do normal and simple re-key.
+ */
+
+ /* The protocol ends in next stage. We have sent the REKEY packet
+ and now we just wait that the responder send REKEY_DONE and
+ the we'll generate the new key, simple. */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ }
+ }
+ }
+ break;
+
+ case 2:
+ /*
+ * Second state, used only when oding re-key with PFS.
+ */
+ if (ctx->responder == TRUE) {
+ if (ctx->pfs == TRUE) {
+ /*
+ * Send our KE packe to the initiator now that we've processed
+ * the initiator's KE packet.
+ */
+ status =
+ silc_ske_responder_finish(ctx->ske, NULL, NULL,
+ SILC_SKE_PK_TYPE_SILC,
+ silc_client_protocol_rekey_send_packet,
+ context);
+
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(client->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+ }
+
+ } else {
+ if (ctx->pfs == TRUE) {
+ /*
+ * The packet type must be KE packet
+ */
+ if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_2) {
+ /* Error in protocol */
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 300000);
+ }
+
+ status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer,
+ NULL, NULL, NULL, NULL);
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(client->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+ }
+ }
+
+ /* Send the REKEY_DONE to indicate we will take new keys into use
+ now. */
+ silc_client_packet_send(client, ctx->sock, SILC_PACKET_REKEY_DONE,
+ NULL, 0, NULL, NULL, 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->packet->type != SILC_PACKET_REKEY_DONE) {
+ /* Error in protocol */
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+ }
+
+ if (ctx->responder == FALSE) {
+ if (ctx->pfs == FALSE) {
+ /* Send the REKEY_DONE to indicate we will take new keys into use
+ now. */
+ silc_client_packet_send(client, ctx->sock,
+ SILC_PACKET_REKEY_DONE,
+ NULL, 0, NULL, NULL, NULL, 0, TRUE);
+ }
+ }
+
+ /* Protocol has ended, call the final callback */
+ if (protocol->final_callback)
+ protocol->execute_final(client->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_client_protocol_ke_send_packet,
+ context);
+ }
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ protocol->execute_final(client->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(client->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ break;
+
+ case SILC_PROTOCOL_STATE_UNKNOWN:
+ break;
+ }
+
+}
+
/* Registers protocols used in client */
void silc_client_protocols_register(void)
silc_client_protocol_connection_auth);
silc_protocol_register(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
silc_client_protocol_key_exchange);
+ silc_protocol_register(SILC_PROTOCOL_CLIENT_REKEY,
+ silc_client_protocol_rekey);
}
/* Unregisters protocols */
silc_client_protocol_connection_auth);
silc_protocol_unregister(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
silc_client_protocol_key_exchange);
+ silc_protocol_unregister(SILC_PROTOCOL_CLIENT_REKEY,
+ silc_client_protocol_rekey);
}