X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Fsilcd%2Fprotocol.c;h=794a20880279462c6b473c8896443a1c971969e2;hb=386c883d8774999c6e74d7c6c37e52e4163a4cb1;hp=64d40f1f26f493c508f403ca6b6c7764636314d0;hpb=e50ed85129da65f2451e9d59546ec5538c7a33df;p=silc.git diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c index 64d40f1f..794a2088 100644 --- a/apps/silcd/protocol.c +++ b/apps/silcd/protocol.c @@ -131,12 +131,11 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock, /* Save the key for future checking */ unlink(filename); - silc_pkcs_save_public_key_data(filename, pk, pk_len, - SILC_PKCS_FILE_PEM); + silc_pkcs_save_public_key_data(filename, pk, pk_len, SILC_PKCS_FILE_PEM); return TRUE; } - if (memcmp(encpk, pk, encpk_len)) { + 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, sock->port)); @@ -277,14 +276,11 @@ int silc_server_protocol_ke_set_keys(SilcServer server, } 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->send_enc_key = silc_memdup(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) + if (ske->prop->flags & SILC_SKE_SP_FLAG_PFS) idata->rekey->pfs = TRUE; idata->rekey->ske_group = silc_ske_group_get_number(group); @@ -458,9 +454,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) SilcSKE ske; /* Allocate Key Exchange object */ - ske = silc_ske_alloc(); - ctx->ske = ske; - ske->rng = server->rng; + 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, @@ -472,12 +466,12 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) properties packet from initiator. */ status = silc_ske_responder_start(ske, ctx->rng, ctx->sock, silc_version_string, - ctx->packet->buffer, TRUE); + ctx->packet->buffer, ctx->flags); } else { SilcSKEStartPayload *start_payload; /* Assemble security properties. */ - silc_ske_assemble_security_properties(ske, SILC_SKE_SP_FLAG_MUTUAL, + silc_ske_assemble_security_properties(ske, ctx->flags, silc_version_string, &start_payload); @@ -515,8 +509,7 @@ 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); + 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 @@ -563,7 +556,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) Key Exhange 1 Payload to the responder. */ status = silc_ske_initiator_phase_2(ctx->ske, server->public_key, - server->private_key); + server->private_key, + SILC_SKE_PK_TYPE_SILC); protocol->state++; } @@ -654,6 +648,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) 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 + timeout callbacks for this protocol. */ + silc_protocol_cancel(protocol, server->schedule); + /* Call the final callback */ if (protocol->final_callback) silc_protocol_execute_final(protocol, server->schedule); @@ -676,6 +675,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) 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 + 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); @@ -694,6 +698,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) 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 + 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); @@ -711,13 +720,13 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange) */ static int -silc_server_password_authentication(SilcServer server, char *auth1, - char *auth2) +silc_server_password_authentication(SilcServer server, char *remote_auth, + char *local_auth) { - if (!auth1 || !auth2) + if (!remote_auth || !local_auth) return FALSE; - if (!memcmp(auth1, auth2, strlen(auth1))) + if (!memcmp(remote_auth, local_auth, strlen(local_auth))) return TRUE; return FALSE; @@ -769,7 +778,7 @@ silc_server_public_key_authentication(SilcServer server, static int silc_server_get_public_key_auth(SilcServer server, - unsigned char *auth_data, + unsigned char **auth_data, uint32 *auth_data_len, SilcSKE ske) { @@ -790,16 +799,63 @@ 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->len, auth_data, auth_data_len)) { + auth->len, *auth_data, auth_data_len)) { silc_buffer_free(auth); return TRUE; } + silc_free(*auth_data); silc_buffer_free(auth); return FALSE; } +/* Function that actually performs the authentication to the remote. This + supports both passphrase and public key authentication. */ + +static bool +silc_server_get_authentication(SilcServerConnAuthInternalContext *ctx, + char *local_passphrase, + void *local_publickey, + unsigned char *remote_auth, + uint32 remote_auth_len) +{ + SilcServer server = (SilcServer)ctx->server; + SilcSKE ske = ctx->ske; + bool result = FALSE; + + /* If we don't have authentication data set at all we do not require + authentication at all */ + if (!local_passphrase && !local_publickey) { + SILC_LOG_DEBUG(("No authentication required")); + return TRUE; + } + + /* If both passphrase and public key is provided then we'll try both of + them and see which one of them authenticates. If only one of them is + set, then try only that. */ + + /* Try first passphrase (as it is faster to check) */ + if (local_passphrase) { + SILC_LOG_DEBUG(("Password authentication")); + result = silc_server_password_authentication(server, local_passphrase, + remote_auth); + } + + /* Try public key authenetication */ + if (!result && local_publickey) { + SILC_LOG_DEBUG(("Public key authentication")); + result = silc_server_public_key_authentication(server, + local_publickey, + remote_auth, + remote_auth_len, + ske); + } + + return result; +} + /* Performs connection authentication protocol. If responder, we authenticate the remote data received. If initiator, we will send authentication data to the remote end. */ @@ -892,57 +948,24 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) /* Remote end is client */ if (conn_type == SILC_SOCKET_TYPE_CLIENT) { - SilcServerConfigSectionClientConnection *client = ctx->cconfig; + SilcServerConfigClient *client = ctx->cconfig; if (client) { - switch(client->auth_meth) { - case SILC_AUTH_NONE: - /* No authentication required */ - SILC_LOG_DEBUG(("No authentication required")); - break; - - case SILC_AUTH_PASSWORD: - /* Password authentication */ - SILC_LOG_DEBUG(("Password authentication")); - ret = silc_server_password_authentication(server, auth_data, - client->auth_data); - - if (ret) - break; - + ret = silc_server_get_authentication(ctx, client->passphrase, + client->publickey, + 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; - break; - - case SILC_AUTH_PUBLIC_KEY: - /* Public key authentication */ - SILC_LOG_DEBUG(("Public key authentication")); - ret = silc_server_public_key_authentication(server, - client->auth_data, - auth_data, - payload_len, - ctx->ske); - - if (ret) - break; - - 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); + silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } } else { - SILC_LOG_DEBUG(("No configuration for remote connection")); - SILC_LOG_ERROR(("Remote connection not configured")); + 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; @@ -954,57 +977,24 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) /* Remote end is server */ if (conn_type == SILC_SOCKET_TYPE_SERVER) { - SilcServerConfigSectionServerConnection *serv = ctx->sconfig; + SilcServerConfigServer *serv = ctx->sconfig; if (serv) { - switch(serv->auth_meth) { - case SILC_AUTH_NONE: - /* No authentication required */ - SILC_LOG_DEBUG(("No authentication required")); - break; - - case SILC_AUTH_PASSWORD: - /* Password authentication */ - SILC_LOG_DEBUG(("Password authentication")); - ret = silc_server_password_authentication(server, auth_data, - serv->auth_data); - - if (ret) - break; - + ret = silc_server_get_authentication(ctx, serv->passphrase, + serv->publickey, + 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; - break; - - case SILC_AUTH_PUBLIC_KEY: - /* Public key authentication */ - SILC_LOG_DEBUG(("Public key authentication")); - ret = silc_server_public_key_authentication(server, - serv->auth_data, - auth_data, - payload_len, - ctx->ske); - - if (ret) - break; - - 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); + silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } } else { - SILC_LOG_DEBUG(("No configuration for remote connection")); - SILC_LOG_ERROR(("Remote connection not configured")); + 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, @@ -1016,57 +1006,24 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) /* Remote end is router */ if (conn_type == SILC_SOCKET_TYPE_ROUTER) { - SilcServerConfigSectionServerConnection *serv = ctx->rconfig; + SilcServerConfigRouter *serv = ctx->rconfig; if (serv) { - switch(serv->auth_meth) { - case SILC_AUTH_NONE: - /* No authentication required */ - SILC_LOG_DEBUG(("No authentication required")); - break; - - case SILC_AUTH_PASSWORD: - /* Password authentication */ - SILC_LOG_DEBUG(("Password authentication")); - ret = silc_server_password_authentication(server, auth_data, - serv->auth_data); - - if (ret) - break; - + ret = silc_server_get_authentication(ctx, serv->passphrase, + serv->publickey, + 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; - break; - - case SILC_AUTH_PUBLIC_KEY: - /* Public key authentication */ - SILC_LOG_DEBUG(("Public key authentication")); - ret = silc_server_public_key_authentication(server, - serv->auth_data, - auth_data, - payload_len, - ctx->ske); - - if (ret) - break; - - 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); + silc_protocol_execute(protocol, server->schedule, 0, 300000); return; } } else { - SILC_LOG_DEBUG(("No configuration for remote connection")); - SILC_LOG_ERROR(("Remote connection not configured")); + 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; @@ -1113,13 +1070,9 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) case SILC_AUTH_PUBLIC_KEY: { - unsigned char sign[1024]; - /* Public key authentication */ - silc_server_get_public_key_auth(server, sign, &auth_data_len, + silc_server_get_public_key_auth(server, &auth_data, &auth_data_len, ctx->ske); - auth_data = silc_calloc(auth_data_len, sizeof(*auth_data)); - memcpy(auth_data, sign, auth_data_len); break; } } @@ -1172,6 +1125,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) 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 + 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); @@ -1198,6 +1156,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) 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 + 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); @@ -1217,6 +1180,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) 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 + 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); @@ -1276,11 +1244,8 @@ silc_server_protocol_rekey_validate(SilcServer server, 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->send_enc_key = silc_memdup(keymat->send_enc_key, + keymat->enc_key_len / 8); idata->rekey->enc_key_len = keymat->enc_key_len / 8; } } @@ -1409,8 +1374,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) return; } - ctx->ske = silc_ske_alloc(); - ctx->ske->rng = server->rng; + ctx->ske = silc_ske_alloc(server->rng, server); ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop)); silc_ske_group_get_by_number(idata->rekey->ske_group, &ctx->ske->prop->group); @@ -1465,8 +1429,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) * 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 = silc_ske_alloc(server->rng, server); ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop)); silc_ske_group_get_by_number(idata->rekey->ske_group, &ctx->ske->prop->group); @@ -1476,7 +1439,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) NULL, NULL, NULL, silc_ske_check_version, context); - status = silc_ske_initiator_phase_2(ctx->ske, NULL, NULL); + 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))); @@ -1586,6 +1549,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) encrypted with the new key so set the decryption key to the new key */ 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 + 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); @@ -1603,6 +1571,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) 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 + 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); @@ -1615,6 +1588,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey) * We have received failure from remote */ + /* Assure that after calling final callback there cannot be pending + 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);