SILC_TASK_CALLBACK(silc_server_protocol_connection_auth);
SILC_TASK_CALLBACK(silc_server_protocol_key_exchange);
+SILC_TASK_CALLBACK(silc_server_protocol_rekey);
extern char *silc_version_string;
SilcPKCS pkcs,
SilcHash hash,
SilcHmac hmac,
- int is_responder)
+ SilcSKEDiffieHellmanGroup group,
+ 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);
}
+ 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;
+ idata->rekey->ske_group = silc_ske_group_get_number(group);
+
/* 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);
}
/* Save HMAC key to be used in the communication. */
- if (!silc_hmac_alloc(hmac->hmac->name, NULL, &idata->hmac)) {
+ if (!silc_hmac_alloc(hmac->hmac->name, NULL, &idata->hmac_send)) {
silc_cipher_free(idata->send_key);
silc_cipher_free(idata->receive_key);
silc_hash_free(idata->hash);
silc_free(conn_data);
return FALSE;
}
- silc_hmac_set_key(idata->hmac, keymat->hmac_key, keymat->hmac_key_len);
+ silc_hmac_set_key(idata->hmac_send, keymat->hmac_key, keymat->hmac_key_len);
+ idata->hmac_receive = idata->hmac_send;
sock->user_data = (void *)conn_data;
/* Check remote host version string */
SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
- unsigned int len)
+ uint32 len)
{
SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ char *cp;
+ int maj = 0, min = 0, build = 0, maj2 = 0, min2 = 0, build2 = 0;
SILC_LOG_INFO(("%s (%s) is version %s", ske->sock->hostname,
ske->sock->ip, version));
/* Check software version */
- if (len < strlen(silc_version_string))
+ cp = version + 9;
+ if (!cp)
+ status = SILC_SKE_STATUS_BAD_VERSION;
+
+ maj = atoi(cp);
+ cp = strchr(cp, '.');
+ if (cp) {
+ min = atoi(cp + 1);
+ cp++;
+ }
+ if (cp) {
+ cp = strchr(cp, '.');
+ if (cp)
+ build = atoi(cp + 1);
+ }
+
+ cp = silc_version_string + 9;
+ if (!cp)
status = SILC_SKE_STATUS_BAD_VERSION;
- /* XXX for now there is no other tests due to the abnormal version
- string that is used */
+ maj2 = atoi(cp);
+ cp = strchr(cp, '.');
+ if (cp) {
+ min2 = atoi(cp + 1);
+ cp++;
+ }
+ if (cp) {
+ cp = strchr(cp, '.');
+ if (cp)
+ build2 = atoi(cp + 1);
+ }
+
+ if (maj != maj2)
+ status = SILC_SKE_STATUS_BAD_VERSION;
+ if (min < min2)
+ status = SILC_SKE_STATUS_BAD_VERSION;
return status;
}
+/* Callback that is called by the SKE to indicate that it is safe to
+ continue the execution of the protocol. This is used only if we are
+ initiator. Is given as argument to the silc_ske_initiator_finish
+ function. This is called due to the fact that the public key verification
+ process is asynchronous and we must not continue the protocl until
+ the public key has been verified and this callback is called. */
+
+static void silc_server_protocol_ke_finish(SilcSKE ske, void *context)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerKEInternalContext *ctx =
+ (SilcServerKEInternalContext *)protocol->context;
+ SilcServer server = (SilcServer)ctx->server;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (ske->status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+ ske->status));
+ SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+ ske->status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(server->timeout_queue, 0, protocol, 0, 0, 300000);
+ return;
+ }
+
+ /* Send Ok to the other end. We will end the protocol as responder
+ sends Ok to us when we will take the new keys into use. */
+ if (ctx->responder == FALSE)
+ silc_ske_end(ctx->ske, silc_server_protocol_ke_send_packet, context);
+
+ /* End the protocol on the next round */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+}
+
/* Performs key exchange protocol. This is used for both initiator
and responder key exchange. This is performed always when accepting
new connection to the server. This may be called recursively. */
SilcServerKEInternalContext *ctx =
(SilcServerKEInternalContext *)protocol->context;
SilcServer server = (SilcServer)ctx->server;
- SilcSKEStatus status = 0;
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
SILC_LOG_DEBUG(("Start"));
context);
}
+ /* Return now if the procedure is pending. */
+ if (status == SILC_SKE_STATUS_PENDING)
+ return;
+
if (status != SILC_SKE_STATUS_OK) {
SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
status));
NULL, NULL);
}
+ /* Return now if the procedure is pending. */
+ if (status == SILC_SKE_STATUS_PENDING)
+ return;
+
if (status != SILC_SKE_STATUS_OK) {
SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
status));
/* Process the received Key Exchange 1 Payload packet from
the initiator. This also creates our parts of the Diffie
Hellman algorithm. */
+ /* XXX TODO: If mutual authentication flag is set then the
+ verify_key callback should be set to verify the remote ends
+ public key!! */
+ /* XXX TODO: when the verify_key is set then the `callback'
+ must be set as well as the verify_key is asynchronous
+ (take a look to silc_ske_initiator_finish for example. */
status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer,
NULL, NULL, NULL, NULL);
} else {
context);
}
+ /* Return now if the procedure is pending. */
+ if (status == SILC_SKE_STATUS_PENDING)
+ return;
+
if (status != SILC_SKE_STATUS_OK) {
SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
status));
SILC_SKE_PK_TYPE_SILC,
silc_server_protocol_ke_send_packet,
context);
+
+ /* End the protocol on the next round */
+ protocol->state = SILC_PROTOCOL_STATE_END;
} else {
/* Finish the protocol. This verifies the Key Exchange 2 payload
sent by responder. */
+ /* XXX TODO: the verify_key callback is not set!!! */
status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer,
- NULL, NULL, NULL, NULL);
+ NULL, NULL,
+ silc_server_protocol_ke_finish,
+ context);
}
+ /* Return now if the procedure is pending. */
+ if (status == SILC_SKE_STATUS_PENDING)
+ return;
+
if (status != SILC_SKE_STATUS_OK) {
SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
status));
protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000);
return;
}
-
- /* Send Ok to the other end. We will end the protocol as responder
- sends Ok to us when we will take the new keys into use. */
- if (ctx->responder == FALSE)
- silc_ske_end(ctx->ske, silc_server_protocol_ke_send_packet, context);
-
- /* End the protocol on the next round */
- protocol->state = SILC_PROTOCOL_STATE_END;
}
break;
silc_server_public_key_authentication(SilcServer server,
SilcPublicKey pub_key,
unsigned char *sign,
- unsigned int sign_len,
+ uint32 sign_len,
SilcSKE ske)
{
SilcPKCS pkcs;
silc_server_get_public_key_auth(SilcServer server,
SilcPublicKey pub_key,
unsigned char *auth_data,
- unsigned int *auth_data_len,
+ uint32 *auth_data_len,
SilcSKE ske)
{
int len;
* We are receiving party
*/
int ret;
- unsigned short payload_len;
- unsigned short conn_type;
+ uint16 payload_len;
+ uint16 conn_type;
unsigned char *auth_data = NULL;
SILC_LOG_INFO(("Performing authentication protocol for %s (%s)",
/* Remote end is client */
if (conn_type == SILC_SOCKET_TYPE_CLIENT) {
- SilcServerConfigSectionClientConnection *client = NULL;
- client = silc_server_config_find_client_conn(server->config,
- ctx->sock->ip,
- ctx->sock->port);
- if (!client)
- client = silc_server_config_find_client_conn(server->config,
- ctx->sock->hostname,
- ctx->sock->port);
+ SilcServerConfigSectionClientConnection *client = ctx->cconfig;
if (client) {
switch(client->auth_meth) {
/* Remote end is server */
if (conn_type == SILC_SOCKET_TYPE_SERVER) {
- SilcServerConfigSectionServerConnection *serv = NULL;
- serv = silc_server_config_find_server_conn(server->config,
- ctx->sock->ip,
- ctx->sock->port);
- if (!serv)
- serv = silc_server_config_find_server_conn(server->config,
- ctx->sock->hostname,
- ctx->sock->port);
-
+ SilcServerConfigSectionServerConnection *serv = ctx->sconfig;
+
if (serv) {
switch(serv->auth_meth) {
case SILC_AUTH_NONE:
/* Remote end is router */
if (conn_type == SILC_SOCKET_TYPE_ROUTER) {
- SilcServerConfigSectionServerConnection *serv = NULL;
- serv = silc_server_config_find_router_conn(server->config,
- ctx->sock->ip,
- ctx->sock->port);
- if (!serv)
- serv = silc_server_config_find_router_conn(server->config,
- ctx->sock->hostname,
- ctx->sock->port);
-
+ SilcServerConfigSectionServerConnection *serv = ctx->rconfig;
+
if (serv) {
switch(serv->auth_meth) {
case SILC_AUTH_NONE:
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:
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
+ */
+
+/* Actually takes the new keys into use. */
+
+static void
+silc_server_protocol_rekey_validate(SilcServer server,
+ SilcServerRekeyInternalContext *ctx,
+ SilcIDListData idata,
+ SilcSKEKeyMaterial *keymat,
+ bool send)
+{
+ if (ctx->responder == TRUE) {
+ if (send) {
+ 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);
+ } else {
+ 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 {
+ if (send) {
+ 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);
+ } else {
+ 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);
+ }
+ }
+
+ if (send) {
+ silc_hmac_alloc(idata->hmac_send->hmac->name, NULL, &idata->hmac_send);
+ silc_hmac_set_key(idata->hmac_send, keymat->hmac_key,
+ keymat->hmac_key_len);
+ } else {
+ silc_hmac_free(idata->hmac_receive);
+ idata->hmac_receive = idata->hmac_send;
+ }
+
+ /* Save the current sending encryption key */
+ if (!send) {
+ 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;
+ }
+}
+
+/* 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,
+ bool send)
+{
+ 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 %s session keys (no PFS)",
+ send ? "sending" : "receiving"));
+
+ /* 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 */
+ silc_server_protocol_rekey_validate(server, ctx, idata, keymat, send);
+
+ silc_ske_free_key_material(keymat);
+}
+
+/* This function actually re-generates (with PFS) the keys and
+ takes them into use. */
+
+void
+silc_server_protocol_rekey_generate_pfs(SilcServer server,
+ SilcServerRekeyInternalContext *ctx,
+ bool send)
+{
+ 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;
+ unsigned char *tmpbuf;
+ uint32 klen;
+
+ SILC_LOG_DEBUG(("Generating new %s session keys (with PFS)",
+ send ? "sending" : "receiving"));
+
+ /* 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,
+ idata->hash, keymat);
+
+ /* Set the keys into use */
+ silc_server_protocol_rekey_validate(server, ctx, idata, keymat, send);
+
+ 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_server_protocol_rekey_send_packet(SilcSKE ske,
+ SilcBuffer packet,
+ SilcPacketType type,
+ void *context)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerRekeyInternalContext *ctx =
+ (SilcServerRekeyInternalContext *)protocol->context;
+ SilcServer server = (SilcServer)ctx->server;
+
+ /* Send the packet immediately */
+ silc_server_packet_send(server, ctx->sock,
+ type, 0, packet->data, packet->len, FALSE);
+}
+
+/* Performs re-key as defined in 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;
+ SilcIDListData idata = (SilcIDListData)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(server->timeout_queue, 0, protocol, fd,
+ 0, 300000);
+ }
+
+ ctx->ske = silc_ske_alloc();
+ ctx->ske->rng = server->rng;
+ ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop));
+ silc_ske_get_group_by_number(idata->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(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+
+ /* Advance the protocol state */
+ protocol->state++;
+ protocol->execute(server->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_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY_DONE,
+ 0, NULL, 0, FALSE);
+
+ /* After we send REKEY_DONE we must set the sending encryption
+ key to the new key since all packets after this packet must
+ encrypted with the new key. */
+ silc_server_protocol_rekey_generate(server, ctx, 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_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY,
+ 0, NULL, 0, FALSE);
+
+ 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 = server->rng;
+ ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop));
+ silc_ske_get_group_by_number(idata->rekey->ske_group,
+ &ctx->ske->prop->group);
+
+ status =
+ silc_ske_initiator_phase_2(ctx->ske, NULL, NULL,
+ silc_server_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(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+
+ /* Advance the protocol state */
+ protocol->state++;
+ } else {
+ /*
+ * Do normal and simple re-key.
+ */
+
+ /* 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, FALSE);
+
+ /* After we send REKEY_DONE we must set the sending encryption
+ key to the new key since all packets after this packet must
+ encrypted with the new key. */
+ silc_server_protocol_rekey_generate(server, ctx, TRUE);
+
+ /* The protocol ends in next stage. */
+ 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_server_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(server->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(server->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(server->timeout_queue, 0,
+ protocol, fd, 0, 300000);
+ return;
+ }
+ }
+ }
+
+ /* 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, FALSE);
+
+ /* After we send REKEY_DONE we must set the sending encryption
+ key to the new key since all packets after this packet must
+ encrypted with the new key. */
+ silc_server_protocol_rekey_generate_pfs(server, ctx, 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(server->timeout_queue, 0, protocol, fd, 0, 0);
+ }
+
+ /* We received the REKEY_DONE packet and all packets after this is
+ encrypted with the new key so set the decryption key to the new key */
+ silc_server_protocol_rekey_generate(server, ctx, FALSE);
+
+ /* 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);
}