X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=apps%2Fsilcd%2Fprotocol.c;h=170120f696c98007627aa1a7394628185b8ecf59;hp=d31955fe56c2c01b247b467cbe93c5ffe521bf23;hb=e5d8d3db6caa344b3d419b884556c21b15e7d123;hpb=1b71837125fbc3111617cab6f22a6244508b7ed2 diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c index d31955fe..170120f6 100644 --- a/apps/silcd/protocol.c +++ b/apps/silcd/protocol.c @@ -2,7 +2,7 @@ protocol.c - Author: Pekka Riikonen + Author: Pekka Riikonen Copyright (C) 1997 - 2001 Pekka Riikonen @@ -27,6 +27,7 @@ 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; @@ -34,6 +35,150 @@ extern char *silc_version_string; * Key Exhange protocol functions */ +static bool +silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock, + SilcSocketType conn_type, + unsigned char *pk, uint32 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", + sock->hostname, sock->ip, sock->port, pk_type)); + return FALSE; + } + + /* Accept client keys without verification */ + if (conn_type == SILC_SOCKET_TYPE_CLIENT) { + SILC_LOG_DEBUG(("Accepting client public key without verification")); + return TRUE; + } + + memset(filename, 0, sizeof(filename)); + memset(file, 0, sizeof(file)); + snprintf(file, sizeof(file) - 1, "serverkey_%s_%d.pub", sock->hostname, + sock->port); + 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 (mkdir(SILC_ETCDIR "/serverkeys", 0755) < 0) { + SILC_LOG_ERROR(("Couldn't create `%s' directory\n", + SILC_ETCDIR "/serverkeys")); + return TRUE; + } + } else { + SILC_LOG_ERROR(("%s\n", strerror(errno))); + return TRUE; + } + } + + /* 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)", + sock->hostname, sock->ip, sock->port, fingerprint)); + silc_free(fingerprint); + + /* Check whether this key already exists */ + if (stat(filename, &st) < 0) { + /* 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_FILE_PEM); + return TRUE; + } else { + /* The key already exists, verify it. */ + SilcPublicKey public_key; + unsigned char *encpk; + uint32 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, + SILC_PKCS_FILE_PEM)) + 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, + sock->port)); + + /* Save the key for future checking */ + unlink(filename); + silc_pkcs_save_public_key_data(filename, pk, pk_len, + SILC_PKCS_FILE_PEM); + return TRUE; + } + + /* Encode the key data */ + encpk = silc_pkcs_public_key_encode(public_key, &encpk_len); + if (!encpk) { + SILC_LOG_WARNING(("Local copy of the server %s (%s) port %d public key " + "is malformed", sock->hostname, sock->ip, sock->port)); + + /* Save the key for future checking */ + unlink(filename); + silc_pkcs_save_public_key_data(filename, pk, pk_len, + SILC_PKCS_FILE_PEM); + return TRUE; + } + + if (memcmp(encpk, pk, encpk_len)) { + SILC_LOG_WARNING(("%s (%s) port %d server public key does not match " + "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 " + "man-in-the-middle attack")); + SILC_LOG_WARNING(("Will not accept the server %s (%s) port %d public " + "key", + sock->hostname, sock->ip, sock->port)); + return FALSE; + } + + /* Local copy matched */ + return TRUE; + } +} + +/* Callback that is called when we have received KE2 payload from + responder. We try to verify the public key now. */ + +static void +silc_server_protocol_ke_verify_key(SilcSKE ske, + unsigned char *pk_data, + uint32 pk_len, + SilcSKEPKType pk_type, + void *context, + SilcSKEVerifyCbCompletion completion, + void *completion_context) +{ + SilcProtocol protocol = (SilcProtocol)context; + SilcServerKEInternalContext *ctx = + (SilcServerKEInternalContext *)protocol->context; + SilcServer server = (SilcServer)ctx->server; + + SILC_LOG_DEBUG(("Start")); + + 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)) + completion(ske, SILC_SKE_STATUS_OK, completion_context); + else + completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY, + completion_context); +} + /* Packet sending callback. This function is provided as packet sending routine to the Key Exchange functions. */ @@ -61,6 +206,7 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske, SilcPKCS pkcs, SilcHash hash, SilcHmac hmac, + SilcSKEDiffieHellmanGroup group, bool is_responder) { SilcUnknownEntry conn_data; @@ -71,9 +217,6 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske, conn_data = silc_calloc(1, sizeof(*conn_data)); idata = (SilcIDListData)conn_data; - if (ske->start_payload->flags & SILC_SKE_SP_FLAG_PFS) - idata->pfs = TRUE; - /* Allocate cipher to be used in the communication */ if (!silc_cipher_alloc(cipher->cipher->name, &idata->send_key)) { silc_free(conn_data); @@ -100,11 +243,17 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske, silc_cipher_set_iv(idata->receive_key, keymat->receive_iv); } - /* Note that for responder the initiator's sending key is receiving key */ - idata->send_enc_key = silc_calloc(keymat->enc_key_len / 8, - sizeof(*idata->send_enc_key)); - memcpy(idata->send_enc_key, keymat->send_enc_key, keymat->enc_key_len / 8); - idata->enc_key_len = keymat->enc_key_len / 8; + 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, @@ -119,26 +268,35 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske, } /* 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; + SILC_LOG_INFO(("%s (%s) security properties: %s %s %s", + sock->hostname, sock->ip, + idata->send_key->cipher->name, + idata->hmac_send->hmac->name, + idata->hash->hash->name)); + return TRUE; } /* Check remote host version string */ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version, - uint32 len) + uint32 len, void *context) { 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)); @@ -149,15 +307,92 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *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 (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 or + silc_ske_responder_phase_2 functions. 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_continue(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 (%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))); + + protocol->state = SILC_PROTOCOL_STATE_ERROR; + silc_protocol_execute(protocol, server->schedule, 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); + + /* 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. + This happens when this callback was sent to silc_ske_responder_phase_2 + function. */ + if (ctx->responder == TRUE) { + protocol->state++; + silc_protocol_execute(protocol, server->schedule, 0, 100000); + } +} + /* 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. */ @@ -168,7 +403,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) SilcServerKEInternalContext *ctx = (SilcServerKEInternalContext *)protocol->context; SilcServer server = (SilcServer)ctx->server; - SilcSKEStatus status = 0; + SilcSKEStatus status = SILC_SKE_STATUS_OK; SILC_LOG_DEBUG(("Start")); @@ -190,13 +425,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) ctx->ske = ske; ske->rng = server->rng; + 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. */ status = silc_ske_responder_start(ske, ctx->rng, ctx->sock, silc_version_string, - ctx->packet->buffer, FALSE, - NULL, NULL); + ctx->packet->buffer, FALSE); } else { SilcSKEStartPayload *start_payload; @@ -208,26 +447,28 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) /* Start the key exchange by sending our security properties to the remote end. */ status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock, - start_payload, - silc_server_protocol_ke_send_packet, - context); + start_payload); } + /* 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_LOG_DEBUG(("Error (type %d) during Key Exchange protocol", - status)); + 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))); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } /* Advance protocol state and call the next state if we are responder */ protocol->state++; if (ctx->responder == TRUE) - protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 100000); + silc_protocol_execute(protocol, server->schedule, 0, 100000); } break; case 2: @@ -237,35 +478,35 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) */ if (ctx->responder == TRUE) { /* 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, - context); + status = silc_ske_responder_phase_1(ctx->ske, + ctx->ske->start_payload); } 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. */ - status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet->buffer, - NULL, NULL); + status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet->buffer); } + /* 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_LOG_DEBUG(("Error (type %d) during Key Exchange protocol", - status)); + 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))); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } /* Advance protocol state and call next state if we are initiator */ protocol->state++; if (ctx->responder == FALSE) - protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 100000); + silc_protocol_execute(protocol, server->schedule, 0, 100000); } break; case 3: @@ -276,36 +517,33 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) 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. */ - status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer, - NULL, NULL, NULL, NULL); + Hellman algorithm. The silc_server_protocol_ke_continue + will be called after the public key has been verified. */ + 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. */ - status = - silc_ske_initiator_phase_2(ctx->ske, - server->public_key, - server->private_key, - silc_server_protocol_ke_send_packet, - context); + status = silc_ske_initiator_phase_2(ctx->ske, + server->public_key, + server->private_key); + protocol->state++; } + /* 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_LOG_DEBUG(("Error (type %d) during Key Exchange protocol", - status)); + 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))); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } - - /* Advance protocol state and call the next state if we are responder */ - protocol->state++; - if (ctx->responder == TRUE) - protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 100000); } break; case 4: @@ -316,37 +554,34 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) 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, server->private_key, - SILC_SKE_PK_TYPE_SILC, - silc_server_protocol_ke_send_packet, - context); + status = silc_ske_responder_finish(ctx->ske, + server->public_key, + server->private_key, + SILC_SKE_PK_TYPE_SILC); + + /* 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. */ - status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer, - NULL, NULL, NULL, NULL); + sent by responder. The silc_server_protocol_ke_continue will + be called after the public key has been verified. */ + status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer); } + /* 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_LOG_DEBUG(("Error (type %d) during Key Exchange protocol", - status)); + 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))); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, 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; @@ -365,7 +600,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) keymat); if (status != SILC_SKE_STATUS_OK) { protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, 0, 300000); silc_ske_free_key_material(keymat); return; } @@ -374,17 +609,17 @@ 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) - silc_ske_end(ctx->ske, silc_server_protocol_ke_send_packet, context); + silc_ske_end(ctx->ske); /* 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(server->timeout_queue, ctx->timeout_task); + silc_schedule_task_del(server->schedule, ctx->timeout_task); /* Call the final callback */ if (protocol->final_callback) - protocol->execute_final(server->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, server->schedule); else silc_protocol_free(protocol); } @@ -396,19 +631,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) */ /* Send abort notification */ - silc_ske_abort(ctx->ske, ctx->ske->status, - silc_server_protocol_ke_send_packet, - context); + silc_ske_abort(ctx->ske, ctx->ske->status); /* 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(server->timeout_queue, ctx->timeout_task); + silc_schedule_task_del(server->schedule, ctx->timeout_task); /* On error the final callback is always called. */ if (protocol->final_callback) - protocol->execute_final(server->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, server->schedule); else silc_protocol_free(protocol); break; @@ -422,11 +655,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) This was the timeout task to be executed if the protocol is not completed fast enough. */ if (ctx->timeout_task) - silc_task_unregister(server->timeout_queue, ctx->timeout_task); + silc_schedule_task_del(server->schedule, ctx->timeout_task); /* On error the final callback is always called. */ if (protocol->final_callback) - protocol->execute_final(server->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, server->schedule); else silc_protocol_free(protocol); break; @@ -485,7 +718,8 @@ silc_server_public_key_authentication(SilcServer server, SILC_STR_END); /* Verify signature */ - if (silc_pkcs_verify(pkcs, sign, sign_len, auth->data, auth->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); return TRUE; @@ -498,7 +732,6 @@ silc_server_public_key_authentication(SilcServer server, static int silc_server_get_public_key_auth(SilcServer server, - SilcPublicKey pub_key, unsigned char *auth_data, uint32 *auth_data_len, SilcSKE ske) @@ -507,14 +740,7 @@ silc_server_get_public_key_auth(SilcServer server, SilcPKCS pkcs; SilcBuffer auth; - if (!pub_key) - return FALSE; - - silc_pkcs_alloc(pub_key->name, &pkcs); - if (!silc_pkcs_public_key_set(pkcs, pub_key)) { - silc_pkcs_free(pkcs); - return FALSE; - } + pkcs = server->pkcs; /* Make the authentication data. Protocol says it is HASH plus KE Start Payload. */ @@ -527,13 +753,12 @@ silc_server_get_public_key_auth(SilcServer server, 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); + 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_pkcs_free(pkcs); silc_buffer_free(auth); return FALSE; } @@ -584,14 +809,14 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) if (ret == -1) { SILC_LOG_DEBUG(("Bad payload in authentication packet")); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } if (payload_len != ctx->packet->buffer->len) { SILC_LOG_DEBUG(("Bad payload in authentication packet")); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } @@ -601,7 +826,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) conn_type > SILC_SOCKET_TYPE_ROUTER) { SILC_LOG_ERROR(("Bad connection type %d", conn_type)); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } @@ -615,8 +840,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) if (ret == -1) { SILC_LOG_DEBUG(("Bad payload in authentication packet")); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, - protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } } @@ -631,14 +855,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) /* 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) { @@ -661,8 +878,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) SILC_LOG_DEBUG(("Authentication failed")); silc_free(auth_data); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, - protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, + 0, 300000); return; break; @@ -682,8 +899,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) SILC_LOG_DEBUG(("Authentication failed")); silc_free(auth_data); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, - protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, + 0, 300000); return; } } else { @@ -692,23 +909,16 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) SILC_LOG_ERROR(("Authentication failed")); silc_free(auth_data); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, - protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, + 0, 300000); return; } } /* 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: @@ -730,8 +940,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) SILC_LOG_DEBUG(("Authentication failed")); silc_free(auth_data); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, - protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, + 0, 300000); return; break; @@ -751,8 +961,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) SILC_LOG_DEBUG(("Authentication failed")); silc_free(auth_data); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, - protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, + 0, 300000); return; } } else { @@ -760,8 +970,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) SILC_LOG_ERROR(("Remote connection not configured")); SILC_LOG_ERROR(("Authentication failed")); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, - protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, + 0, 300000); silc_free(auth_data); return; } @@ -769,15 +979,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) /* 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: @@ -799,8 +1002,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) SILC_LOG_DEBUG(("Authentication failed")); silc_free(auth_data); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, - protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, + 0, 300000); return; break; @@ -820,8 +1023,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) SILC_LOG_DEBUG(("Authentication failed")); silc_free(auth_data); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, - protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, + 0, 300000); return; } } else { @@ -830,8 +1033,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) SILC_LOG_ERROR(("Authentication failed")); silc_free(auth_data); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, - protocol, fd, 0, 300000); + silc_protocol_execute(protocol, server->schedule, + 0, 300000); return; } } @@ -844,7 +1047,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) /* Advance protocol state. */ protocol->state = SILC_PROTOCOL_STATE_END; - protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 0); + silc_protocol_execute(protocol, server->schedule, 0, 0); } else { /* @@ -876,8 +1079,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) unsigned char sign[1024]; /* Public key authentication */ - silc_server_get_public_key_auth(server, ctx->auth_data, - sign, &auth_data_len, + silc_server_get_public_key_auth(server, sign, &auth_data_len, ctx->ske); auth_data = silc_calloc(auth_data_len, sizeof(*auth_data)); memcpy(auth_data, sign, auth_data_len); @@ -931,11 +1133,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) This was the timeout task to be executed if the protocol is not completed fast enough. */ if (ctx->timeout_task) - silc_task_unregister(server->timeout_queue, ctx->timeout_task); + silc_schedule_task_del(server->schedule, ctx->timeout_task); /* Protocol has ended, call the final callback */ if (protocol->final_callback) - protocol->execute_final(server->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, server->schedule); else silc_protocol_free(protocol); } @@ -957,11 +1159,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) This was the timeout task to be executed if the protocol is not completed fast enough. */ if (ctx->timeout_task) - silc_task_unregister(server->timeout_queue, ctx->timeout_task); + silc_schedule_task_del(server->schedule, ctx->timeout_task); /* On error the final callback is always called. */ if (protocol->final_callback) - protocol->execute_final(server->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, server->schedule); else silc_protocol_free(protocol); } @@ -976,11 +1178,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) This was the timeout task to be executed if the protocol is not completed fast enough. */ if (ctx->timeout_task) - silc_task_unregister(server->timeout_queue, ctx->timeout_task); + silc_schedule_task_del(server->schedule, ctx->timeout_task); /* On error the final callback is always called. */ if (protocol->final_callback) - protocol->execute_final(server->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, server->schedule); else silc_protocol_free(protocol); break; @@ -994,58 +1196,141 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) * 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) + 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)); - silc_ske_process_key_material_data(idata->send_enc_key, - idata->enc_key_len, + 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); - 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); - } 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); - } + silc_ske_free_key_material(keymat); +} - silc_hmac_set_key(idata->hmac, keymat->hmac_key, keymat->hmac_key_len); +/* This function actually re-generates (with PFS) the keys and + takes them into use. */ - /* Save the current sending encryption key */ - memset(idata->send_enc_key, 0, idata->enc_key_len); - silc_free(idata->send_enc_key); - idata->send_enc_key = silc_calloc(keymat->enc_key_len / 8, - sizeof(*idata->send_enc_key)); - memcpy(idata->send_enc_key, keymat->send_enc_key, keymat->enc_key_len / 8); - idata->enc_key_len = keymat->enc_key_len / 8; +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); } -/* Performs re-key as defined the SILC protocol specification. */ +/* 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) { @@ -1053,6 +1338,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) SilcServerRekeyInternalContext *ctx = (SilcServerRekeyInternalContext *)protocol->context; SilcServer server = (SilcServer)ctx->server; + SilcIDListData idata = (SilcIDListData)ctx->sock->user_data; + SilcSKEStatus status; SILC_LOG_DEBUG(("Start")); @@ -1079,6 +1366,37 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) * using the SKE protocol. */ + if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_1) { + /* Error in protocol */ + protocol->state = SILC_PROTOCOL_STATE_ERROR; + silc_protocol_execute(protocol, server->schedule, 0, 300000); + return; + } + + 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); + + 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))); + + protocol->state = SILC_PROTOCOL_STATE_ERROR; + silc_protocol_execute(protocol, server->schedule, 0, 300000); + return; + } + + /* Advance the protocol state */ + protocol->state++; + silc_protocol_execute(protocol, server->schedule, 0, 0); } else { /* * Do normal and simple re-key. @@ -1086,7 +1404,12 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) /* 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, TRUE); + 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; @@ -1097,81 +1420,139 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) * 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); + + 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); + if (status != SILC_SKE_STATUS_OK) { + SILC_LOG_WARNING(("Error (%s) during Re-key (PFS)", + silc_ske_map_status(status))); + + protocol->state = SILC_PROTOCOL_STATE_ERROR; + silc_protocol_execute(protocol, server->schedule, 0, 300000); + return; + } + /* Advance the protocol state */ + protocol->state++; } else { /* * Do normal and simple re-key. */ - /* Start the re-key by sending the REKEY packet */ - silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY, - 0, NULL, 0, TRUE); + /* 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 SILC_PROTOCOL_STATE_END: - /* - * End protocol + case 2: + /* + * Second state, used only when oding re-key with PFS. */ - if (ctx->responder == TRUE) { - if (ctx->pfs == TRUE) { /* - * - */ - - } else { - /* - * We must have received the REKEY_DONE from the initiator. + * Send our KE packe to the initiator now that we've processed + * the initiator's KE packet. */ - - if (ctx->packet->type != SILC_PACKET_REKEY_DONE) { - /* Error in protocol */ + 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))); + protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 0); + silc_protocol_execute(protocol, server->schedule, 0, 300000); + return; } } } else { - if (ctx->pfs == TRUE) { /* - * - */ - - } else { - /* - * We must have received the REKEY_DONE from the responder. + * The packet type must be KE packet */ - - if (ctx->packet->type != SILC_PACKET_REKEY_DONE) { + 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, 0); + 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))); + + protocol->state = SILC_PROTOCOL_STATE_ERROR; + silc_protocol_execute(protocol, server->schedule, 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, TRUE); } } + /* 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; + silc_protocol_execute(protocol, server->schedule, 0, 300000); + return; + } + + /* 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); + silc_protocol_execute_final(protocol, server->schedule); else silc_protocol_free(protocol); break; @@ -1183,14 +1564,12 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) if (ctx->pfs == TRUE) { /* Send abort notification */ - silc_ske_abort(ctx->ske, ctx->ske->status, - silc_server_protocol_ke_send_packet, - context); + silc_ske_abort(ctx->ske, ctx->ske->status); } /* On error the final callback is always called. */ if (protocol->final_callback) - protocol->execute_final(server->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, server->schedule); else silc_protocol_free(protocol); break; @@ -1202,7 +1581,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) /* On error the final callback is always called. */ if (protocol->final_callback) - protocol->execute_final(server->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, server->schedule); else silc_protocol_free(protocol); break; @@ -1223,6 +1602,8 @@ void silc_server_protocols_register(void) silc_server_protocol_key_exchange); silc_protocol_register(SILC_PROTOCOL_SERVER_REKEY, silc_server_protocol_rekey); + silc_protocol_register(SILC_PROTOCOL_SERVER_BACKUP, + silc_server_protocol_backup); } /* Unregisters protocols */ @@ -1235,4 +1616,6 @@ void silc_server_protocols_unregister(void) silc_server_protocol_key_exchange); silc_protocol_unregister(SILC_PROTOCOL_SERVER_REKEY, silc_server_protocol_rekey); + silc_protocol_unregister(SILC_PROTOCOL_SERVER_BACKUP, + silc_server_protocol_backup); }