}
/* 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;
uint32 len)
{
SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ char *cp;
+ int maj = 0, min = 0, build = 0, maj2, min2, build2;
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;
- /* XXX for now there is no other tests due to the abnormal version
- string that is used */
+ 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;
+
+ 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 0
+ if (min < min2)
+ status = SILC_SKE_STATUS_BAD_VERSION;
+#endif
return status;
}
/* 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:
silc_server_protocol_rekey_validate(SilcServer server,
SilcServerRekeyInternalContext *ctx,
SilcIDListData idata,
- SilcSKEKeyMaterial *keymat)
+ SilcSKEKeyMaterial *keymat,
+ bool send)
{
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);
+ 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 {
- 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);
+ 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);
+ }
}
- silc_hmac_set_key(idata->hmac, keymat->hmac_key, keymat->hmac_key_len);
+ 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 */
- 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;
+ 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)
+ 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 session keys (no PFS)"));
+ SILC_LOG_DEBUG(("Generating new %s session keys (no PFS)",
+ send ? "sending" : "receiving"));
/* Generate the new key */
keymat = silc_calloc(1, sizeof(*keymat));
idata->hash, keymat);
/* Set the keys into use */
- silc_server_protocol_rekey_validate(server, ctx, idata, keymat);
+ silc_server_protocol_rekey_validate(server, ctx, idata, keymat, send);
silc_ske_free_key_material(keymat);
}
void
silc_server_protocol_rekey_generate_pfs(SilcServer server,
- SilcServerRekeyInternalContext *ctx)
+ SilcServerRekeyInternalContext *ctx,
+ bool send)
{
SilcIDListData idata = (SilcIDListData)ctx->sock->user_data;
SilcSKEKeyMaterial *keymat;
unsigned char *tmpbuf;
uint32 klen;
- SILC_LOG_DEBUG(("Generating new session keys (with PFS)"));
+ 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);
idata->hash, keymat);
/* Set the keys into use */
- silc_server_protocol_rekey_validate(server, ctx, idata, keymat);
+ silc_server_protocol_rekey_validate(server, ctx, idata, keymat, send);
memset(tmpbuf, 0, klen);
silc_free(tmpbuf);
/* Send the packet immediately */
silc_server_packet_send(server, ctx->sock,
- type, 0, packet->data, packet->len, TRUE);
+ type, 0, packet->data, packet->len, FALSE);
}
/* Performs re-key as defined in the SILC protocol specification. */
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;
}
/* Start the re-key by sending the REKEY packet */
silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY,
- 0, NULL, 0, TRUE);
+ 0, NULL, 0, FALSE);
if (ctx->pfs == TRUE) {
/*
* 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. */
+ /* 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;
}
}
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;
protocol->execute(server->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_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY_DONE,
- 0, NULL, 0, FALSE);
- }
- }
+ /* 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)