X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Fsilcd%2Fprotocol.c;h=f232c3d84f94cb86384443fe1b7f766a502451d9;hb=413da0f8686910f5e627393157566ae729ca99c4;hp=794a20880279462c6b473c8896443a1c971969e2;hpb=386c883d8774999c6e74d7c6c37e52e4163a4cb1;p=silc.git diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c index 794a2088..f232c3d8 100644 --- a/apps/silcd/protocol.c +++ b/apps/silcd/protocol.c @@ -4,13 +4,13 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2001 Pekka Riikonen + Copyright (C) 1997 - 2003 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -29,23 +29,21 @@ 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; - /* * Key Exhange protocol functions */ -static bool +static bool silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock, SilcSocketType conn_type, - unsigned char *pk, uint32 pk_len, + unsigned char *pk, SilcUInt32 pk_len, SilcSKEPKType pk_type) { char file[256], filename[256], *fingerprint; struct stat st; if (pk_type != SILC_SKE_PK_TYPE_SILC) { - SILC_LOG_WARNING(("We don't support %s (%s) port %d public key type %d", + SILC_LOG_WARNING(("We don't support %s (%s) port %d public key type %d", sock->hostname, sock->ip, sock->port, pk_type)); return FALSE; } @@ -62,20 +60,20 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock, conn auth protocol with public key we MUST have the key already. */ return TRUE; /* Rest is unreachable code! */ - + memset(filename, 0, sizeof(filename)); memset(file, 0, sizeof(file)); - snprintf(file, sizeof(file) - 1, "serverkey_%s_%d.pub", sock->hostname, + snprintf(file, sizeof(file) - 1, "serverkey_%s_%d.pub", sock->hostname, sock->port); - snprintf(filename, sizeof(filename) - 1, SILC_ETCDIR "/serverkeys/%s", + snprintf(filename, sizeof(filename) - 1, SILC_ETCDIR "/serverkeys/%s", file); /* Create serverkeys directory if it doesn't exist. */ if (stat(SILC_ETCDIR "/serverkeys", &st) < 0) { /* If dir doesn't exist */ - if (errno == ENOENT) { + if (errno == ENOENT) { if (mkdir(SILC_ETCDIR "/serverkeys", 0755) < 0) { - SILC_LOG_ERROR(("Couldn't create `%s' directory\n", + SILC_LOG_ERROR(("Couldn't create `%s' directory\n", SILC_ETCDIR "/serverkeys")); return TRUE; } @@ -87,7 +85,7 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock, /* Take fingerprint of the public key */ fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); - SILC_LOG_DEBUG(("Received server %s (%s) port %d public key (%s)", + SILC_LOG_DEBUG(("Received server %s (%s) port %d public key (%s)", sock->hostname, sock->ip, sock->port, fingerprint)); silc_free(fingerprint); @@ -96,24 +94,24 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock, /* We don't have it, then cache it. */ SILC_LOG_DEBUG(("New public key from server")); - silc_pkcs_save_public_key_data(filename, pk, pk_len, + silc_pkcs_save_public_key_data(filename, pk, pk_len, SILC_PKCS_FILE_PEM); return TRUE; } else { /* The key already exists, verify it. */ SilcPublicKey public_key; unsigned char *encpk; - uint32 encpk_len; + SilcUInt32 encpk_len; SILC_LOG_DEBUG(("We have the public key saved locally")); /* Load the key file */ - if (!silc_pkcs_load_public_key(filename, &public_key, + if (!silc_pkcs_load_public_key(filename, &public_key, SILC_PKCS_FILE_PEM)) - if (!silc_pkcs_load_public_key(filename, &public_key, + if (!silc_pkcs_load_public_key(filename, &public_key, SILC_PKCS_FILE_BIN)) { SILC_LOG_WARNING(("Could not load local copy of the %s (%s) port %d " - "server public key", sock->hostname, sock->ip, + "server public key", sock->hostname, sock->ip, sock->port)); /* Save the key for future checking */ @@ -122,7 +120,7 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock, SILC_PKCS_FILE_PEM); return TRUE; } - + /* Encode the key data */ encpk = silc_pkcs_public_key_encode(public_key, &encpk_len); if (!encpk) { @@ -137,7 +135,7 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock, if (memcmp(pk, encpk, encpk_len)) { SILC_LOG_WARNING(("%s (%s) port %d server public key does not match " - "with local copy", sock->hostname, sock->ip, + "with local copy", sock->hostname, sock->ip, sock->port)); SILC_LOG_WARNING(("It is possible that the key has expired or changed")); SILC_LOG_WARNING(("It is also possible that some one is performing " @@ -156,32 +154,33 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock, /* Callback that is called when we have received KE2 payload from responder. We try to verify the public key now. */ -static void +static void silc_server_protocol_ke_verify_key(SilcSKE ske, unsigned char *pk_data, - uint32 pk_len, + SilcUInt32 pk_len, SilcSKEPKType pk_type, void *context, SilcSKEVerifyCbCompletion completion, void *completion_context) { SilcProtocol protocol = (SilcProtocol)context; - SilcServerKEInternalContext *ctx = + SilcServerKEInternalContext *ctx = (SilcServerKEInternalContext *)protocol->context; SilcServer server = (SilcServer)ctx->server; - SILC_LOG_DEBUG(("Start")); + SILC_LOG_DEBUG(("Verifying received public key")); - if (silc_verify_public_key_internal(server, ctx->sock, - (ctx->responder == FALSE ? - SILC_SOCKET_TYPE_ROUTER: - ctx->sconfig ? SILC_SOCKET_TYPE_SERVER : - ctx->rconfig ? SILC_SOCKET_TYPE_ROUTER : - SILC_SOCKET_TYPE_CLIENT), - pk_data, pk_len, pk_type)) + if (silc_verify_public_key_internal( + server, ctx->sock, + (ctx->responder == FALSE ? + SILC_SOCKET_TYPE_ROUTER: + ctx->sconfig.ref_ptr ? SILC_SOCKET_TYPE_SERVER : + ctx->rconfig.ref_ptr ? SILC_SOCKET_TYPE_ROUTER : + SILC_SOCKET_TYPE_CLIENT), + pk_data, pk_len, pk_type)) completion(ske, SILC_SKE_STATUS_OK, completion_context); else - completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY, + completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY, completion_context); } @@ -194,7 +193,7 @@ static void silc_server_protocol_ke_send_packet(SilcSKE ske, void *context) { SilcProtocol protocol = (SilcProtocol)context; - SilcServerKEInternalContext *ctx = + SilcServerKEInternalContext *ctx = (SilcServerKEInternalContext *)protocol->context; SilcServer server = (SilcServer)ctx->server; @@ -218,60 +217,67 @@ int silc_server_protocol_ke_set_keys(SilcServer server, { SilcUnknownEntry conn_data; SilcIDListData idata; + const char *cname = silc_cipher_get_name(cipher); - SILC_LOG_DEBUG(("Setting new key into use")); + SILC_LOG_DEBUG(("Setting new keys into use")); conn_data = silc_calloc(1, sizeof(*conn_data)); idata = (SilcIDListData)conn_data; /* Allocate cipher to be used in the communication */ - if (!silc_cipher_alloc(cipher->cipher->name, &idata->send_key)) { + if (!silc_cipher_alloc((char *)cname, &idata->send_key)) { silc_free(conn_data); + SILC_LOG_ERROR(("Cannot allocate algorithm: %s", cname)); return FALSE; } - if (!silc_cipher_alloc(cipher->cipher->name, &idata->receive_key)) { + if (!silc_cipher_alloc((char *)cname, &idata->receive_key)) { silc_free(conn_data); + SILC_LOG_ERROR(("Cannot allocate algorithm: %s", cname)); return FALSE; } - - if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, + + if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &idata->hmac_send)) { silc_cipher_free(idata->send_key); silc_cipher_free(idata->receive_key); silc_free(conn_data); + SILC_LOG_ERROR(("Cannot allocate algorithm: %s", + silc_hmac_get_name(hmac))); return FALSE; } - if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, + if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &idata->hmac_receive)) { silc_cipher_free(idata->send_key); silc_cipher_free(idata->receive_key); silc_hmac_free(idata->hmac_send); silc_free(conn_data); + SILC_LOG_ERROR(("Cannot allocate algorithm: %s", + silc_hmac_get_name(hmac))); return FALSE; } if (is_responder == TRUE) { - silc_cipher_set_key(idata->send_key, keymat->receive_enc_key, + 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, + 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); - silc_hmac_set_key(idata->hmac_send, keymat->receive_hmac_key, + silc_hmac_set_key(idata->hmac_send, keymat->receive_hmac_key, keymat->hmac_key_len); - silc_hmac_set_key(idata->hmac_receive, keymat->send_hmac_key, + silc_hmac_set_key(idata->hmac_receive, keymat->send_hmac_key, keymat->hmac_key_len); } else { - silc_cipher_set_key(idata->send_key, keymat->send_enc_key, + 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, + 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_send, keymat->send_hmac_key, + silc_hmac_set_key(idata->hmac_send, keymat->send_hmac_key, keymat->hmac_key_len); - silc_hmac_set_key(idata->hmac_receive, keymat->receive_hmac_key, + silc_hmac_set_key(idata->hmac_receive, keymat->receive_hmac_key, keymat->hmac_key_len); } @@ -285,17 +291,19 @@ int silc_server_protocol_ke_set_keys(SilcServer server, idata->rekey->ske_group = silc_ske_group_get_number(group); /* Save the hash */ - if (!silc_hash_alloc(hash->hash->name, &idata->hash)) { + if (!silc_hash_alloc(silc_hash_get_name(hash), &idata->hash)) { silc_cipher_free(idata->send_key); silc_cipher_free(idata->receive_key); silc_hmac_free(idata->hmac_send); silc_hmac_free(idata->hmac_receive); silc_free(conn_data); + SILC_LOG_ERROR(("Cannot allocate algorithm: %s", + silc_hash_get_name(hash))); return FALSE; } /* Save the remote host's public key */ - silc_pkcs_public_key_decode(ske->ke1_payload->pk_data, + silc_pkcs_public_key_decode(ske->ke1_payload->pk_data, ske->ke1_payload->pk_len, &idata->public_key); if (ske->prop->flags & SILC_SKE_SP_FLAG_MUTUAL) silc_hash_make(server->sha1hash, ske->ke1_payload->pk_data, @@ -303,11 +311,12 @@ int silc_server_protocol_ke_set_keys(SilcServer server, sock->user_data = (void *)conn_data; - SILC_LOG_INFO(("%s (%s) security properties: %s %s %s", + SILC_LOG_INFO(("%s (%s) security properties: %s %s %s %s", sock->hostname, sock->ip, - idata->send_key->cipher->name, + silc_cipher_get_name(idata->send_key), (char *)silc_hmac_get_name(idata->hmac_send), - idata->hash->hash->name)); + silc_hash_get_name(idata->hash), + ske->prop->flags & SILC_SKE_SP_FLAG_PFS ? "PFS" : "")); return TRUE; } @@ -315,69 +324,38 @@ int silc_server_protocol_ke_set_keys(SilcServer server, /* Check remote host version string */ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version, - uint32 len, void *context) + SilcUInt32 len, void *context) { - SilcSKEStatus status = SILC_SKE_STATUS_OK; - char *cp; - int maj = 0, min = 0, build = 0, maj2 = 0, min2 = 0, build2 = 0; + SilcUInt32 l_protocol_version = 0, r_protocol_version = 0; SILC_LOG_INFO(("%s (%s) is version %s", ske->sock->hostname, ske->sock->ip, version)); - /* Check for initial version string */ - if (!strstr(version, "SILC-1.0-")) - status = SILC_SKE_STATUS_BAD_VERSION; - - /* Check software version */ - - 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 (!silc_parse_version_string(version, &r_protocol_version, NULL, NULL, + NULL, NULL)) { + SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version", + ske->sock->hostname, ske->sock->ip, version)); + return SILC_SKE_STATUS_BAD_VERSION; } - 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 (!silc_parse_version_string(silc_version_string, + &l_protocol_version, NULL, NULL, + NULL, NULL)) { + SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version", + ske->sock->hostname, ske->sock->ip, version)); + return SILC_SKE_STATUS_BAD_VERSION; } - 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 - /* XXX < 0.6 is not allowed */ - if (maj == 0 && min < 5) - status = SILC_SKE_STATUS_BAD_VERSION; + /* If remote is too new, don't connect */ + if (l_protocol_version < r_protocol_version) { + SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version", + ske->sock->hostname, ske->sock->ip, version)); + return SILC_SKE_STATUS_BAD_VERSION; + } - /* XXX backward support for 0.6.1 */ - if (maj == 0 && min == 6 && build < 2) - ske->backward_version = 1; + ske->sock->version = r_protocol_version; - return status; + return SILC_SKE_STATUS_OK; } /* Callback that is called by the SKE to indicate that it is safe to @@ -391,18 +369,15 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version, static void silc_server_protocol_ke_continue(SilcSKE ske, void *context) { SilcProtocol protocol = (SilcProtocol)context; - SilcServerKEInternalContext *ctx = + 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 (%s) during Key Exchange protocol", - silc_ske_map_status(ske->status))); - SILC_LOG_DEBUG(("Error (%s) during Key Exchange protocol", - silc_ske_map_status(ske->status))); - + SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)", + silc_ske_map_status(ske->status), ctx->sock->hostname, + ctx->sock->ip)); + protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; @@ -411,13 +386,14 @@ static void silc_server_protocol_ke_continue(SilcSKE ske, void *context) /* 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_LOG_DEBUG(("Ending key exchange protocol")); silc_ske_end(ctx->ske); /* End the protocol on the next round */ protocol->state = SILC_PROTOCOL_STATE_END; } - /* Advance protocol state and call the next state if we are responder. + /* Advance protocol state and call the next state if we are responder. This happens when this callback was sent to silc_ske_responder_phase_2 function. */ if (ctx->responder == TRUE) { @@ -433,17 +409,15 @@ static void silc_server_protocol_ke_continue(SilcSKE ske, void *context) SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) { SilcProtocol protocol = (SilcProtocol)context; - SilcServerKEInternalContext *ctx = + SilcServerKEInternalContext *ctx = (SilcServerKEInternalContext *)protocol->context; SilcServer server = (SilcServer)ctx->server; SilcSKEStatus status = SILC_SKE_STATUS_OK; - SILC_LOG_DEBUG(("Start")); - if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN) protocol->state = SILC_PROTOCOL_STATE_START; - SILC_LOG_DEBUG(("State=%d", protocol->state)); + SILC_LOG_DEBUG(("Current protocol state %d", protocol->state)); switch(protocol->state) { case SILC_PROTOCOL_STATE_START: @@ -455,23 +429,26 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) /* Allocate Key Exchange object */ ctx->ske = ske = silc_ske_alloc(server->rng, server); - + silc_ske_set_callbacks(ske, silc_server_protocol_ke_send_packet, NULL, silc_server_protocol_ke_verify_key, silc_server_protocol_ke_continue, silc_ske_check_version, context); - + if (ctx->responder == TRUE) { /* Start the key exchange by processing the received security properties packet from initiator. */ + SILC_LOG_DEBUG(("Process security property list (KE)")); status = silc_ske_responder_start(ske, ctx->rng, ctx->sock, silc_version_string, ctx->packet->buffer, ctx->flags); } else { SilcSKEStartPayload *start_payload; + SILC_LOG_DEBUG(("Send security property list (KE)")); + /* Assemble security properties. */ - silc_ske_assemble_security_properties(ske, ctx->flags, + silc_ske_assemble_security_properties(ske, ctx->flags, silc_version_string, &start_payload); @@ -486,10 +463,9 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) return; if (status != SILC_SKE_STATUS_OK) { - SILC_LOG_WARNING(("Error (%s) during Key Exchange protocol", - silc_ske_map_status(status))); - SILC_LOG_DEBUG(("Error (%s) during Key Exchange protocol", - silc_ske_map_status(status))); + SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)", + silc_ske_map_status(status), ctx->sock->hostname, + ctx->sock->ip)); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); @@ -504,17 +480,19 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) break; case 2: { - /* - * Phase 1 + /* + * Phase 1 */ if (ctx->responder == TRUE) { /* Sends the selected security properties to the initiator. */ + SILC_LOG_DEBUG(("Send security property list reply (KE)")); status = silc_ske_responder_phase_1(ctx->ske); } else { /* Call Phase-1 function. This processes the Key Exchange Start paylaod reply we just got from the responder. The callback function will receive the processed payload where we will save it. */ + SILC_LOG_DEBUG(("Process security property list reply (KE)")); status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet->buffer); } @@ -523,10 +501,9 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) return; if (status != SILC_SKE_STATUS_OK) { - SILC_LOG_WARNING(("Error (%s) during Key Exchange protocol", - silc_ske_map_status(status))); - SILC_LOG_DEBUG(("Error (%s) during Key Exchange protocol", - silc_ske_map_status(status))); + SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)", + silc_ske_map_status(status), ctx->sock->hostname, + ctx->sock->ip)); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); @@ -541,19 +518,21 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) break; case 3: { - /* - * Phase 2 + /* + * Phase 2 */ if (ctx->responder == TRUE) { /* Process the received Key Exchange 1 Payload packet from the initiator. This also creates our parts of the Diffie Hellman algorithm. The silc_server_protocol_ke_continue will be called after the public key has been verified. */ + SILC_LOG_DEBUG(("Process KE1 packet")); status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer); } 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. */ + SILC_LOG_DEBUG(("Send KE1 packet")); status = silc_ske_initiator_phase_2(ctx->ske, server->public_key, server->private_key, @@ -566,10 +545,9 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) return; if (status != SILC_SKE_STATUS_OK) { - SILC_LOG_WARNING(("Error (%s) during Key Exchange protocol", - silc_ske_map_status(status))); - SILC_LOG_DEBUG(("Error (%s) during Key Exchange protocol", - silc_ske_map_status(status))); + SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)", + silc_ske_map_status(status), ctx->sock->hostname, + ctx->sock->ip)); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); @@ -579,14 +557,15 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) break; case 4: { - /* + /* * Finish protocol */ if (ctx->responder == TRUE) { /* This creates the key exchange material and sends our public parts to the initiator inside Key Exchange 2 Payload. */ - status = silc_ske_responder_finish(ctx->ske, - server->public_key, + SILC_LOG_DEBUG(("Process KE2 packet")); + status = silc_ske_responder_finish(ctx->ske, + server->public_key, server->private_key, SILC_SKE_PK_TYPE_SILC); @@ -596,6 +575,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) /* Finish the protocol. This verifies the Key Exchange 2 payload sent by responder. The silc_server_protocol_ke_continue will be called after the public key has been verified. */ + SILC_LOG_DEBUG(("Send KE2 packet")); status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer); } @@ -604,10 +584,9 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) return; if (status != SILC_SKE_STATUS_OK) { - SILC_LOG_WARNING(("Error (%s) during Key Exchange protocol", - silc_ske_map_status(status))); - SILC_LOG_DEBUG(("Error (%s) during Key Exchange protocol", - silc_ske_map_status(status))); + SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)", + silc_ske_map_status(status), ctx->sock->hostname, + ctx->sock->ip)); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); @@ -618,18 +597,23 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) case SILC_PROTOCOL_STATE_END: { - /* + /* * End protocol */ SilcSKEKeyMaterial *keymat; int key_len = silc_cipher_get_key_len(ctx->ske->prop->cipher); - int hash_len = ctx->ske->prop->hash->hash->hash_len; + int hash_len = silc_hash_len(ctx->ske->prop->hash); + + SILC_LOG_DEBUG(("Process computed key material")); /* Process the key material */ keymat = silc_calloc(1, sizeof(*keymat)); status = silc_ske_process_key_material(ctx->ske, 16, key_len, hash_len, keymat); if (status != SILC_SKE_STATUS_OK) { + SILC_LOG_ERROR(("Error during Key Exchange protocol: " + "could not process key material")); + protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); silc_ske_free_key_material(keymat); @@ -639,17 +623,19 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) /* Send Ok to the other end if we are responder. If we are initiator we have sent this already. */ - if (ctx->responder == TRUE) + if (ctx->responder == TRUE) { + SILC_LOG_DEBUG(("Ending key exchange protocol")); silc_ske_end(ctx->ske); + } - /* Unregister the timeout task since the protocol has ended. + /* 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_schedule_task_del(server->schedule, ctx->timeout_task); /* Assure that after calling final callback there cannot be pending - executions for this protocol anymore. This just unregisters any + executions for this protocol anymore. This just unregisters any timeout callbacks for this protocol. */ silc_protocol_cancel(protocol, server->schedule); @@ -669,14 +655,14 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) /* Send abort notification */ silc_ske_abort(ctx->ske, ctx->ske->status); - /* Unregister the timeout task since the protocol has ended. + /* 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_schedule_task_del(server->schedule, ctx->timeout_task); /* Assure that after calling final callback there cannot be pending - executions for this protocol anymore. This just unregisters any + executions for this protocol anymore. This just unregisters any timeout callbacks for this protocol. */ silc_protocol_cancel(protocol, server->schedule); @@ -692,17 +678,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) * We have received failure from remote */ - /* Unregister the timeout task since the protocol has ended. + /* 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_schedule_task_del(server->schedule, ctx->timeout_task); /* Assure that after calling final callback there cannot be pending - executions for this protocol anymore. This just unregisters any + executions for this protocol anymore. This just unregisters any timeout callbacks for this protocol. */ silc_protocol_cancel(protocol, server->schedule); - + /* On error the final callback is always called. */ if (protocol->final_callback) silc_protocol_execute_final(protocol, server->schedule); @@ -719,11 +705,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) * Connection Authentication protocol functions */ -static int -silc_server_password_authentication(SilcServer server, char *remote_auth, - char *local_auth) +static int +silc_server_password_authentication(SilcServer server, char *local_auth, + char *remote_auth) { - if (!remote_auth || !local_auth) + if (!remote_auth || !local_auth || strlen(local_auth) != strlen(remote_auth)) return FALSE; if (!memcmp(remote_auth, local_auth, strlen(local_auth))) @@ -736,7 +722,7 @@ static int silc_server_public_key_authentication(SilcServer server, SilcPublicKey pub_key, unsigned char *sign, - uint32 sign_len, + SilcUInt32 sign_len, SilcSKE ske) { SilcPKCS pkcs; @@ -764,7 +750,7 @@ silc_server_public_key_authentication(SilcServer server, SILC_STR_END); /* Verify signature */ - if (silc_pkcs_verify_with_hash(pkcs, ske->prop->hash, sign, sign_len, + if (silc_pkcs_verify_with_hash(pkcs, ske->prop->hash, sign, sign_len, auth->data, auth->len)) { silc_pkcs_free(pkcs); silc_buffer_free(auth); @@ -779,7 +765,7 @@ silc_server_public_key_authentication(SilcServer server, static int silc_server_get_public_key_auth(SilcServer server, unsigned char **auth_data, - uint32 *auth_data_len, + SilcUInt32 *auth_data_len, SilcSKE ske) { int len; @@ -799,13 +785,16 @@ silc_server_get_public_key_auth(SilcServer server, ske->start_payload_copy->len), SILC_STR_END); - *auth_data = silc_calloc(silc_pkcs_get_key_len(pkcs), sizeof(**auth_data)); - if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data, + *auth_data = silc_calloc((silc_pkcs_get_key_len(pkcs) / 8) + 1, + sizeof(**auth_data)); + if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data, auth->len, *auth_data, auth_data_len)) { silc_buffer_free(auth); return TRUE; } + SILC_LOG_ERROR(("Error computing signature")); + silc_free(*auth_data); silc_buffer_free(auth); return FALSE; @@ -814,12 +803,12 @@ silc_server_get_public_key_auth(SilcServer server, /* Function that actually performs the authentication to the remote. This supports both passphrase and public key authentication. */ -static bool +static bool silc_server_get_authentication(SilcServerConnAuthInternalContext *ctx, char *local_passphrase, - void *local_publickey, + SilcHashTable local_publickeys, unsigned char *remote_auth, - uint32 remote_auth_len) + SilcUInt32 remote_auth_len) { SilcServer server = (SilcServer)ctx->server; SilcSKE ske = ctx->ske; @@ -827,7 +816,8 @@ silc_server_get_authentication(SilcServerConnAuthInternalContext *ctx, /* If we don't have authentication data set at all we do not require authentication at all */ - if (!local_passphrase && !local_publickey) { + if (!local_passphrase && (!local_publickeys || + !silc_hash_table_count(local_publickeys))) { SILC_LOG_DEBUG(("No authentication required")); return TRUE; } @@ -844,40 +834,49 @@ silc_server_get_authentication(SilcServerConnAuthInternalContext *ctx, } /* Try public key authenetication */ - if (!result && local_publickey) { + if (!result && local_publickeys) { + SilcPublicKey cached_key; + SilcPublicKey remote_key = + ((SilcIDListData)ctx->sock->user_data)->public_key; + SILC_LOG_DEBUG(("Public key authentication")); - result = silc_server_public_key_authentication(server, - local_publickey, + + /* Find the public key to be used in authentication */ + cached_key = silc_server_find_public_key(server, local_publickeys, + remote_key); + if (!cached_key) + return FALSE; + + result = silc_server_public_key_authentication(server, cached_key, remote_auth, - remote_auth_len, - ske); + remote_auth_len, ske); } + SILC_LOG_DEBUG(("Authentication %s", result ? "successful" : "failed")); + return result; } -/* Performs connection authentication protocol. If responder, we +/* Performs connection authentication protocol. If responder, we authenticate the remote data received. If initiator, we will send authentication data to the remote end. */ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) { SilcProtocol protocol = (SilcProtocol)context; - SilcServerConnAuthInternalContext *ctx = + SilcServerConnAuthInternalContext *ctx = (SilcServerConnAuthInternalContext *)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)); + SILC_LOG_DEBUG(("Current protocol state %d", protocol->state)); switch(protocol->state) { case SILC_PROTOCOL_STATE_START: { - /* + /* * Start protocol. */ @@ -886,8 +885,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) * We are receiving party */ int ret; - uint16 payload_len; - uint16 conn_type; + SilcUInt16 payload_len; + SilcUInt16 conn_type; unsigned char *auth_data = NULL; SILC_LOG_INFO(("Performing authentication protocol for %s (%s)", @@ -900,45 +899,46 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) SILC_STR_UI_SHORT(&conn_type), SILC_STR_END); if (ret == -1) { - SILC_LOG_DEBUG(("Bad payload in authentication packet")); + SILC_LOG_ERROR(("Bad payload in authentication packet")); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } - + if (payload_len != ctx->packet->buffer->len) { - SILC_LOG_DEBUG(("Bad payload in authentication packet")); + SILC_LOG_ERROR(("Bad payload length in authentication packet")); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } - + payload_len -= 4; - - if (conn_type < SILC_SOCKET_TYPE_CLIENT || + + if (conn_type < SILC_SOCKET_TYPE_CLIENT || conn_type > SILC_SOCKET_TYPE_ROUTER) { - SILC_LOG_ERROR(("Bad connection type %d", conn_type)); + SILC_LOG_ERROR(("Bad connection type (%d) in authentication packet", + conn_type)); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } - + if (payload_len > 0) { /* Get authentication data */ silc_buffer_pull(ctx->packet->buffer, 4); ret = silc_buffer_unformat(ctx->packet->buffer, - SILC_STR_UI_XNSTRING_ALLOC(&auth_data, + SILC_STR_UI_XNSTRING_ALLOC(&auth_data, payload_len), SILC_STR_END); if (ret == -1) { - SILC_LOG_DEBUG(("Bad payload in authentication packet")); + SILC_LOG_DEBUG(("Bad payload in authentication payload")); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } } - /* + /* * Check the remote connection type and make sure that we have * configured this connection. If we haven't allowed this connection * the authentication must be failed. @@ -948,117 +948,111 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) /* Remote end is client */ if (conn_type == SILC_SOCKET_TYPE_CLIENT) { - SilcServerConfigClient *client = ctx->cconfig; - + SilcServerConfigClient *client = ctx->cconfig.ref_ptr; + if (client) { ret = silc_server_get_authentication(ctx, client->passphrase, - client->publickey, + client->publickeys, auth_data, payload_len); if (!ret) { /* Authentication failed */ SILC_LOG_ERROR(("Authentication failed")); - SILC_LOG_DEBUG(("Authentication failed")); silc_free(auth_data); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } } else { - SILC_LOG_DEBUG(("No configuration for remote client connection")); SILC_LOG_ERROR(("Remote client connection not configured")); SILC_LOG_ERROR(("Authentication failed")); silc_free(auth_data); protocol->state = SILC_PROTOCOL_STATE_ERROR; - silc_protocol_execute(protocol, server->schedule, + silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } } - + /* Remote end is server */ if (conn_type == SILC_SOCKET_TYPE_SERVER) { - SilcServerConfigServer *serv = ctx->sconfig; - + SilcServerConfigServer *serv = ctx->sconfig.ref_ptr; + if (serv) { ret = silc_server_get_authentication(ctx, serv->passphrase, - serv->publickey, + serv->publickeys, auth_data, payload_len); if (!ret) { /* Authentication failed */ SILC_LOG_ERROR(("Authentication failed")); - SILC_LOG_DEBUG(("Authentication failed")); silc_free(auth_data); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } } else { - SILC_LOG_DEBUG(("No configuration for remote server connection")); SILC_LOG_ERROR(("Remote server connection not configured")); SILC_LOG_ERROR(("Authentication failed")); protocol->state = SILC_PROTOCOL_STATE_ERROR; - silc_protocol_execute(protocol, server->schedule, + silc_protocol_execute(protocol, server->schedule, 0, 300000); silc_free(auth_data); return; } } - + /* Remote end is router */ if (conn_type == SILC_SOCKET_TYPE_ROUTER) { - SilcServerConfigRouter *serv = ctx->rconfig; + SilcServerConfigRouter *serv = ctx->rconfig.ref_ptr; if (serv) { ret = silc_server_get_authentication(ctx, serv->passphrase, - serv->publickey, + serv->publickeys, auth_data, payload_len); if (!ret) { /* Authentication failed */ SILC_LOG_ERROR(("Authentication failed")); - SILC_LOG_DEBUG(("Authentication failed")); silc_free(auth_data); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } } else { - SILC_LOG_DEBUG(("No configuration for remote router connection")); SILC_LOG_ERROR(("Remote router connection not configured")); SILC_LOG_ERROR(("Authentication failed")); silc_free(auth_data); protocol->state = SILC_PROTOCOL_STATE_ERROR; - silc_protocol_execute(protocol, server->schedule, + silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } } - + silc_free(auth_data); /* Save connection type. This is later used to create the ID for the connection. */ ctx->conn_type = conn_type; - + /* Advance protocol state. */ protocol->state = SILC_PROTOCOL_STATE_END; silc_protocol_execute(protocol, server->schedule, 0, 0); } else { - /* + /* * We are initiator. We are authenticating ourselves to a * remote server. We will send the authentication data to the - * other end for verify. + * other end for verify. */ SilcBuffer packet; int payload_len = 0; unsigned char *auth_data = NULL; - uint32 auth_data_len = 0; - + SilcUInt32 auth_data_len = 0; + switch(ctx->auth_meth) { case SILC_AUTH_NONE: /* No authentication required */ break; - + case SILC_AUTH_PASSWORD: /* Password authentication */ if (ctx->auth_data && ctx->auth_data_len) { @@ -1067,7 +1061,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) break; } break; - + case SILC_AUTH_PUBLIC_KEY: { /* Public key authentication */ @@ -1076,30 +1070,30 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) break; } } - + payload_len = 4 + auth_data_len; packet = silc_buffer_alloc(payload_len); silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); silc_buffer_format(packet, SILC_STR_UI_SHORT(payload_len), - SILC_STR_UI_SHORT(server->server_type + SILC_STR_UI_SHORT(server->server_type == SILC_SERVER ? SILC_SOCKET_TYPE_SERVER : SILC_SOCKET_TYPE_ROUTER), SILC_STR_UI_XNSTRING(auth_data, auth_data_len), SILC_STR_END); - + /* Send the packet to server */ silc_server_packet_send(server, ctx->sock, - SILC_PACKET_CONNECTION_AUTH, 0, + SILC_PACKET_CONNECTION_AUTH, 0, packet->data, packet->len, TRUE); - + if (auth_data) { memset(auth_data, 0, auth_data_len); silc_free(auth_data); } silc_buffer_free(packet); - + /* Next state is end of protocol */ protocol->state = SILC_PROTOCOL_STATE_END; } @@ -1108,7 +1102,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) case SILC_PROTOCOL_STATE_END: { - /* + /* * End protocol */ unsigned char ok[4]; @@ -1119,17 +1113,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) silc_server_packet_send(server, ctx->sock, SILC_PACKET_SUCCESS, 0, ok, 4, TRUE); - /* Unregister the timeout task since the protocol has ended. + /* 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_schedule_task_del(server->schedule, ctx->timeout_task); /* Assure that after calling final callback there cannot be pending - executions for this protocol anymore. This just unregisters any + executions for this protocol anymore. This just unregisters any timeout callbacks for this protocol. */ silc_protocol_cancel(protocol, server->schedule); - + /* Protocol has ended, call the final callback */ if (protocol->final_callback) silc_protocol_execute_final(protocol, server->schedule); @@ -1144,23 +1138,22 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) */ unsigned char error[4]; - SILC_PUT32_MSB(SILC_AUTH_FAILED, error); - /* Authentication failed */ + SILC_PUT32_MSB(SILC_AUTH_FAILED, error); silc_server_packet_send(server, ctx->sock, SILC_PACKET_FAILURE, 0, error, 4, TRUE); - /* Unregister the timeout task since the protocol has ended. + /* 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_schedule_task_del(server->schedule, ctx->timeout_task); /* Assure that after calling final callback there cannot be pending - executions for this protocol anymore. This just unregisters any + executions for this protocol anymore. This just unregisters any timeout callbacks for this protocol. */ silc_protocol_cancel(protocol, server->schedule); - + /* On error the final callback is always called. */ if (protocol->final_callback) silc_protocol_execute_final(protocol, server->schedule); @@ -1174,17 +1167,19 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) * We have received failure from remote */ - /* Unregister the timeout task since the protocol has ended. + SILC_LOG_ERROR(("Received Authentication Failure")); + + /* 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_schedule_task_del(server->schedule, ctx->timeout_task); /* Assure that after calling final callback there cannot be pending - executions for this protocol anymore. This just unregisters any + executions for this protocol anymore. This just unregisters any timeout callbacks for this protocol. */ silc_protocol_cancel(protocol, server->schedule); - + /* On error the final callback is always called. */ if (protocol->final_callback) silc_protocol_execute_final(protocol, server->schedule); @@ -1203,7 +1198,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) /* Actually takes the new keys into use. */ -static void +static void silc_server_protocol_rekey_validate(SilcServer server, SilcServerRekeyInternalContext *ctx, SilcIDListData idata, @@ -1212,30 +1207,30 @@ silc_server_protocol_rekey_validate(SilcServer server, { if (ctx->responder == TRUE) { if (send) { - silc_cipher_set_key(idata->send_key, keymat->receive_enc_key, + 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_hmac_set_key(idata->hmac_send, keymat->receive_hmac_key, + silc_hmac_set_key(idata->hmac_send, keymat->receive_hmac_key, keymat->hmac_key_len); } else { - silc_cipher_set_key(idata->receive_key, keymat->send_enc_key, + 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); - silc_hmac_set_key(idata->hmac_receive, keymat->send_hmac_key, + silc_hmac_set_key(idata->hmac_receive, keymat->send_hmac_key, keymat->hmac_key_len); } } else { if (send) { - silc_cipher_set_key(idata->send_key, keymat->send_enc_key, + 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_hmac_set_key(idata->hmac_send, keymat->send_hmac_key, + silc_hmac_set_key(idata->hmac_send, keymat->send_hmac_key, keymat->hmac_key_len); } else { - silc_cipher_set_key(idata->receive_key, keymat->receive_enc_key, + 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_receive, keymat->receive_hmac_key, + silc_hmac_set_key(idata->hmac_receive, keymat->receive_hmac_key, keymat->hmac_key_len); } } @@ -1259,8 +1254,8 @@ void silc_server_protocol_rekey_generate(SilcServer server, { 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; + SilcUInt32 key_len = silc_cipher_get_key_len(idata->send_key); + SilcUInt32 hash_len = silc_hash_len(idata->hash); SILC_LOG_DEBUG(("Generating new %s session keys (no PFS)", send ? "sending" : "receiving")); @@ -1269,7 +1264,7 @@ void silc_server_protocol_rekey_generate(SilcServer server, 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, + 16, key_len, hash_len, idata->hash, keymat); /* Set the keys into use */ @@ -1281,17 +1276,17 @@ void silc_server_protocol_rekey_generate(SilcServer server, /* This function actually re-generates (with PFS) the keys and takes them into use. */ -void +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; + SilcUInt32 key_len = silc_cipher_get_key_len(idata->send_key); + SilcUInt32 hash_len = silc_hash_len(idata->hash); unsigned char *tmpbuf; - uint32 klen; + SilcUInt32 klen; SILC_LOG_DEBUG(("Generating new %s session keys (with PFS)", send ? "sending" : "receiving")); @@ -1301,7 +1296,7 @@ silc_server_protocol_rekey_generate_pfs(SilcServer server, /* Generate the new key */ keymat = silc_calloc(1, sizeof(*keymat)); - silc_ske_process_key_material_data(tmpbuf, klen, 16, key_len, hash_len, + silc_ske_process_key_material_data(tmpbuf, klen, 16, key_len, hash_len, idata->hash, keymat); /* Set the keys into use */ @@ -1315,14 +1310,14 @@ silc_server_protocol_rekey_generate_pfs(SilcServer server, /* Packet sending callback. This function is provided as packet sending routine to the Key Exchange functions. */ -static void +static void silc_server_protocol_rekey_send_packet(SilcSKE ske, SilcBuffer packet, SilcPacketType type, void *context) { SilcProtocol protocol = (SilcProtocol)context; - SilcServerRekeyInternalContext *ctx = + SilcServerRekeyInternalContext *ctx = (SilcServerRekeyInternalContext *)protocol->context; SilcServer server = (SilcServer)ctx->server; @@ -1336,23 +1331,21 @@ silc_server_protocol_rekey_send_packet(SilcSKE ske, SILC_TASK_CALLBACK(silc_server_protocol_rekey) { SilcProtocol protocol = (SilcProtocol)context; - SilcServerRekeyInternalContext *ctx = + 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)); + SILC_LOG_DEBUG(("Current protocol state %d", protocol->state)); switch(protocol->state) { case SILC_PROTOCOL_STATE_START: { - /* + /* * Start protocol. */ @@ -1362,13 +1355,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) */ 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 */ + SILC_LOG_ERROR(("Error during Re-key (R PFS): re-key state is " + "incorrect (received %d, expected %d packet), " + "with %s (%s)", ctx->packet->type, + SILC_PACKET_KEY_EXCHANGE_1, ctx->sock->hostname, + ctx->sock->ip)); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; @@ -1379,16 +1376,16 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) silc_ske_group_get_by_number(idata->rekey->ske_group, &ctx->ske->prop->group); - silc_ske_set_callbacks(ctx->ske, - silc_server_protocol_rekey_send_packet, + silc_ske_set_callbacks(ctx->ske, + silc_server_protocol_rekey_send_packet, NULL, NULL, NULL, silc_ske_check_version, context); - + status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer); if (status != SILC_SKE_STATUS_OK) { - SILC_LOG_WARNING(("Error (%s) during Re-key (PFS)", - silc_ske_map_status(status))); - + SILC_LOG_ERROR(("Error (%s) during Re-key (R PFS), with %s (%s)", + silc_ske_map_status(status), ctx->sock->hostname, + ctx->sock->ip)); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; @@ -1410,11 +1407,12 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) 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); + silc_server_packet_queue_purge(server, ctx->sock); /* The protocol ends in next stage. */ protocol->state = SILC_PROTOCOL_STATE_END; } - + } else { /* * We are the initiator of this protocol @@ -1425,7 +1423,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) 0, NULL, 0, FALSE); if (ctx->pfs == TRUE) { - /* + /* * Use Perfect Forward Secrecy, ie. negotiate the key material * using the SKE protocol. */ @@ -1434,16 +1432,16 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) silc_ske_group_get_by_number(idata->rekey->ske_group, &ctx->ske->prop->group); - silc_ske_set_callbacks(ctx->ske, - silc_server_protocol_rekey_send_packet, + silc_ske_set_callbacks(ctx->ske, + silc_server_protocol_rekey_send_packet, NULL, NULL, NULL, silc_ske_check_version, context); - + status = silc_ske_initiator_phase_2(ctx->ske, NULL, NULL, 0); if (status != SILC_SKE_STATUS_OK) { - SILC_LOG_WARNING(("Error (%s) during Re-key (PFS)", - silc_ske_map_status(status))); - + SILC_LOG_ERROR(("Error (%s) during Re-key (I PFS), with %s (%s)", + silc_ske_map_status(status), ctx->sock->hostname, + ctx->sock->ip)); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; @@ -1456,8 +1454,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) * Do normal and simple re-key. */ - /* Send the REKEY_DONE to indicate we will take new keys into use - now. */ + /* 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); @@ -1465,6 +1463,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) 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); + silc_server_packet_queue_purge(server, ctx->sock); /* The protocol ends in next stage. */ protocol->state = SILC_PROTOCOL_STATE_END; @@ -1475,20 +1474,20 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) case 2: /* - * Second state, used only when oding re-key with PFS. + * Second state, used only when doing re-key with PFS. */ if (ctx->responder == TRUE) { if (ctx->pfs == TRUE) { /* - * Send our KE packe to the initiator now that we've processed + * Send our KE packet to the initiator now that we've processed * the initiator's KE packet. */ - status = silc_ske_responder_finish(ctx->ske, NULL, NULL, + status = silc_ske_responder_finish(ctx->ske, NULL, NULL, SILC_SKE_PK_TYPE_SILC); if (status != SILC_SKE_STATUS_OK) { - SILC_LOG_WARNING(("Error (%s) during Re-key (PFS)", - silc_ske_map_status(status))); - + SILC_LOG_ERROR(("Error (%s) during Re-key (R PFS), with %s (%s)", + silc_ske_map_status(status), ctx->sock->hostname, + ctx->sock->ip)); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; @@ -1501,17 +1500,21 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) * The packet type must be KE packet */ if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_2) { - /* Error in protocol */ + SILC_LOG_ERROR(("Error during Re-key (I PFS): re-key state is " + "incorrect (received %d, expected %d packet), " + "with %s (%s)", ctx->packet->type, + SILC_PACKET_KEY_EXCHANGE_2, ctx->sock->hostname, + ctx->sock->ip)); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } - + status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer); if (status != SILC_SKE_STATUS_OK) { - SILC_LOG_WARNING(("Error (%s) during Re-key (PFS)", - silc_ske_map_status(status))); - + SILC_LOG_ERROR(("Error (%s) during Re-key (I PFS), with %s (%s)", + silc_ske_map_status(status), ctx->sock->hostname, + ctx->sock->ip)); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; @@ -1519,11 +1522,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) } } - /* Send the REKEY_DONE to indicate we will take new keys into use - now. */ + /* 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. */ @@ -1534,12 +1537,16 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) break; case SILC_PROTOCOL_STATE_END: - /* + /* * End protocol */ if (ctx->packet->type != SILC_PACKET_REKEY_DONE) { - /* Error in protocol */ + SILC_LOG_ERROR(("Error during Re-key (%s PFS): re-key state is " + "incorrect (received %d, expected %d packet), " + "with %s (%s)", ctx->responder ? "R" : "I", + ctx->packet->type, SILC_PACKET_REKEY_DONE, + ctx->sock->hostname, ctx->sock->ip)); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, server->schedule, 0, 300000); return; @@ -1547,13 +1554,16 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) /* 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); + if (ctx->pfs == TRUE) + silc_server_protocol_rekey_generate_pfs(server, ctx, FALSE); + else + silc_server_protocol_rekey_generate(server, ctx, FALSE); /* Assure that after calling final callback there cannot be pending - executions for this protocol anymore. This just unregisters any + executions for this protocol anymore. This just unregisters any timeout callbacks for this protocol. */ silc_protocol_cancel(protocol, server->schedule); - + /* Protocol has ended, call the final callback */ if (protocol->final_callback) silc_protocol_execute_final(protocol, server->schedule); @@ -1566,16 +1576,15 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) * Error occured */ - if (ctx->pfs == TRUE) { + if (ctx->pfs == TRUE) /* Send abort notification */ silc_ske_abort(ctx->ske, ctx->ske->status); - } /* Assure that after calling final callback there cannot be pending - executions for this protocol anymore. This just unregisters any + executions for this protocol anymore. This just unregisters any timeout callbacks for this protocol. */ silc_protocol_cancel(protocol, server->schedule); - + /* On error the final callback is always called. */ if (protocol->final_callback) silc_protocol_execute_final(protocol, server->schedule); @@ -1588,11 +1597,13 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) * We have received failure from remote */ + SILC_LOG_ERROR(("Error during Re-Key: received Failure")); + /* Assure that after calling final callback there cannot be pending - executions for this protocol anymore. This just unregisters any + executions for this protocol anymore. This just unregisters any timeout callbacks for this protocol. */ silc_protocol_cancel(protocol, server->schedule); - + /* On error the final callback is always called. */ if (protocol->final_callback) silc_protocol_execute_final(protocol, server->schedule);