From 0b2abb8c3271f529fd69a028e4ab406de8596851 Mon Sep 17 00:00:00 2001 From: Jan Hutter Date: Mon, 21 Nov 2005 10:59:45 +0000 Subject: [PATCH] further implemented --- Source/charon/ike_sa.c | 340 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 280 insertions(+), 60 deletions(-) diff --git a/Source/charon/ike_sa.c b/Source/charon/ike_sa.c index 3a6b099..760d906 100644 --- a/Source/charon/ike_sa.c +++ b/Source/charon/ike_sa.c @@ -99,11 +99,29 @@ struct private_ike_sa_s { */ ike_sa_t public; + /** + * Builds an empty IKEv2-Message + * + * Depending on the type of message (request or response), the message id is + * either message_id_out or message_id_in. + * + * + * @param this calling object + * @param type exchange type of new message + * @param request TRUE, if message has to be a request + * @param message new message is stored at this location + * @return + * - SUCCESS + * - OUT_OF_RES + */ + status_t (*build_message) (private_ike_sa_t *this, exchange_type_t type, bool request, message_t **message); + status_t (*build_sa_payload) (private_ike_sa_t *this, sa_payload_t **payload); status_t (*build_ke_payload) (private_ike_sa_t *this, ke_payload_t **payload); status_t (*build_nonce_payload) (private_ike_sa_t *this, nonce_payload_t **payload); - status_t (*build_message) (private_ike_sa_t *this, exchange_type_t type, bool request, message_t **message); + status_t (*create_delete_job) (private_ike_sa_t *this); + status_t (*resend_last_reply) (private_ike_sa_t *this); status_t (*transto_ike_sa_init_requested) (private_ike_sa_t *this, char *name); @@ -163,6 +181,7 @@ struct private_ike_sa_s { * Diffie Hellman object used to compute shared secret */ diffie_hellman_t *diffie_hellman; + /** * Diffie Hellman group number */ @@ -177,10 +196,12 @@ struct private_ike_sa_s { * selected proposals */ linked_list_t *proposals; + /** * Sent nonce value */ chunk_t sent_nonce; + /** * received nonce value */ @@ -211,18 +232,56 @@ static status_t process_message (private_ike_sa_t *this, message_t *message) { u_int32_t message_id; bool is_request; + exchange_type_t exchange_type; + /* we must process each request or response from remote host + * the check if a given message is possible for a given state is done in here + */ + + /* find out type of message (request or response) */ is_request = message->get_request(message); + exchange_type = message->get_exchange_type(message); + this->logger->log(this->logger, CONTROL|MORE, "Process %s message of exchange type %s",(is_request) ? "REQUEST" : "RESPONSE", - mapping_find(exchange_type_m,message->get_exchange_type(message))); - + mapping_find(exchange_type_m,exchange_type)); + + message_id = message->get_message_id(message); - //message->get_exchange_type(message); + /* + * It has to be checked, if the message has to be resent cause of lost packets! + */ + if (is_request && ( message_id == (this->message_id_in - 1))) + { + /* message can be resent ! */ + this->logger->log(this->logger, CONTROL|MORE, "Resent message detected. Send stored reply"); + return (this->resend_last_reply(this)); + } + /* Now, the message id is checked for request AND reply */ + if (is_request) + { + /* In a request, the message has to be this->message_id_in (other case is already handled) */ + if (message_id != this->message_id_in) + { + this->logger->log(this->logger, ERROR | MORE, "Message request with message id %d received, but %d expected",message_id,this->message_id_in); + return FAILED; + } + } + else + { + /* In a reply, the message has to be this->message_id_out -1 cause it is the reply to the last sent message*/ + if (message_id != (this->message_id_out - 1)) + { + this->logger->log(this->logger, ERROR | MORE, "Message reply with message id %d received, but %d expected",message_id,this->message_id_in); + return FAILED; + } + } + /* Now, the exchange type is checked and the appropriate transition handler is called*/ switch (message->get_exchange_type(message)) { case IKE_SA_INIT: { + if (message->get_request(message)) { if (this->state == NO_STATE) { @@ -242,15 +301,25 @@ static status_t process_message (private_ike_sa_t *this, message_t *message) } case IKE_AUTH: { - /* break; */ + if (this->state <= IKE_SA_INIT_REQUESTED) + { + this->logger->log(this->logger, ERROR | MORE, "Current state %s of IKE_SA does not allow IKE_AUTH message",mapping_find(ike_sa_state_m,this->state)); + return FAILED; + } + break; } case CREATE_CHILD_SA: { - /* break; */ + if (this->state < IKE_SA_INITIALIZED) + { + this->logger->log(this->logger, ERROR | MORE, "Current state %s of IKE_SA does not allow CREATE_CHILD_SA message",mapping_find(ike_sa_state_m,this->state)); + return FAILED; + } + break; } case INFORMATIONAL: { - /* break; */ + break; } default: { @@ -259,54 +328,69 @@ static status_t process_message (private_ike_sa_t *this, message_t *message) return NOT_SUPPORTED; } } - this->logger->log(this->logger, ERROR, "received %s-message in state %s, rejected.", + this->logger->log(this->logger, CONTROL, "received %s-message in state %s, not handled.", mapping_find(exchange_type_m, message->get_exchange_type(message)), mapping_find(ike_sa_state_m, this->state)); return INVALID_STATE; } - +/** + * @brief Implements function build_message of private_ike_sa_t. + */ static status_t build_message(private_ike_sa_t *this, exchange_type_t type, bool request, message_t **message) { status_t status; message_t *new_message; host_t *source, *destination; - + + this ->logger->log(this->logger, CONTROL|MORE, "build empty message"); new_message = message_create(); if (new_message == NULL) { + this->logger->log(this->logger, ERROR, "Fatal error: could not create empty message object"); return OUT_OF_RES; } status = this->me.host->clone(this->me.host, &source); - status |= this->other.host->clone(this->other.host, &destination); if (status != SUCCESS) { + this->logger->log(this->logger, ERROR, "Fatal error: could not clone my host information"); + new_message->destroy(new_message); + return status; + } + status = this->other.host->clone(this->other.host, &destination); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Fatal error: could not clone other host information"); + source->destroy(source); new_message->destroy(new_message); return status; } + new_message->set_source(new_message, source); new_message->set_destination(new_message, destination); new_message->set_exchange_type(new_message, type); new_message->set_request(new_message, request); - if (request) - { - new_message->set_message_id(new_message, this->message_id_out); - }else + new_message->set_message_id(new_message, (request) ? this->message_id_out : this->message_id_in); + + status = new_message->set_ike_sa_id(new_message, this->ike_sa_id); + if (status != SUCCESS) { - new_message->set_message_id(new_message, this->message_id_in); + this->logger->log(this->logger, ERROR, "Fatal error: could not set ike_sa_id of message"); + new_message->destroy(new_message); + return status; } - new_message->set_ike_sa_id(new_message, this->ike_sa_id); - *message = new_message; return SUCCESS; } - +/** + * @brief Implements function transto_ike_sa_init_requested of private_ike_sa_t. + */ static status_t transto_ike_sa_init_requested(private_ike_sa_t *this, char *name) { message_t *message; @@ -314,32 +398,35 @@ static status_t transto_ike_sa_init_requested(private_ike_sa_t *this, char *name packet_t *packet; status_t status; - this->logger->log(this->logger, CONTROL, "initializing connection"); - + this->logger->log(this->logger, CONTROL, "Initializing connection %s",name); + status = global_configuration_manager->get_local_host(global_configuration_manager, name, &(this->me.host)); if (status != SUCCESS) { + this->logger->log(this->logger, ERROR | MORE, "Could not retrieve local host configuration information for %s",name); return INVALID_ARG; } status = global_configuration_manager->get_remote_host(global_configuration_manager, name, &(this->other.host)); if (status != SUCCESS) { + this->logger->log(this->logger, ERROR | MORE, "Could not retrieve remote host configuration information for %s",name); return INVALID_ARG; } status = global_configuration_manager->get_dh_group_number(global_configuration_manager, name, &(this->ike_sa_init_data.dh_group_number), this->ike_sa_init_data.dh_group_priority); if (status != SUCCESS) { + this->logger->log(this->logger, ERROR | MORE, "Could not retrieve DH group number for %s",name); return INVALID_ARG; } - this ->logger->log(this->logger, CONTROL|MORE, "create diffie hellman object"); if (this->ike_sa_init_data.diffie_hellman != NULL) { - this->logger->log(this->logger, ERROR, "Object of type diffie_hellman_t already existing!"); + this->logger->log(this->logger, ERROR, "Object of type diffie_hellman_t already existing!"); return FAILED; } + this ->logger->log(this->logger, CONTROL|MOST, "create diffie hellman object"); this->ike_sa_init_data.diffie_hellman = diffie_hellman_create(this->ike_sa_init_data.dh_group_number); if (this->ike_sa_init_data.diffie_hellman == NULL) { @@ -361,7 +448,6 @@ static status_t transto_ike_sa_init_requested(private_ike_sa_t *this, char *name /* going to build message */ - status = this->build_message(this, IKE_SA_INIT, TRUE, &message); if (status != SUCCESS) { @@ -377,7 +463,16 @@ static status_t transto_ike_sa_init_requested(private_ike_sa_t *this, char *name message->destroy(message); return status; } - message->add_payload(message, payload); + + this ->logger->log(this->logger, CONTROL|MOST, "add SA payload to message"); + status = message->add_payload(message, payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not add SA payload to message"); + message->destroy(message); + return status; + } + /* build KE payload */ status = this->build_ke_payload(this,(ke_payload_t **) &payload); @@ -387,7 +482,15 @@ static status_t transto_ike_sa_init_requested(private_ike_sa_t *this, char *name message->destroy(message); return status; } - message->add_payload(message, payload); + + this ->logger->log(this->logger, CONTROL|MOST, "add KE payload to message"); + status = message->add_payload(message, payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not add KE payload to message"); + message->destroy(message); + return status; + } /* build Nonce payload */ status = this->build_nonce_payload(this, (nonce_payload_t**)&payload); @@ -397,17 +500,26 @@ static status_t transto_ike_sa_init_requested(private_ike_sa_t *this, char *name message->destroy(message); return status; } - message->add_payload(message, payload); - + + this ->logger->log(this->logger, CONTROL|MOST, "add nonce payload to message"); + status = message->add_payload(message, payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not add nonce payload to message"); + message->destroy(message); + return status; + } + this ->logger->log(this->logger, CONTROL|MOST, "generate packet from message"); status = message->generate(message, &packet); if (status != SUCCESS) { - this->logger->log(this->logger, ERROR, "Could not generate message"); + this->logger->log(this->logger, ERROR, "Fatal error: could not generate packet from message"); message->destroy(message); return status; } + this ->logger->log(this->logger, CONTROL|MOST, "Add packet to global send queue"); status = global_send_queue->add(global_send_queue, packet); if (status != SUCCESS) { @@ -419,6 +531,7 @@ static status_t transto_ike_sa_init_requested(private_ike_sa_t *this, char *name if ( this->last_requested_message != NULL) { /* destroy message */ + this ->logger->log(this->logger, CONTROL|MOST, "Destroy stored last requested message"); this->last_requested_message->destroy(this->last_requested_message); } @@ -428,6 +541,7 @@ static status_t transto_ike_sa_init_requested(private_ike_sa_t *this, char *name this->message_id_out++; /* states has NOW changed :-) */ + this ->logger->log(this->logger, CONTROL|MORE, "Change state of IKE_SA from %s to %s",mapping_find(ike_sa_state_m,this->state),mapping_find(ike_sa_state_m,IKE_SA_INIT_REQUESTED) ); this->state = IKE_SA_INIT_REQUESTED; return SUCCESS; @@ -451,45 +565,64 @@ static status_t transto_ike_sa_init_responded(private_ike_sa_t *this, message_t status = request->parse_body(request); if (status != SUCCESS) { - this->logger->log(this->logger, ERROR, "Could not parse body"); + this->logger->log(this->logger, ERROR | MORE, "Could not parse body of request message"); + this->create_delete_job(this); return status; } - /* iterate over incoming payloads */ + + /* iterate over incoming payloads. We can be sure, the message contains only accepted payloads! */ status = request->get_payload_iterator(request, &payloads); if (status != SUCCESS) { - request->destroy(request); - return status; + this->logger->log(this->logger, ERROR, "Fatal error: Could not get payload interator"); + this->create_delete_job(this); + return status; } + while (payloads->has_next(payloads)) { payload_t *payload; + + /* get current payload */ payloads->current(payloads, (void**)&payload); - this->logger->log(this->logger, CONTROL|MORE, "Processing payload %s", mapping_find(payload_type_m, payload->get_type(payload))); + this->logger->log(this->logger, CONTROL|MORE, "Processing payload of type %s", mapping_find(payload_type_m, payload->get_type(payload))); switch (payload->get_type(payload)) { case SECURITY_ASSOCIATION: { sa_payload_t *sa_payload = (sa_payload_t*)payload; linked_list_iterator_t *suggested_proposals, *accepted_proposals; + /* create a list for accepted proposals */ - if (this->ike_sa_init_data.proposals == NULL) { + if (this->ike_sa_init_data.proposals == NULL) + { this->ike_sa_init_data.proposals = linked_list_create(); } else { - /** @todo destroy list contents */ + /* delete stored proposals */ + while (this->ike_sa_init_data.proposals->get_count(this->ike_sa_init_data.proposals) > 0) + { + proposal_substructure_t *current_proposal; + this->ike_sa_init_data.proposals->remove_first(this->ike_sa_init_data.proposals,(void **)¤t_proposal); + current_proposal->destroy(current_proposal); + } } if (this->ike_sa_init_data.proposals == NULL) { + /* destroy iterator and leave */ + this->logger->log(this->logger, ERROR, "Fatal error: Could not create list for proposals"); payloads->destroy(payloads); + this->create_delete_job(this); return OUT_OF_RES; } status = this->ike_sa_init_data.proposals->create_iterator(this->ike_sa_init_data.proposals, &accepted_proposals, FALSE); if (status != SUCCESS) { + this->logger->log(this->logger, ERROR, "Fatal error: Could not create iterator on list for proposals"); payloads->destroy(payloads); + this->create_delete_job(this); return status; } @@ -497,8 +630,10 @@ static status_t transto_ike_sa_init_responded(private_ike_sa_t *this, message_t status = sa_payload->create_proposal_substructure_iterator(sa_payload, &suggested_proposals, TRUE); if (status != SUCCESS) { + this->logger->log(this->logger, ERROR, "Fatal error: Could not create iterator on suggested proposals"); accepted_proposals->destroy(accepted_proposals); payloads->destroy(payloads); + this->create_delete_job(this); return status; } @@ -507,51 +642,64 @@ static status_t transto_ike_sa_init_responded(private_ike_sa_t *this, message_t this->other.host, suggested_proposals, accepted_proposals); if (status != SUCCESS) { + this->logger->log(this->logger, CONTROL | MORE, "No proposal of suggested proposals selected"); suggested_proposals->destroy(suggested_proposals); accepted_proposals->destroy(accepted_proposals); payloads->destroy(payloads); + this->create_delete_job(this); return status; } - + + /* iterators are not needed anymore */ suggested_proposals->destroy(suggested_proposals); accepted_proposals->destroy(accepted_proposals); - /* ok, we have what we need for sa_payload */ + /* ok, we have what we need for sa_payload (proposals are stored in this->proposals)*/ break; } case KEY_EXCHANGE: { ke_payload_t *ke_payload = (ke_payload_t*)payload; - diffie_hellman_t *dh; diffie_hellman_group_t group; + diffie_hellman_t *dh; bool allowed_group; group = ke_payload->get_dh_group_number(ke_payload); status = global_configuration_manager->is_dh_group_allowed_for_host(global_configuration_manager, this->other.host, group, &allowed_group); + if (status != SUCCESS) { + this->logger->log(this->logger, ERROR | MORE, "Could not get informations about DH group"); payloads->destroy(payloads); + this->create_delete_job(this); return status; } if (!allowed_group) { - /** @todo info reply */ + /** @todo Send info reply */ } + /* create diffie hellman object to handle DH exchange */ dh = diffie_hellman_create(group); if (dh == NULL) { + this->logger->log(this->logger, ERROR, "Could not generate DH object"); payloads->destroy(payloads); + this->create_delete_job(this); return OUT_OF_RES; } + + this->logger->log(this->logger, CONTROL | MORE, "Set other DH public value"); status = dh->set_other_public_value(dh, ke_payload->get_key_exchange_data(ke_payload)); if (status != SUCCESS) { + this->logger->log(this->logger, ERROR, "Could not set other DH public value"); dh->destroy(dh); payloads->destroy(payloads); + this->create_delete_job(this); return OUT_OF_RES; } /** @todo destroy if there is already one */ @@ -562,7 +710,8 @@ static status_t transto_ike_sa_init_responded(private_ike_sa_t *this, message_t { nonce_payload_t *nonce_payload = (nonce_payload_t*)payload; chunk_t nonce; - + + this->logger->log(this->logger, CONTROL | MORE, "Get nonce value and store it"); nonce_payload->get_nonce(nonce_payload, &nonce); /** @todo free if there is already one */ this->ike_sa_init_data.received_nonce.ptr = allocator_clone_bytes(nonce.ptr, nonce.len); @@ -570,6 +719,7 @@ static status_t transto_ike_sa_init_responded(private_ike_sa_t *this, message_t if (this->ike_sa_init_data.received_nonce.ptr == NULL) { payloads->destroy(payloads); + this->create_delete_job(this); return OUT_OF_RES; } break; @@ -582,34 +732,24 @@ static status_t transto_ike_sa_init_responded(private_ike_sa_t *this, message_t } } + /* iterator can be destroyed */ payloads->destroy(payloads); - printf("done.\n"); + this->logger->log(this->logger, CONTROL | MORE, "Request successfully handled. Going to create reply."); /* set up the reply */ status = this->build_message(this, IKE_SA_INIT, FALSE, &response); if (status != SUCCESS) { + this->logger->log(this->logger, ERROR, "Could not create empty message"); + this->create_delete_job(this); return status; } + /* leaks */ + response->destroy(response); - - /* - job_t *delete_job; - delete_job = (job_t *) delete_ike_sa_job_create(this->ike_sa_id); - if (delete_job == NULL) - { - this->logger->log(this->logger, ERROR, "Job to delete IKE SA could not be created"); - } - - status = global_job_queue->add(global_job_queue,delete_job); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "%s Job to delete IKE SA could not be added to job queue",mapping_find(status_m,status)); - delete_job->destroy_all(delete_job); - }*/ return SUCCESS; } @@ -748,9 +888,13 @@ static status_t transto_ike_auth_requested(private_ike_sa_t *this, message_t *re status = this->build_message(this, IKE_SA_INIT, FALSE, &response); if (status != SUCCESS) { + this->create_delete_job(this); return status; } + + response->destroy(response); + return SUCCESS; } @@ -883,6 +1027,55 @@ static status_t build_nonce_payload(private_ike_sa_t *this, nonce_payload_t **pa } /** + * @brief implements function resend_last_reply of private_ike_sa_t + */ +status_t resend_last_reply (private_ike_sa_t *this) +{ + packet_t *packet; + status_t status; + + status = this->last_responded_message->generate(this->last_responded_message, &packet); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not generate message to resent"); + return status; + } + + status = global_send_queue->add(global_send_queue, packet); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not add packet to send queue"); + packet->destroy(packet); + return status; + } + return SUCCESS; +} + +status_t create_delete_job (private_ike_sa_t *this) +{ + job_t *delete_job; + status_t status; + + this->logger->log(this->logger, CONTROL | MORE, "Going to create job to delete this IKE_SA"); + + delete_job = (job_t *) delete_ike_sa_job_create(this->ike_sa_id); + if (delete_job == NULL) + { + this->logger->log(this->logger, ERROR, "Job to delete IKE SA could not be created"); + return FAILED; + } + + status = global_job_queue->add(global_job_queue,delete_job); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "%s Job to delete IKE SA could not be added to job queue",mapping_find(status_m,status)); + delete_job->destroy_all(delete_job); + return status; + } + return SUCCESS; +} + +/** * @brief implements function destroy of private_ike_sa_t */ static status_t destroy (private_ike_sa_t *this) @@ -921,9 +1114,24 @@ static status_t destroy (private_ike_sa_t *this) this->last_responded_message->destroy(this->last_responded_message); } + /* destroy stored proposal */ + if (this->ike_sa_init_data.proposals != NULL) + { + this->logger->log(this->logger, CONTROL | MOST, "Destroy stored proposals"); + while (this->ike_sa_init_data.proposals->get_count(this->ike_sa_init_data.proposals) > 0) + { + proposal_substructure_t *current_proposal; + this->ike_sa_init_data.proposals->remove_first(this->ike_sa_init_data.proposals,(void **)¤t_proposal); + current_proposal->destroy(current_proposal); + } + this->ike_sa_init_data.proposals->destroy(this->ike_sa_init_data.proposals); + } + this->logger->log(this->logger, CONTROL | MOST, "Destroy randomizer"); this->randomizer->destroy(this->randomizer); + + /* destroy ike_sa_init data */ this->logger->log(this->logger, CONTROL | MOST, "Going to destroy ike_sa_init data"); if (this->ike_sa_init_data.diffie_hellman != NULL) { @@ -941,11 +1149,23 @@ static status_t destroy (private_ike_sa_t *this) allocator_free_chunk(this->ike_sa_init_data.received_nonce); } + if (this->me.host != NULL) + { + this->logger->log(this->logger, CONTROL | MOST, "Destroy host informations of me"); + this->me.host->destroy(this->me.host); + } + + if (this->other.host != NULL) + { + this->logger->log(this->logger, CONTROL | MOST, "Destroy host informations of other"); + this->other.host->destroy(this->other.host); + } + + this->logger->log(this->logger, CONTROL | MOST, "Destroy logger of IKE_SA"); global_logger_manager->destroy_logger(global_logger_manager, this->logger); allocator_free(this); - return SUCCESS; } @@ -960,7 +1180,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) return NULL; } - /* Public functions */ this->public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message; this->public.initialize_connection = (status_t(*)(ike_sa_t*, char*)) initialize_connection; @@ -975,8 +1194,9 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->transto_ike_sa_init_requested = transto_ike_sa_init_requested; this->transto_ike_sa_init_responded = transto_ike_sa_init_responded; this->transto_ike_auth_requested = transto_ike_auth_requested; + this->resend_last_reply = resend_last_reply; + this->create_delete_job = create_delete_job; - /* initialize private fields */ this->logger = global_logger_manager->create_logger(global_logger_manager, IKE_SA, NULL); -- 2.7.4