From 8323a9c12002a5e25ceb8dfef406e235dd548517 Mon Sep 17 00:00:00 2001 From: Jan Hutter Date: Mon, 21 Nov 2005 16:41:24 +0000 Subject: [PATCH] current state --- Source/charon/daemon.c | 2 +- Source/charon/ike_sa.c | 1192 ++---------------- Source/charon/ike_sa.h | 151 +++ Source/charon/states/ike_auth_requested.c | 10 +- Source/charon/states/ike_auth_requested.h | 5 +- Source/charon/states/ike_sa_established.c | 10 +- Source/charon/states/ike_sa_established.h | 5 +- Source/charon/states/ike_sa_init_requested.c | 254 ++++ Source/charon/states/ike_sa_init_requested.h | 51 + Source/charon/states/ike_sa_init_responded.c | 91 ++ Source/charon/states/ike_sa_init_responded.h | 47 + Source/charon/states/initiator_init.c | 418 +++++- Source/charon/states/initiator_init.h | 6 +- Source/charon/states/responder_init.c | 480 ++++++- Source/charon/states/responder_init.h | 6 +- Source/charon/states/state.h | 2 + Source/charon/thread_pool.c | 12 +- 17 files changed, 1605 insertions(+), 1137 deletions(-) diff --git a/Source/charon/daemon.c b/Source/charon/daemon.c index 7de66a80d..c30459ed8 100644 --- a/Source/charon/daemon.c +++ b/Source/charon/daemon.c @@ -145,7 +145,7 @@ int main() { initiate_ike_sa_job_t *initiate_job; - initiate_job = initiate_ike_sa_job_create("pinflb31"); + initiate_job = initiate_ike_sa_job_create("pinflb30"); global_event_queue->add_relative(global_event_queue, (job_t*)initiate_job, i * 1000); } diff --git a/Source/charon/ike_sa.c b/Source/charon/ike_sa.c index 1829c652c..3d0a5c165 100644 --- a/Source/charon/ike_sa.c +++ b/Source/charon/ike_sa.c @@ -36,218 +36,30 @@ #include "payloads/ke_payload.h" #include "payloads/transform_substructure.h" #include "payloads/transform_attribute.h" +#include "states/initiator_init.h" +#include "states/responder_init.h" + + /** - * Nonce size in bytes of all sent nonces + * @brief implements function process_message of protected_ike_sa_t */ -#define NONCE_SIZE 16 - -/** - * States in which a IKE_SA can actually be - */ -typedef enum ike_sa_state_e ike_sa_state_t; - -enum ike_sa_state_e { - - /** - * IKE_SA is is not in a state - */ - NO_STATE = 1, - - /** - * A IKE_SA_INIT-message was sent: role initiator - */ - IKE_SA_INIT_REQUESTED = 2, - - /** - * A IKE_SA_INIT-message was replied: role responder - */ - IKE_SA_INIT_RESPONDED = 3, - - /** - * An IKE_AUTH-message was sent after a successful - * IKE_SA_INIT-exchange: role initiator - */ - IKE_AUTH_REQUESTED = 4, - - /** - * An IKE_AUTH-message was replied: role responder. - * In this state, all the informations for an IKE_SA - * and one CHILD_SA are known. - */ - IKE_SA_INITIALIZED = 5 -}; - -/** - * string mappings for ike_sa_state - */ -mapping_t ike_sa_state_m[] = { - {NO_STATE, "NO_STATE"}, - {IKE_SA_INIT_REQUESTED, "IKE_SA_INIT_REQUESTED"}, - {IKE_SA_INIT_RESPONDED, "IKE_SA_INIT_RESPONDED"}, - {IKE_AUTH_REQUESTED, "IKE_AUTH_REQUESTED"}, - {IKE_SA_INITIALIZED, "IKE_SA_INITIALIZED"}, - {MAPPING_END, NULL} -}; - - -/** - * Private data of an message_t object - */ -typedef struct private_ike_sa_s private_ike_sa_t; - -struct private_ike_sa_s { - - /** - * Public part of a ike_sa_t object - */ - 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 (*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); - status_t (*transto_ike_sa_init_responded) (private_ike_sa_t *this, message_t *message); - status_t (*transto_ike_auth_requested) (private_ike_sa_t *this, message_t *message); - - /* Private values */ - /** - * Identifier for the current IKE_SA - */ - ike_sa_id_t *ike_sa_id; - - /** - * Linked List containing the child sa's of the current IKE_SA - */ - linked_list_t *child_sas; - - /** - * Current state of the IKE_SA - */ - ike_sa_state_t state; - - /** - * this SA's source for random data - */ - randomizer_t *randomizer; - - /** - * contains the last responded message - * - */ - message_t *last_responded_message; - - /** - * contains the last requested message - * - */ - message_t *last_requested_message; - - /** - * Informations of this host - */ - struct { - host_t *host; - } me; - - /** - * Informations of the other host - */ - struct { - host_t *host; - } other; - - - struct { - /** - * Diffie Hellman object used to compute shared secret - */ - diffie_hellman_t *diffie_hellman; - - /** - * Diffie Hellman group number - */ - u_int16_t dh_group_number; - - /** - * Priority used get matching dh_group number - */ - u_int16_t dh_group_priority; - - /** - * selected proposals - */ - linked_list_t *proposals; - - /** - * Sent nonce value - */ - chunk_t sent_nonce; - - /** - * received nonce value - */ - chunk_t received_nonce; - } ike_sa_init_data; - - - /** - * next message id to receive - */ - u_int32_t message_id_in; - - /** - * next message id to send - */ - u_int32_t message_id_out; - - /** - * a logger for this IKE_SA - */ - logger_t *logger; -}; - -/** - * @brief implements function process_message of private_ike_sa_t - */ -static status_t process_message (private_ike_sa_t *this, message_t *message) +static status_t process_message (protected_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 - */ + bool is_request; + status_t status; + state_t *new_state; + + /* we must process each request or response from remote host */ /* 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,exchange_type)); + this->logger->log(this->logger, CONTROL|MORE, "Process %s message of exchange type %s",(is_request) ? "REQUEST" : "RESPONSE",mapping_find(exchange_type_m,exchange_type)); message_id = message->get_message_id(message); @@ -281,71 +93,19 @@ static status_t process_message (private_ike_sa_t *this, message_t *message) } } - /* Now, the exchange type is checked and the appropriate transition handler is called*/ - switch (message->get_exchange_type(message)) + /* now the message is processed by the current state object */ + status = this->current_state->process_message(this->current_state,message,&new_state); + if (status == SUCCESS) { - case IKE_SA_INIT: - { - - if (message->get_request(message)) { - if (this->state == NO_STATE) - { - /* state transission NO_STATE => IKE_SA_INIT_RESPONDED */ - return this->transto_ike_sa_init_responded(this, message); - } - } - else - { - if (this->state == IKE_SA_INIT_REQUESTED) - { - /* state transission IKE_SA_INIT_REQUESTED => IKE_AUTH_REQUESTED*/ - return this->transto_ike_auth_requested(this, message); - } - } - - this->logger->log(this->logger, ERROR | MORE, "Message in current state %s not supported",mapping_find(ike_sa_state_m,this->state)); - - break; - } - case IKE_AUTH: - { - 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: - { - 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; - } - default: - { - this->logger->log(this->logger, ERROR, "processing %s-message not supported.", - mapping_find(exchange_type_m,message->get_exchange_type(message))); - return NOT_SUPPORTED; - } + this->current_state = new_state; } - 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; + return status; } /** - * @brief Implements function build_message of private_ike_sa_t. + * @brief Implements function build_message of protected_ike_sa_t. */ -static status_t build_message(private_ike_sa_t *this, exchange_type_t type, bool request, message_t **message) +static status_t build_message(protected_ike_sa_t *this, exchange_type_t type, bool request, message_t **message) { status_t status; message_t *new_message; @@ -397,810 +157,47 @@ static status_t build_message(private_ike_sa_t *this, exchange_type_t type, bool } /** - * @brief Implements function transto_ike_sa_init_requested of private_ike_sa_t. + * @brief implements function process_configuration of protected_ike_sa_t */ -static status_t transto_ike_sa_init_requested(private_ike_sa_t *this, char *name) +static status_t initialize_connection(protected_ike_sa_t *this, char *name) { - message_t *message; - payload_t *payload; - packet_t *packet; + /* work is done in state object of type INITIATOR_INIT */ + initiator_init_t *current_state; status_t status; - linked_list_iterator_t *proposal_iterator; + state_t *new_state; - 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; - } - - if (this->ike_sa_init_data.proposals->get_count(this->ike_sa_init_data.proposals) > 0) + if (this->current_state->get_state(this->current_state) != INITIATOR_INIT) { - this->logger->log(this->logger, ERROR, "Proposals allready existing!"); - return FAILED; - } - - status = this->ike_sa_init_data.proposals->create_iterator(this->ike_sa_init_data.proposals, &proposal_iterator, FALSE); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Fatal error: Could not create iterator on list for proposals"); - return status; - } - - status = global_configuration_manager->get_proposals_for_host(global_configuration_manager, this->other.host, proposal_iterator); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR | MORE, "Could not retrieve Proposals for %s",name); - return status; - } - /* not needed anymore */ - proposal_iterator->destroy(proposal_iterator); - - if (this->ike_sa_init_data.diffie_hellman != NULL) - { - 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) + + current_state = (initiator_init_t *) this->current_state; + + status = current_state->initiate_connection(current_state,name,&new_state); + + if (status == SUCCESS) { - this->logger->log(this->logger, ERROR, "Object of type diffie_hellman_t could not be created!"); - return FAILED; + this->current_state = new_state; } - - if (this->ike_sa_init_data.sent_nonce.ptr != NULL) - { - this->logger->log(this->logger, ERROR, "Nonce for IKE_SA_INIT phase already existing!"); - return FAILED; - } - - if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer, NONCE_SIZE, &(this->ike_sa_init_data.sent_nonce)) != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not create nonce!"); - return OUT_OF_RES; - } - - - /* going to build message */ - status = this->build_message(this, IKE_SA_INIT, TRUE, &message); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not build message"); - return status; - } - - /* build SA payload */ - status = this->build_sa_payload(this, (sa_payload_t**)&payload); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not build SA payload"); - message->destroy(message); - return status; - } - - 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); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not build KE payload"); - message->destroy(message); - return status; - } - - 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); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not build NONCE payload"); - message->destroy(message); - return status; - } - - 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; - } - - /* generate packet */ - 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, "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) - { - this->logger->log(this->logger, ERROR, "Could not add packet to send queue"); - message->destroy(message); - return status; - } - - 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); - } - - this->last_requested_message = message; - - /* message counter can now be increased */ - this->message_id_out++; - - /* state 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; -} - -static status_t transto_ike_sa_init_responded(private_ike_sa_t *this, message_t *request) -{ - status_t status; - linked_list_iterator_t *payloads; - message_t *response; - host_t *source, *destination; - payload_t *payload; - packet_t *packet; - - /* this is the first message we process, so copy host infos */ - request->get_source(request, &source); - request->get_destination(request, &destination); - /* we need to clone them, since we destroy the message later */ - destination->clone(destination, &(this->me.host)); - source->clone(source, &(this->other.host)); - - /* parse incoming message */ - status = request->parse_body(request); - if (status != SUCCESS) - { - 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. We can be sure, the message contains only accepted payloads! */ - status = request->get_payload_iterator(request, &payloads); - if (status != SUCCESS) - { - 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 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; - - 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; - } - - /* get the list of suggested proposals */ - 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; - } - - /* now let the configuration-manager select a subset of the proposals */ - status = global_configuration_manager->select_proposals_for_host(global_configuration_manager, - 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); - - this->logger->log(this->logger, CONTROL | MORE, "SA Payload processed"); - /* 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_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 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; - } - - if (this->ike_sa_init_data.diffie_hellman != NULL) - { - this->logger->log(this->logger, CONTROL | MORE, "Going to destroy allready existing diffie_hellman object"); - this->ike_sa_init_data.diffie_hellman->destroy(this->ike_sa_init_data.diffie_hellman); - } - this->ike_sa_init_data.diffie_hellman = dh; - - this->logger->log(this->logger, CONTROL | MORE, "KE Payload processed"); - break; - } - case NONCE: - { - 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); - this->ike_sa_init_data.received_nonce.len = nonce.len; - if (this->ike_sa_init_data.received_nonce.ptr == NULL) - { - payloads->destroy(payloads); - this->create_delete_job(this); - return OUT_OF_RES; - } - - this->logger->log(this->logger, CONTROL | MORE, "Nonce Payload processed"); - break; - } - default: - { - this->logger->log(this->logger, ERROR | MORE, "Payload type not supported!"); - payloads->destroy(payloads); - this->create_delete_job(this); - return OUT_OF_RES; - } - - } - - } - /* iterator can be destroyed */ - payloads->destroy(payloads); - - this->logger->log(this->logger, CONTROL | MORE, "Request successfully handled. Going to create reply."); - - - if (this->ike_sa_init_data.sent_nonce.ptr != NULL) - { - this->logger->log(this->logger, ERROR, "Nonce for IKE_SA_INIT phase already existing!"); - return FAILED; - } - - this->logger->log(this->logger, CONTROL | MOST, "Going to create nonce."); - if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer, NONCE_SIZE, &(this->ike_sa_init_data.sent_nonce)) != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not create nonce!"); - return OUT_OF_RES; - } - - - /* 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; - } - - /* build SA payload */ - status = this->build_sa_payload(this, (sa_payload_t**)&payload); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not build SA payload"); - this->create_delete_job(this); - response->destroy(response); - return status; - } - - this ->logger->log(this->logger, CONTROL|MOST, "add SA payload to message"); - status = response->add_payload(response, payload); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not add SA payload to message"); - this->create_delete_job(this); - response->destroy(response); - return status; - } - - /* build KE payload */ - status = this->build_ke_payload(this,(ke_payload_t **) &payload); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not build KE payload"); - this->create_delete_job(this); - response->destroy(response); - return status; - } - - this ->logger->log(this->logger, CONTROL|MOST, "add KE payload to message"); - status = response->add_payload(response, payload); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not add KE payload to message"); - this->create_delete_job(this); - response->destroy(response); - return status; - } - - /* build Nonce payload */ - status = this->build_nonce_payload(this, (nonce_payload_t**)&payload); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not build NONCE payload"); - this->create_delete_job(this); - response->destroy(response); - return status; - } - - this ->logger->log(this->logger, CONTROL|MOST, "add nonce payload to message"); - status = response->add_payload(response, payload); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not add nonce payload to message"); - this->create_delete_job(this); - response->destroy(response); - return status; - } - - /* generate packet */ - this ->logger->log(this->logger, CONTROL|MOST, "generate packet from message"); - status = response->generate(response, &packet); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Fatal error: could not generate packet from message"); - this->create_delete_job(this); - response->destroy(response); - 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) - { - this->logger->log(this->logger, ERROR, "Could not add packet to send queue"); - this->create_delete_job(this); - response->destroy(response); - return status; - } - - if ( this->last_responded_message != NULL) - { - /* destroy message */ - this ->logger->log(this->logger, CONTROL|MOST, "Destroy stored last responded message"); - this->last_responded_message->destroy(this->last_responded_message); - } - - this->last_responded_message = response; - - /* state 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_RESPONDED; - - - return SUCCESS; -} - -static status_t transto_ike_auth_requested(private_ike_sa_t *this, message_t *response) -{ - status_t status; - linked_list_iterator_t *payloads; - - - /* parse incoming message */ - status = response->parse_body(response); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not parse body"); - return status; - } - /* iterate over incoming payloads */ - status = response->get_payload_iterator(response, &payloads); - if (status != SUCCESS) - { - response->destroy(response); - return status; - } - while (payloads->has_next(payloads)) - { - payload_t *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))); - 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) { -// this->ike_sa_init_data.proposals = linked_list_create(); -// } -// else -// { -// /** @todo destroy list contents */ -// } -// if (this->ike_sa_init_data.proposals == NULL) -// { -// payloads->destroy(payloads); -// 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) -// { -// payloads->destroy(payloads); -// return status; -// } -// -// /* get the list of suggested proposals */ -// status = sa_payload->create_proposal_substructure_iterator(sa_payload, &suggested_proposals, TRUE); -// if (status != SUCCESS) -// { -// accepted_proposals->destroy(accepted_proposals); -// payloads->destroy(payloads); -// return status; -// } -// -// /* now let the configuration-manager select a subset of the proposals */ -// status = global_configuration_manager->select_proposals_for_host(global_configuration_manager, -// this->other.host, suggested_proposals, accepted_proposals); -// if (status != SUCCESS) -// { -// suggested_proposals->destroy(suggested_proposals); -// accepted_proposals->destroy(accepted_proposals); -// payloads->destroy(payloads); -// return status; -// } -// -// suggested_proposals->destroy(suggested_proposals); -// accepted_proposals->destroy(accepted_proposals); -// -// /* ok, we have what we need for sa_payload */ -// break; -// } - case KEY_EXCHANGE: - { - ke_payload_t *ke_payload = (ke_payload_t*)payload; - diffie_hellman_t *dh; - chunk_t shared_secret; - - dh = this->ike_sa_init_data.diffie_hellman; - - - status = dh->set_other_public_value(dh, ke_payload->get_key_exchange_data(ke_payload)); - if (status != SUCCESS) - { - dh->destroy(dh); - payloads->destroy(payloads); - return OUT_OF_RES; - } - - status = dh->get_shared_secret(dh, &shared_secret); - - this->logger->log_chunk(this->logger, RAW, "Shared secret", &shared_secret); - - break; - } - case NONCE: - { - nonce_payload_t *nonce_payload = (nonce_payload_t*)payload; - chunk_t nonce; - - 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); - this->ike_sa_init_data.received_nonce.len = nonce.len; - if (this->ike_sa_init_data.received_nonce.ptr == NULL) - { - payloads->destroy(payloads); - return OUT_OF_RES; - } - break; - } - default: - { - /** @todo handle */ - } - - } - - } - payloads->destroy(payloads); - - printf("done.\n"); - - /* set up the reply */ - status = this->build_message(this, IKE_SA_INIT, FALSE, &response); - if (status != SUCCESS) + else { this->create_delete_job(this); - return status; } - - response->destroy(response); - - return SUCCESS; - - + return status; } /** - * @brief implements function process_configuration of private_ike_sa_t + * @brief implements function protected_ike_sa_t.get_id */ -static status_t initialize_connection(private_ike_sa_t *this, char *name) -{ - /* work is done in transto_ike_sa_init_requested */ - return (this->transto_ike_sa_init_requested(this,name)); -} - -/** - * @brief implements function private_ike_sa_t.get_id - */ -static ike_sa_id_t* get_id(private_ike_sa_t *this) +static ike_sa_id_t* get_id(protected_ike_sa_t *this) { return this->ike_sa_id; } /** - * implements private_ike_sa_t.build_sa_payload + * @brief implements function resend_last_reply of protected_ike_sa_t */ -static status_t build_sa_payload(private_ike_sa_t *this, sa_payload_t **payload) -{ - sa_payload_t* sa_payload; - linked_list_iterator_t *proposal_iterator; - status_t status; - - - /* SA payload takes proposals from this->ike_sa_init_data.proposals and writes them to the created sa_payload */ - - this->logger->log(this->logger, CONTROL|MORE, "building sa payload"); - - status = this->ike_sa_init_data.proposals->create_iterator(this->ike_sa_init_data.proposals, &proposal_iterator, FALSE); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Fatal error: Could not create iterator on list for proposals"); - return status; - } - - sa_payload = sa_payload_create(); - if (sa_payload == NULL) - { - this->logger->log(this->logger, ERROR, "Fatal error: Could not create SA payload object"); - return OUT_OF_RES; - } - - while (proposal_iterator->has_next(proposal_iterator)) - { - proposal_substructure_t *current_proposal; - proposal_substructure_t *current_proposal_clone; - status = proposal_iterator->current(proposal_iterator,(void **) ¤t_proposal); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not get current proposal needed to copy"); - sa_payload->destroy(sa_payload); - return status; - } - status = current_proposal->clone(current_proposal,¤t_proposal_clone); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not clone current proposal"); - sa_payload->destroy(sa_payload); - return status; - } - - status = sa_payload->add_proposal_substructure(sa_payload,current_proposal_clone); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not add cloned proposal to SA payload"); - sa_payload->destroy(sa_payload); - return status; - } - - } - - this->logger->log(this->logger, CONTROL|MORE, "sa payload buildet"); - - *payload = sa_payload; - - return SUCCESS; -} - -static status_t build_ke_payload(private_ike_sa_t *this, ke_payload_t **payload) -{ - ke_payload_t *ke_payload; - chunk_t key_data; - status_t status; - - this->logger->log(this->logger, CONTROL|MORE, "building ke payload"); - - if (this->state != NO_STATE) - { - this->logger->log(this->logger, ERROR, "KE payload in state %s not supported",mapping_find(ike_sa_state_m,this->state)); - return FALSE; - } - - switch(this->ike_sa_id->is_initiator(this->ike_sa_id)) - { - case TRUE: - case FALSE: - { - this ->logger->log(this->logger, CONTROL|MORE, "get public dh value to send in ke payload"); - status = this->ike_sa_init_data.diffie_hellman->get_my_public_value(this->ike_sa_init_data.diffie_hellman,&key_data); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not get my DH public value"); - return status; - } - - ke_payload = ke_payload_create(); - if (ke_payload == NULL) - { - this->logger->log(this->logger, ERROR, "Could not create KE payload"); - allocator_free_chunk(key_data); - return OUT_OF_RES; - } - ke_payload->set_dh_group_number(ke_payload, MODP_1024_BIT); - if (ke_payload->set_key_exchange_data(ke_payload, key_data) != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not set key exchange data of KE payload"); - ke_payload->destroy(ke_payload); - allocator_free_chunk(key_data); - return OUT_OF_RES; - } - allocator_free_chunk(key_data); - - *payload = ke_payload; - return SUCCESS; - } - } - - return FAILED; -} - -/** - * implements private_ike_sa_t.build_nonce_payload - */ -static status_t build_nonce_payload(private_ike_sa_t *this, nonce_payload_t **payload) -{ - nonce_payload_t *nonce_payload; - status_t status; - - this->logger->log(this->logger, CONTROL|MORE, "building nonce payload"); - - if (this->state != NO_STATE) - { - this->logger->log(this->logger, ERROR, "Nonce payload in state %s not supported",mapping_find(ike_sa_state_m,this->state)); - return FALSE; - } - - nonce_payload = nonce_payload_create(); - if (nonce_payload == NULL) - { - this->logger->log(this->logger, ERROR, "Fatal error: could not create nonce payload object"); - return OUT_OF_RES; - } - - status = nonce_payload->set_nonce(nonce_payload, this->ike_sa_init_data.sent_nonce); - - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Fatal error: could not set nonce data of payload"); - nonce_payload->destroy(nonce_payload); - return status; - } - - *payload = nonce_payload; - - return SUCCESS; -} - -/** - * @brief implements function resend_last_reply of private_ike_sa_t - */ -status_t resend_last_reply (private_ike_sa_t *this) +status_t resend_last_reply (protected_ike_sa_t *this) { packet_t *packet; status_t status; @@ -1222,7 +219,7 @@ status_t resend_last_reply (private_ike_sa_t *this) return SUCCESS; } -status_t create_delete_job (private_ike_sa_t *this) +status_t create_delete_job (protected_ike_sa_t *this) { job_t *delete_job; status_t status; @@ -1247,13 +244,13 @@ status_t create_delete_job (private_ike_sa_t *this) } /** - * @brief implements function destroy of private_ike_sa_t + * @brief implements function destroy of protected_ike_sa_t */ -static status_t destroy (private_ike_sa_t *this) +static status_t destroy (protected_ike_sa_t *this) { this->logger->log(this->logger, CONTROL | MORE, "Going to destroy IKE_SA"); - + /* destroy child sa's */ this->logger->log(this->logger, CONTROL | MOST, "Destroy all child_sa's"); while (this->child_sas->get_count(this->child_sas) > 0) @@ -1285,56 +282,28 @@ static status_t destroy (private_ike_sa_t *this) this->last_responded_message->destroy(this->last_responded_message); } - /* destroy stored proposal */ - 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) - { - this->logger->log(this->logger, CONTROL | MOST, "Destroy diffie hellman object"); - this->ike_sa_init_data.diffie_hellman->destroy(this->ike_sa_init_data.diffie_hellman); - } - if (this->ike_sa_init_data.sent_nonce.ptr != NULL) - { - this->logger->log(this->logger, CONTROL | MOST, "Destroy sent nonce data"); - allocator_free_chunk(this->ike_sa_init_data.sent_nonce); - } - if (this->ike_sa_init_data.received_nonce.ptr != NULL) - { - this->logger->log(this->logger, CONTROL | MOST, "Destroy received nonce data"); - 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); +// 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 current state object"); +// this->current_state->destroy(this->current_state); +// +// 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; } @@ -1343,7 +312,7 @@ static status_t destroy (private_ike_sa_t *this) */ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) { - private_ike_sa_t *this = allocator_alloc_thing(private_ike_sa_t); + protected_ike_sa_t *this = allocator_alloc_thing(protected_ike_sa_t); if (this == NULL) { return NULL; @@ -1356,17 +325,10 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.destroy = (status_t(*)(ike_sa_t*))destroy; /* private functions */ - this->build_sa_payload = build_sa_payload; - this->build_nonce_payload = build_nonce_payload; - this->build_ke_payload = build_ke_payload; this->build_message = build_message; - 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); if (this->logger == NULL) @@ -1402,32 +364,22 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->me.host = NULL; this->other.host = NULL; - this->ike_sa_init_data.diffie_hellman = NULL; - this->ike_sa_init_data.dh_group_number = 0; - /* 1 means highest priority */ - this->ike_sa_init_data.dh_group_priority = 1; - this->ike_sa_init_data.sent_nonce.len = 0; - this->ike_sa_init_data.sent_nonce.ptr = NULL; - this->ike_sa_init_data.received_nonce.len = 0; - this->ike_sa_init_data.received_nonce.ptr = NULL; - this->ike_sa_init_data.proposals = linked_list_create(); - if (this->ike_sa_init_data.proposals == NULL) - { - this->logger->log(this->logger, ERROR, "Fatal error: Could not create list for child_sa's"); - this->child_sas->destroy(this->child_sas); - this->ike_sa_id->destroy(this->ike_sa_id); - this->randomizer->destroy(this->randomizer); - global_logger_manager->destroy_logger(global_logger_manager,this->logger); - allocator_free(this); - } this->last_requested_message = NULL; this->last_responded_message = NULL; this->message_id_out = 0; this->message_id_in = 0; - /* at creation time, IKE_SA isn't in a specific state */ - this->state = NO_STATE; + /* at creation time, IKE_SA is in a initiator state */ + if (ike_sa_id->is_initiator(ike_sa_id)) + { + this->current_state = (state_t *) initiator_init_create(this); + } + else + { + this->current_state = (state_t *) responder_init_create(this); + } + return (&this->public); } diff --git a/Source/charon/ike_sa.h b/Source/charon/ike_sa.h index 4457f7b49..fe909255d 100644 --- a/Source/charon/ike_sa.h +++ b/Source/charon/ike_sa.h @@ -27,6 +27,16 @@ #include "types.h" #include "message.h" #include "ike_sa_id.h" +#include "utils/logger.h" +#include "utils/randomizer.h" +#include "states/state.h" + + + +/** + * Nonce size in bytes of all sent nonces + */ +#define NONCE_SIZE 16 /** * @brief This class is used to represent an IKE_SA @@ -65,6 +75,147 @@ struct ike_sa_s { status_t (*destroy) (ike_sa_t *this); }; +/** + * Protected data of an ike_sa_t object + */ +typedef struct protected_ike_sa_s protected_ike_sa_t; + +struct protected_ike_sa_s { + + /** + * Public part of a ike_sa_t object + */ + ike_sa_t public; + + /** + * Builds an empty IKEv2-Message and fills in default informations. + * + * Depending on the type of message (request or response), the message id is + * either message_id_out or message_id_in. + * + * Used in every state. + * + * @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) (protected_ike_sa_t *this, exchange_type_t type, bool request, message_t **message); + + /** + * Creates a job to delete the given IKE_SA + */ + status_t (*create_delete_job) (protected_ike_sa_t *this); + + /** + * Resends the last sent reply + */ + status_t (*resend_last_reply) (protected_ike_sa_t *this); + + + /* protected values */ + + /** + * Identifier for the current IKE_SA + */ + ike_sa_id_t *ike_sa_id; + + /** + * Linked List containing the child sa's of the current IKE_SA + */ + linked_list_t *child_sas; + + /** + * Current state of the IKE_SA + */ + state_t *current_state; + + /** + * this SA's source for random data + */ + randomizer_t *randomizer; + + /** + * contains the last responded message + * + */ + message_t *last_responded_message; + + /** + * contains the last requested message + * + */ + message_t *last_requested_message; + + /** + * Informations of this host + */ + struct { + host_t *host; + } me; + + /** + * Informations of the other host + */ + struct { + host_t *host; + } other; + + +// struct { +// /** +// * Diffie Hellman object used to compute shared secret +// */ +// diffie_hellman_t *diffie_hellman; +// +// /** +// * Diffie Hellman group number +// */ +// u_int16_t dh_group_number; +// +// /** +// * Priority used get matching dh_group number +// */ +// u_int16_t dh_group_priority; +// +// /** +// * selected proposals +// */ +// linked_list_t *proposals; +// +// /** +// * Sent nonce value +// */ +// chunk_t sent_nonce; +// +// /** +// * received nonce value +// */ +// chunk_t received_nonce; +// } ike_sa_init_data; + + + /** + * next message id to receive + */ + u_int32_t message_id_in; + + /** + * next message id to send + */ + u_int32_t message_id_out; + + /** + * a logger for this IKE_SA + */ + logger_t *logger; +}; + + + /** * Creates an ike_sa_t object with a specific ike_sa_id_t object * diff --git a/Source/charon/states/ike_auth_requested.c b/Source/charon/states/ike_auth_requested.c index cb6996aad..eb0e2b852 100644 --- a/Source/charon/states/ike_auth_requested.c +++ b/Source/charon/states/ike_auth_requested.c @@ -35,6 +35,11 @@ struct private_ike_auth_requested_s { */ ike_auth_requested_t public; + + /** + * Assigned IKE_SA + */ + protected_ike_sa_t *ike_sa; }; /** @@ -66,7 +71,7 @@ static status_t destroy(private_ike_auth_requested_t *this) /* * Described in header. */ -ike_auth_requested_t *ike_auth_requested_create() +ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa) { private_ike_auth_requested_t *this = allocator_alloc_thing(private_ike_auth_requested_t); @@ -80,5 +85,8 @@ ike_auth_requested_t *ike_auth_requested_create() this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state; this->public.state_interface.destroy = (status_t (*) (state_t *)) destroy; + /* private data */ + this->ike_sa = ike_sa; + return &(this->public); } diff --git a/Source/charon/states/ike_auth_requested.h b/Source/charon/states/ike_auth_requested.h index 7c6beb983..2cc20d721 100644 --- a/Source/charon/states/ike_auth_requested.h +++ b/Source/charon/states/ike_auth_requested.h @@ -24,6 +24,7 @@ #define IKE_AUTH_REQUESTED_H_ #include "state.h" +#include "../ike_sa.h" /** * @brief This class represents an IKE_SA, which has requested an IKE_AUTH. @@ -41,7 +42,9 @@ struct ike_auth_requested_s { /** * Constructor of class ike_auth_requested_t + * + * @param ike_sa assigned ike_sa object */ -ike_auth_requested_t *ike_auth_requested_create(); +ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa); #endif /*IKE_AUTH_REQUESTED_H_*/ diff --git a/Source/charon/states/ike_sa_established.c b/Source/charon/states/ike_sa_established.c index 3831a754d..1fc2f116e 100644 --- a/Source/charon/states/ike_sa_established.c +++ b/Source/charon/states/ike_sa_established.c @@ -35,6 +35,11 @@ struct private_ike_sa_established_s { */ ike_sa_established_t public; + /** + * Assigned IKE_SA + */ + protected_ike_sa_t *ike_sa; + }; /** @@ -66,7 +71,7 @@ static status_t destroy(private_ike_sa_established_t *this) /* * Described in header. */ -ike_sa_established_t *ike_sa_established_create() +ike_sa_established_t *ike_sa_established_create(protected_ike_sa_t *ike_sa) { private_ike_sa_established_t *this = allocator_alloc_thing(private_ike_sa_established_t); @@ -80,5 +85,8 @@ ike_sa_established_t *ike_sa_established_create() this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state; this->public.state_interface.destroy = (status_t (*) (state_t *)) destroy; + /* private data */ + this->ike_sa = ike_sa; + return &(this->public); } diff --git a/Source/charon/states/ike_sa_established.h b/Source/charon/states/ike_sa_established.h index 0f90fc0c1..55fc85a96 100644 --- a/Source/charon/states/ike_sa_established.h +++ b/Source/charon/states/ike_sa_established.h @@ -24,6 +24,7 @@ #define IKE_SA_ESTABLISHED_H_ #include "state.h" +#include "../ike_sa.h" /** * @brief This class represents an the state of an established @@ -42,7 +43,9 @@ struct ike_sa_established_s { /** * Constructor of class ike_sa_established_t + * + * @param ike_sa assigned ike_sa */ -ike_sa_established_t *ike_sa_established_create(); +ike_sa_established_t *ike_sa_established_create(protected_ike_sa_t *ike_sa); #endif /*IKE_SA_ESTABLISHED_H_*/ diff --git a/Source/charon/states/ike_sa_init_requested.c b/Source/charon/states/ike_sa_init_requested.c index e69de29bb..81a10043e 100644 --- a/Source/charon/states/ike_sa_init_requested.c +++ b/Source/charon/states/ike_sa_init_requested.c @@ -0,0 +1,254 @@ +/** + * @file ike_sa_init_requested.c + * + * @brief State of a IKE_SA after requesting an IKE_SA_INIT + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See . + * + * 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 GNU General Public License + * for more details. + */ + +#include "ike_sa_init_requested.h" + +#include "../utils/allocator.h" +#include "../transforms/diffie_hellman.h" +#include "../payloads/sa_payload.h" +#include "../payloads/ke_payload.h" +#include "../payloads/nonce_payload.h" + +/** + * Private data of a ike_sa_init_requested_t object. + * + */ +typedef struct private_ike_sa_init_requested_s private_ike_sa_init_requested_t; +struct private_ike_sa_init_requested_s { + /** + * methods of the state_t interface + */ + ike_sa_init_requested_t public; + + /** + * Assigned IKE_SA + */ + protected_ike_sa_t *ike_sa; + + /** + * Diffie Hellman object used to compute shared secret + */ + diffie_hellman_t *diffie_hellman; + /** + * Sent nonce value + */ + chunk_t sent_nonce; + + /** + * Received nonce + */ + chunk_t received_nonce; + + /** + * Logger used to log data + * + * Is logger of ike_sa! + */ + logger_t *logger; +}; + +/** + * Implements state_t.get_state + */ +static status_t process_message(private_ike_sa_init_requested_t *this, message_t *message, state_t **new_state) +{ + status_t status; + linked_list_iterator_t *payloads; + message_t *response; + + + /* parse incoming message */ + status = message->parse_body(message); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not parse body"); + return status; + } + /* iterate over incoming payloads */ + status = message->get_payload_iterator(message, &payloads); + if (status != SUCCESS) + { + return status; + } + while (payloads->has_next(payloads)) + { + payload_t *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))); + 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) { +// this->ike_sa_init_data.proposals = linked_list_create(); +// } +// else +// { +// /** @todo destroy list contents */ +// } +// if (this->ike_sa_init_data.proposals == NULL) +// { +// payloads->destroy(payloads); +// 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) +// { +// payloads->destroy(payloads); +// return status; +// } +// +// /* get the list of suggested proposals */ +// status = sa_payload->create_proposal_substructure_iterator(sa_payload, &suggested_proposals, TRUE); +// if (status != SUCCESS) +// { +// accepted_proposals->destroy(accepted_proposals); +// payloads->destroy(payloads); +// return status; +// } +// +// /* now let the configuration-manager select a subset of the proposals */ +// status = global_configuration_manager->select_proposals_for_host(global_configuration_manager, +// this->other.host, suggested_proposals, accepted_proposals); +// if (status != SUCCESS) +// { +// suggested_proposals->destroy(suggested_proposals); +// accepted_proposals->destroy(accepted_proposals); +// payloads->destroy(payloads); +// return status; +// } +// +// suggested_proposals->destroy(suggested_proposals); +// accepted_proposals->destroy(accepted_proposals); +// +// /* ok, we have what we need for sa_payload */ +// break; +// } + case KEY_EXCHANGE: + { + ke_payload_t *ke_payload = (ke_payload_t*)payload; + diffie_hellman_t *dh; + chunk_t shared_secret; + + dh = this->diffie_hellman; + + + status = dh->set_other_public_value(dh, ke_payload->get_key_exchange_data(ke_payload)); + if (status != SUCCESS) + { + dh->destroy(dh); + payloads->destroy(payloads); + return OUT_OF_RES; + } + + status = dh->get_shared_secret(dh, &shared_secret); + + this->logger->log_chunk(this->logger, RAW, "Shared secret", &shared_secret); + + break; + } + case NONCE: + { + nonce_payload_t *nonce_payload = (nonce_payload_t*)payload; + chunk_t nonce; + + nonce_payload->get_nonce(nonce_payload, &nonce); + /** @todo free if there is already one */ + this->received_nonce.ptr = allocator_clone_bytes(nonce.ptr, nonce.len); + this->received_nonce.len = nonce.len; + if (this->received_nonce.ptr == NULL) + { + payloads->destroy(payloads); + return OUT_OF_RES; + } + break; + } + default: + { + /** @todo handle */ + } + + } + + } + payloads->destroy(payloads); + + /* set up the reply */ + status = this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response); + if (status != SUCCESS) + { + return status; + } + + response->destroy(response); + + return SUCCESS; +} + +/** + * Implements state_t.get_state + */ +static ike_sa_state_t get_state(private_ike_sa_init_requested_t *this) +{ + return IKE_SA_INIT_REQUESTED; +} + +/** + * Implements state_t.get_state + */ +static status_t destroy(private_ike_sa_init_requested_t *this) +{ + allocator_free(this); + return SUCCESS; +} + +/* + * Described in header. + */ +ike_sa_init_requested_t *ike_sa_init_requested_create(protected_ike_sa_t *ike_sa, diffie_hellman_t *diffie_hellman, chunk_t sent_nonce) +{ + private_ike_sa_init_requested_t *this = allocator_alloc_thing(private_ike_sa_init_requested_t); + + if (this == NULL) + { + return NULL; + } + + /* interface functions */ + this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *,state_t **)) process_message; + this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state; + this->public.state_interface.destroy = (status_t (*) (state_t *)) destroy; + + /* private data */ + this->ike_sa = ike_sa; + this->received_nonce.ptr = NULL; + this->received_nonce.len = 0; + this->logger = this->ike_sa->logger; + this->diffie_hellman = diffie_hellman; + this->sent_nonce = sent_nonce; + + return &(this->public); +} diff --git a/Source/charon/states/ike_sa_init_requested.h b/Source/charon/states/ike_sa_init_requested.h index c25149675..03ec9f0cc 100644 --- a/Source/charon/states/ike_sa_init_requested.h +++ b/Source/charon/states/ike_sa_init_requested.h @@ -1,4 +1,55 @@ +/** + * @file ike_sa_init_requested.h + * + * @brief State of a IKE_SA after requesting an IKE_SA_INIT + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See . + * + * 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 GNU General Public License + * for more details. + */ + + #ifndef IKE_SA_INIT_REQUESTED_H_ #define IKE_SA_INIT_REQUESTED_H_ +#include "state.h" +#include "../types.h" +#include "../transforms/diffie_hellman.h" +#include "../ike_sa.h" + +/** + * @brief This class represents an IKE_SA state when requested an IKE_SA_INIT + * + */ +typedef struct ike_sa_init_requested_s ike_sa_init_requested_t; + +struct ike_sa_init_requested_s { + /** + * methods of the state_t interface + */ + state_t state_interface; + +}; + +/** + * Constructor of class ike_sa_init_responded_t + * + * @param ike_sa assigned ike_sa + * @param diffie_hellman diffie_hellman object use to retrieve shared secret + * @param sent_nonce Sent nonce value + */ +ike_sa_init_requested_t *ike_sa_init_requested_create(protected_ike_sa_t *ike_sa, diffie_hellman_t *diffie_hellman, chunk_t sent_nonce); + #endif /*IKE_SA_INIT_REQUESTED_H_*/ diff --git a/Source/charon/states/ike_sa_init_responded.c b/Source/charon/states/ike_sa_init_responded.c index e69de29bb..5123bad27 100644 --- a/Source/charon/states/ike_sa_init_responded.c +++ b/Source/charon/states/ike_sa_init_responded.c @@ -0,0 +1,91 @@ +/** + * @file ike_sa_init_responded.c + * + * @brief State of a IKE_SA after responding to an IKE_SA_INIT request + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See . + * + * 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 GNU General Public License + * for more details. + */ + +#include "ike_sa_init_responded.h" + +#include "../utils/allocator.h" + +/** + * Private data of a ike_sa_init_responded_t object. + * + */ +typedef struct private_ike_sa_init_responded_s private_ike_sa_init_responded_t; +struct private_ike_sa_init_responded_s { + /** + * methods of the state_t interface + */ + ike_sa_init_responded_t public; + + /** + * Assigned IKE_SA + */ + protected_ike_sa_t *ike_sa; +}; + +/** + * Implements state_t.get_state + */ +static status_t process_message(private_ike_sa_init_responded_t *this, message_t *message, state_t **new_state) +{ + *new_state = (state_t *) this; + return SUCCESS; +} + +/** + * Implements state_t.get_state + */ +static ike_sa_state_t get_state(private_ike_sa_init_responded_t *this) +{ + return IKE_SA_INIT_RESPONDED; +} + +/** + * Implements state_t.get_state + */ +static status_t destroy(private_ike_sa_init_responded_t *this) +{ + allocator_free(this); + return SUCCESS; +} + +/* + * Described in header. + */ +ike_sa_init_responded_t *ike_sa_init_responded_create(protected_ike_sa_t *ike_sa) +{ + private_ike_sa_init_responded_t *this = allocator_alloc_thing(private_ike_sa_init_responded_t); + + if (this == NULL) + { + return NULL; + } + + /* interface functions */ + this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *,state_t **)) process_message; + this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state; + this->public.state_interface.destroy = (status_t (*) (state_t *)) destroy; + + /* private data */ + this->ike_sa = ike_sa; + + return &(this->public); +} diff --git a/Source/charon/states/ike_sa_init_responded.h b/Source/charon/states/ike_sa_init_responded.h index 7de7501e9..92832ecee 100644 --- a/Source/charon/states/ike_sa_init_responded.h +++ b/Source/charon/states/ike_sa_init_responded.h @@ -1,4 +1,51 @@ +/** + * @file ike_sa_init_responded.h + * + * @brief State of a IKE_SA after responding to an IKE_SA_INIT request + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See . + * + * 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 GNU General Public License + * for more details. + */ + #ifndef IKE_SA_INIT_RESPONDED_H_ #define IKE_SA_INIT_RESPONDED_H_ +#include "state.h" + +#include "../ike_sa.h" + +/** + * @brief This class represents an IKE_SA state when responded to an IKE_SA_INIT request + * + */ +typedef struct ike_sa_init_responded_s ike_sa_init_responded_t; + +struct ike_sa_init_responded_s { + /** + * methods of the state_t interface + */ + state_t state_interface; + +}; + +/** + * Constructor of class ike_sa_init_responded_t + * + * @param ike_sa assigned IKE_SA + */ +ike_sa_init_responded_t *ike_sa_init_responded_create(protected_ike_sa_t *ike_sa); + #endif /*IKE_SA_INIT_RESPONDED_H_*/ diff --git a/Source/charon/states/initiator_init.c b/Source/charon/states/initiator_init.c index 7b13c4aa2..8fc6f4dd4 100644 --- a/Source/charon/states/initiator_init.c +++ b/Source/charon/states/initiator_init.c @@ -22,7 +22,16 @@ #include "initiator_init.h" + +#include "state.h" +#include "ike_sa_init_requested.h" +#include "../globals.h" #include "../utils/allocator.h" +#include "../transforms/diffie_hellman.h" +#include "../payloads/sa_payload.h" +#include "../payloads/ke_payload.h" +#include "../payloads/nonce_payload.h" + /** * Private data of a initiator_init_t object. @@ -35,10 +44,363 @@ struct private_initiator_init_s { */ initiator_init_t public; + /** + * Assigned IKE_SA + */ + protected_ike_sa_t *ike_sa; + + /** + * Diffie hellman object + */ + diffie_hellman_t *diffie_hellman; + + /** + * DH group number + */ + u_int16_t dh_group_number; + + /** + * DH group priority + */ + u_int16_t dh_group_priority; + + /** + * Sent nonce + */ + chunk_t sent_nonce; + + /** + * Proposals used to initiate connection + */ + linked_list_t *proposals; + + /** + * Logger used to log data + * + * Is logger of ike_sa! + */ + logger_t *logger; + + status_t (*build_sa_payload) (private_initiator_init_t *this, payload_t **payload); + status_t (*build_ke_payload) (private_initiator_init_t *this, payload_t **payload); + status_t (*build_nonce_payload) (private_initiator_init_t *this, payload_t **payload); + + status_t (*destroy_after_state_change) (private_initiator_init_t *this); }; static status_t initiate_connection (private_initiator_init_t *this, char *name, state_t **new_state) { + message_t *message; + payload_t *payload; + packet_t *packet; + status_t status; + linked_list_iterator_t *proposal_iterator; + ike_sa_init_requested_t *next_state; + + + this->logger->log(this->logger, CONTROL, "Initializing connection %s",name); + + status = global_configuration_manager->get_local_host(global_configuration_manager, name, &(this->ike_sa->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->ike_sa->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->dh_group_number), this->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; + } + + status = this->proposals->create_iterator(this->proposals, &proposal_iterator, FALSE); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Fatal error: Could not create iterator on list for proposals"); + return status; + } + + status = global_configuration_manager->get_proposals_for_host(global_configuration_manager, this->ike_sa->other.host, proposal_iterator); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR | MORE, "Could not retrieve Proposals for %s",name); + return status; + } + /* not needed anymore */ + proposal_iterator->destroy(proposal_iterator); + + this ->logger->log(this->logger, CONTROL|MOST, "create diffie hellman object"); + this->diffie_hellman = diffie_hellman_create(this->dh_group_number); + + if (this->diffie_hellman == NULL) + { + this->logger->log(this->logger, ERROR, "Object of type diffie_hellman_t could not be created!"); + return FAILED; + } + + + if (this->ike_sa->randomizer->allocate_pseudo_random_bytes(this->ike_sa->randomizer, NONCE_SIZE, &(this->sent_nonce)) != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not create nonce!"); + return OUT_OF_RES; + } + + + /* going to build message */ + status = this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, TRUE, &message); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not build message"); + return status; + } + + /* build SA payload */ + status = this->build_sa_payload(this, &payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not build SA payload"); + message->destroy(message); + return status; + } + + 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, &payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not build KE payload"); + message->destroy(message); + return status; + } + + 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, &payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not build NONCE payload"); + message->destroy(message); + return status; + } + + 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; + } + + /* generate packet */ + 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, "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) + { + this->logger->log(this->logger, ERROR, "Could not add packet to send queue"); + message->destroy(message); + return status; + } + + if ( this->ike_sa->last_requested_message != NULL) + { + /* destroy message */ + this ->logger->log(this->logger, CONTROL|MOST, "Destroy stored last requested message"); + this->ike_sa->last_requested_message->destroy(this->ike_sa->last_requested_message); + } + + this->ike_sa->last_requested_message = message; + + /* message counter can now be increased */ + this->ike_sa->message_id_out++; + + + /* state can now be changed */ + next_state = ike_sa_init_requested_create(this->ike_sa,this->diffie_hellman,this->sent_nonce); + + if (next_state == NULL) + { + this ->logger->log(this->logger, ERROR, "Fatal error: could not create next state object of type ike_sa_init_requested_t"); + return FAILED; + } + + /* state 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,INITIATOR_INIT),mapping_find(ike_sa_state_m,IKE_SA_INIT_REQUESTED) ); + + this->destroy_after_state_change(this); + + *new_state = (state_t *) next_state; + + return SUCCESS; +} + +/** + * implements private_initiator_init_t.build_sa_payload + */ +static status_t build_sa_payload(private_initiator_init_t *this, payload_t **payload) +{ + sa_payload_t* sa_payload; + linked_list_iterator_t *proposal_iterator; + status_t status; + + + /* SA payload takes proposals from this->ike_sa_init_data.proposals and writes them to the created sa_payload */ + + this->logger->log(this->logger, CONTROL|MORE, "building sa payload"); + + status = this->proposals->create_iterator(this->proposals, &proposal_iterator, FALSE); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Fatal error: Could not create iterator on list for proposals"); + return status; + } + + sa_payload = sa_payload_create(); + if (sa_payload == NULL) + { + this->logger->log(this->logger, ERROR, "Fatal error: Could not create SA payload object"); + return OUT_OF_RES; + } + + while (proposal_iterator->has_next(proposal_iterator)) + { + proposal_substructure_t *current_proposal; + proposal_substructure_t *current_proposal_clone; + status = proposal_iterator->current(proposal_iterator,(void **) ¤t_proposal); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not get current proposal needed to copy"); + sa_payload->destroy(sa_payload); + return status; + } + status = current_proposal->clone(current_proposal,¤t_proposal_clone); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not clone current proposal"); + sa_payload->destroy(sa_payload); + return status; + } + + status = sa_payload->add_proposal_substructure(sa_payload,current_proposal_clone); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not add cloned proposal to SA payload"); + sa_payload->destroy(sa_payload); + return status; + } + + } + + this->logger->log(this->logger, CONTROL|MORE, "sa payload builded"); + + *payload = (payload_t *) sa_payload; + + return SUCCESS; +} + +/** + * implements private_initiator_init_t.build_ke_payload + */ +static status_t build_ke_payload(private_initiator_init_t *this, payload_t **payload) +{ + ke_payload_t *ke_payload; + chunk_t key_data; + status_t status; + + this->logger->log(this->logger, CONTROL|MORE, "building ke payload"); + + + this ->logger->log(this->logger, CONTROL|MORE, "get public dh value to send in ke payload"); + status = this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not get my DH public value"); + return status; + } + + ke_payload = ke_payload_create(); + if (ke_payload == NULL) + { + this->logger->log(this->logger, ERROR, "Could not create KE payload"); + allocator_free_chunk(key_data); + return OUT_OF_RES; + } + ke_payload->set_dh_group_number(ke_payload, MODP_1024_BIT); + if (ke_payload->set_key_exchange_data(ke_payload, key_data) != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not set key exchange data of KE payload"); + ke_payload->destroy(ke_payload); + allocator_free_chunk(key_data); + return OUT_OF_RES; + } + allocator_free_chunk(key_data); + + *payload = (payload_t *) ke_payload; + return SUCCESS; +} + +/** + * implements private_initiator_init_t.build_nonce_payload + */ +static status_t build_nonce_payload(private_initiator_init_t *this, payload_t **payload) +{ + nonce_payload_t *nonce_payload; + status_t status; + + this->logger->log(this->logger, CONTROL|MORE, "building nonce payload"); + + nonce_payload = nonce_payload_create(); + if (nonce_payload == NULL) + { + this->logger->log(this->logger, ERROR, "Fatal error: could not create nonce payload object"); + return OUT_OF_RES; + } + + status = nonce_payload->set_nonce(nonce_payload, this->sent_nonce); + + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Fatal error: could not set nonce data of payload"); + nonce_payload->destroy(nonce_payload); + return status; + } + + *payload = (payload_t *) nonce_payload; + return SUCCESS; } @@ -64,6 +426,41 @@ static ike_sa_state_t get_state(private_initiator_init_t *this) */ static status_t destroy(private_initiator_init_t *this) { + /* destroy stored proposal */ + this->logger->log(this->logger, CONTROL | MOST, "Destroy stored proposals"); + while (this->proposals->get_count(this->proposals) > 0) + { + proposal_substructure_t *current_proposal; + this->proposals->remove_first(this->proposals,(void **)¤t_proposal); + current_proposal->destroy(current_proposal); + } + this->proposals->destroy(this->proposals); + + /* destroy diffie hellman object */ + if (this->diffie_hellman != NULL) + { + this->logger->log(this->logger, CONTROL | MOST, "Destroy diffie_hellman_t object"); + this->diffie_hellman->destroy(this->diffie_hellman); + } + + allocator_free(this); + return SUCCESS; +} + +/** + * Implements private_initiator_init_t.destroy_after_state_change + */ +static status_t destroy_after_state_change (private_initiator_init_t *this) +{ + /* destroy stored proposal */ + this->logger->log(this->logger, CONTROL | MOST, "Destroy stored proposals"); + while (this->proposals->get_count(this->proposals) > 0) + { + proposal_substructure_t *current_proposal; + this->proposals->remove_first(this->proposals,(void **)¤t_proposal); + current_proposal->destroy(current_proposal); + } + this->proposals->destroy(this->proposals); allocator_free(this); return SUCCESS; } @@ -71,7 +468,7 @@ static status_t destroy(private_initiator_init_t *this) /* * Described in header. */ -initiator_init_t *initiator_init_create() +initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa) { private_initiator_init_t *this = allocator_alloc_thing(private_initiator_init_t); @@ -88,5 +485,24 @@ initiator_init_t *initiator_init_create() /* public functions */ this->public.initiate_connection = (status_t (*)(initiator_init_t *, char *, state_t **)) initiate_connection; + /* private functions */ + this->build_sa_payload = build_sa_payload; + this->build_ke_payload = build_ke_payload; + this->build_nonce_payload = build_nonce_payload; + this->destroy_after_state_change = destroy_after_state_change; + + /* private data */ + this->ike_sa = ike_sa; + this->logger = this->ike_sa->logger; + this->dh_group_priority = 1; + this->proposals = linked_list_create(); + this->sent_nonce.ptr = NULL; + this->sent_nonce.len = 0; + if (this->proposals == NULL) + { + allocator_free(this); + return NULL; + } + return &(this->public); } diff --git a/Source/charon/states/initiator_init.h b/Source/charon/states/initiator_init.h index e2ecdcafa..3458ad461 100644 --- a/Source/charon/states/initiator_init.h +++ b/Source/charon/states/initiator_init.h @@ -26,6 +26,8 @@ #include "state.h" +#include "../ike_sa.h" + /** * @brief This class represents an IKE_SA state when initializing * a connection as initiator @@ -52,8 +54,10 @@ struct initiator_init_s { /** * Constructor of class initiator_init_t + * + * @param ike_sa assigned IKE_SA */ -initiator_init_t *initiator_init_create(); +initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa); #endif /*INITIATOR_INIT_H_*/ diff --git a/Source/charon/states/responder_init.c b/Source/charon/states/responder_init.c index 0fad3ecdb..9fc744f2e 100644 --- a/Source/charon/states/responder_init.c +++ b/Source/charon/states/responder_init.c @@ -22,7 +22,12 @@ #include "responder_init.h" +#include "../globals.h" #include "../utils/allocator.h" +#include "../payloads/sa_payload.h" +#include "../payloads/ke_payload.h" +#include "../payloads/nonce_payload.h" +#include "../transforms/diffie_hellman.h" /** * Private data of a responder_init_t object. @@ -35,6 +40,51 @@ struct private_responder_init_s { */ responder_init_t public; + /** + * Assigned IKE_SA + */ + protected_ike_sa_t *ike_sa; + + /** + * Diffie Hellman object used to compute shared secret + */ + diffie_hellman_t *diffie_hellman; + + /** + * Diffie Hellman group number + */ + u_int16_t dh_group_number; + + /** + * Priority used get matching dh_group number + */ + u_int16_t dh_group_priority; + + /** + * Sent nonce value + */ + chunk_t sent_nonce; + + /** + * Received nonce value + */ + chunk_t received_nonce; + + /** + * Logger used to log data + * + * Is logger of ike_sa! + */ + logger_t *logger; + + /** + * Proposals used to initiate connection + */ + linked_list_t *proposals; + + status_t (*build_sa_payload) (private_responder_init_t *this, payload_t **payload); + status_t (*build_ke_payload) (private_responder_init_t *this, payload_t **payload); + status_t (*build_nonce_payload) (private_responder_init_t *this, payload_t **payload); }; /** @@ -42,16 +92,412 @@ struct private_responder_init_s { */ static status_t process_message(private_responder_init_t *this, message_t *message, state_t **new_state) { - *new_state = (state_t *) this; + linked_list_iterator_t *payloads; + host_t *source, *destination; + status_t status; + message_t *response; + payload_t *payload; + packet_t *packet; + + /* this is the first message we process, so copy host infos */ + message->get_source(message, &source); + message->get_destination(message, &destination); + + /* we need to clone them, since we destroy the message later */ + destination->clone(destination, &(this->ike_sa->me.host)); + source->clone(source, &(this->ike_sa->other.host)); + + /* parse incoming message */ + status = message->parse_body(message); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR | MORE, "Could not parse body of request message"); + return status; + } + + /* iterate over incoming payloads. We can be sure, the message contains only accepted payloads! */ + status = message->get_payload_iterator(message, &payloads); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Fatal error: Could not get payload interator"); + 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 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; + + status = this->proposals->create_iterator(this->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); + return status; + } + + /* get the list of suggested proposals */ + 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); + return status; + } + + /* now let the configuration-manager select a subset of the proposals */ + status = global_configuration_manager->select_proposals_for_host(global_configuration_manager, + this->ike_sa->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); + return status; + } + + /* iterators are not needed anymore */ + suggested_proposals->destroy(suggested_proposals); + accepted_proposals->destroy(accepted_proposals); + + this->logger->log(this->logger, CONTROL | MORE, "SA Payload processed"); + /* 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_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->ike_sa->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); + return status; + } + if (!allowed_group) + { + /** @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); + 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); + return OUT_OF_RES; + } + + this->diffie_hellman = dh; + + this->logger->log(this->logger, CONTROL | MORE, "KE Payload processed"); + break; + } + case NONCE: + { + 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->received_nonce.ptr = allocator_clone_bytes(nonce.ptr, nonce.len); + this->received_nonce.len = nonce.len; + if (this->received_nonce.ptr == NULL) + { + payloads->destroy(payloads); + return OUT_OF_RES; + } + + this->logger->log(this->logger, CONTROL | MORE, "Nonce Payload processed"); + break; + } + default: + { + this->logger->log(this->logger, ERROR | MORE, "Payload type not supported!"); + payloads->destroy(payloads); + return OUT_OF_RES; + } + + } + + } + /* iterator can be destroyed */ + payloads->destroy(payloads); + + this->logger->log(this->logger, CONTROL | MORE, "Request successfully handled. Going to create reply."); + + this->logger->log(this->logger, CONTROL | MOST, "Going to create nonce."); + if (this->ike_sa->randomizer->allocate_pseudo_random_bytes(this->ike_sa->randomizer, NONCE_SIZE, &(this->sent_nonce)) != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not create nonce!"); + return OUT_OF_RES; + } + + + /* set up the reply */ + status = this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not create empty message"); + return status; + } + + /* build SA payload */ + status = this->build_sa_payload(this, &payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not build SA payload"); + return status; + } + + this ->logger->log(this->logger, CONTROL|MOST, "add SA payload to message"); + status = response->add_payload(response, payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not add SA payload to message"); + return status; + } + + /* build KE payload */ + status = this->build_ke_payload(this,&payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not build KE payload"); + return status; + } + + this ->logger->log(this->logger, CONTROL|MOST, "add KE payload to message"); + status = response->add_payload(response, payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not add KE payload to message"); + return status; + } + + /* build Nonce payload */ + status = this->build_nonce_payload(this, &payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not build NONCE payload"); + return status; + } + + this ->logger->log(this->logger, CONTROL|MOST, "add nonce payload to message"); + status = response->add_payload(response, payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not add nonce payload to message"); + return status; + } + + /* generate packet */ + this ->logger->log(this->logger, CONTROL|MOST, "generate packet from message"); + status = response->generate(response, &packet); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Fatal error: could not generate packet from 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) + { + this->logger->log(this->logger, ERROR, "Could not add packet to send queue"); + return status; + } + + if ( this->ike_sa->last_responded_message != NULL) + { + /* destroy message */ + this ->logger->log(this->logger, CONTROL|MOST, "Destroy stored last responded message"); + this->ike_sa->last_responded_message->destroy(this->ike_sa->last_responded_message); + } + + this->ike_sa->last_responded_message = response; + + /* state 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) ); + + return SUCCESS; } +/** + * implements private_initiator_init_t.build_sa_payload + */ +static status_t build_sa_payload(private_responder_init_t *this, payload_t **payload) +{ + sa_payload_t* sa_payload; + linked_list_iterator_t *proposal_iterator; + status_t status; + + + /* SA payload takes proposals from this->ike_sa_init_data.proposals and writes them to the created sa_payload */ + + this->logger->log(this->logger, CONTROL|MORE, "building sa payload"); + + status = this->proposals->create_iterator(this->proposals, &proposal_iterator, FALSE); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Fatal error: Could not create iterator on list for proposals"); + return status; + } + + sa_payload = sa_payload_create(); + if (sa_payload == NULL) + { + this->logger->log(this->logger, ERROR, "Fatal error: Could not create SA payload object"); + return OUT_OF_RES; + } + + while (proposal_iterator->has_next(proposal_iterator)) + { + proposal_substructure_t *current_proposal; + proposal_substructure_t *current_proposal_clone; + status = proposal_iterator->current(proposal_iterator,(void **) ¤t_proposal); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not get current proposal needed to copy"); + sa_payload->destroy(sa_payload); + return status; + } + status = current_proposal->clone(current_proposal,¤t_proposal_clone); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not clone current proposal"); + sa_payload->destroy(sa_payload); + return status; + } + + status = sa_payload->add_proposal_substructure(sa_payload,current_proposal_clone); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not add cloned proposal to SA payload"); + sa_payload->destroy(sa_payload); + return status; + } + + } + + this->logger->log(this->logger, CONTROL|MORE, "sa payload builded"); + + *payload = (payload_t *) sa_payload; + + return SUCCESS; +} + +/** + * implements private_initiator_init_t.build_ke_payload + */ +static status_t build_ke_payload(private_responder_init_t *this, payload_t **payload) +{ + ke_payload_t *ke_payload; + chunk_t key_data; + status_t status; + + this->logger->log(this->logger, CONTROL|MORE, "building ke payload"); + + + this ->logger->log(this->logger, CONTROL|MORE, "get public dh value to send in ke payload"); + status = this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not get my DH public value"); + return status; + } + + ke_payload = ke_payload_create(); + if (ke_payload == NULL) + { + this->logger->log(this->logger, ERROR, "Could not create KE payload"); + allocator_free_chunk(key_data); + return OUT_OF_RES; + } + ke_payload->set_dh_group_number(ke_payload, MODP_1024_BIT); + if (ke_payload->set_key_exchange_data(ke_payload, key_data) != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not set key exchange data of KE payload"); + ke_payload->destroy(ke_payload); + allocator_free_chunk(key_data); + return OUT_OF_RES; + } + allocator_free_chunk(key_data); + + *payload = (payload_t *) ke_payload; + return SUCCESS; +} + +/** + * implements private_initiator_init_t.build_nonce_payload + */ +static status_t build_nonce_payload(private_responder_init_t *this, payload_t **payload) +{ + nonce_payload_t *nonce_payload; + status_t status; + + this->logger->log(this->logger, CONTROL|MORE, "building nonce payload"); + + nonce_payload = nonce_payload_create(); + if (nonce_payload == NULL) + { + this->logger->log(this->logger, ERROR, "Fatal error: could not create nonce payload object"); + return OUT_OF_RES; + } + + status = nonce_payload->set_nonce(nonce_payload, this->sent_nonce); + + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Fatal error: could not set nonce data of payload"); + nonce_payload->destroy(nonce_payload); + return status; + } + + *payload = (payload_t *) nonce_payload; + + return SUCCESS; +} + + /** * Implements state_t.get_state */ static ike_sa_state_t get_state(private_responder_init_t *this) { - return INITIATOR_INIT; + return RESPONDER_INIT; } /** @@ -59,6 +505,15 @@ static ike_sa_state_t get_state(private_responder_init_t *this) */ static status_t destroy(private_responder_init_t *this) { + /* destroy stored proposal */ + this->logger->log(this->logger, CONTROL | MOST, "Destroy stored proposals"); + while (this->proposals->get_count(this->proposals) > 0) + { + proposal_substructure_t *current_proposal; + this->proposals->remove_first(this->proposals,(void **)¤t_proposal); + current_proposal->destroy(current_proposal); + } + this->proposals->destroy(this->proposals); allocator_free(this); return SUCCESS; } @@ -66,7 +521,7 @@ static status_t destroy(private_responder_init_t *this) /* * Described in header. */ -responder_init_t *responder_init_create() +responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa) { private_responder_init_t *this = allocator_alloc_thing(private_responder_init_t); @@ -80,5 +535,24 @@ responder_init_t *responder_init_create() this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state; this->public.state_interface.destroy = (status_t (*) (state_t *)) destroy; + /* private functions */ + this->build_sa_payload = build_sa_payload; + this->build_ke_payload = build_ke_payload; + this->build_nonce_payload = build_nonce_payload; + + /* private data */ + this->ike_sa = ike_sa; + this->logger = this->ike_sa->logger; + this->sent_nonce.ptr = NULL; + this->sent_nonce.len = 0; + this->received_nonce.ptr = NULL; + this->received_nonce.len = 0; + this->proposals = linked_list_create(); + if (this->proposals == NULL) + { + allocator_free(this); + return NULL; + } + return &(this->public); } diff --git a/Source/charon/states/responder_init.h b/Source/charon/states/responder_init.h index bb7e48c90..4d2d2f3df 100644 --- a/Source/charon/states/responder_init.h +++ b/Source/charon/states/responder_init.h @@ -25,6 +25,8 @@ #include "state.h" +#include "../ike_sa.h" + /** * @brief This class represents an IKE_SA state when initializing * a connection as responder @@ -42,7 +44,9 @@ struct responder_init_s { /** * Constructor of class responder_init_t + * + * @param ike_sa assigned IKE_SA */ -responder_init_t *responder_init_create(); +responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa); #endif /*RESPONDER_INIT_H_*/ diff --git a/Source/charon/states/state.h b/Source/charon/states/state.h index a7c6826c5..cc66d1f0c 100644 --- a/Source/charon/states/state.h +++ b/Source/charon/states/state.h @@ -27,6 +27,8 @@ #include "../types.h" #include "../message.h" +extern mapping_t ike_sa_state_m[]; + /** * States in which a IKE_SA can actually be */ diff --git a/Source/charon/thread_pool.c b/Source/charon/thread_pool.c index 38f0ae1fa..63a084940 100644 --- a/Source/charon/thread_pool.c +++ b/Source/charon/thread_pool.c @@ -91,11 +91,11 @@ static void job_processing(private_thread_pool_t *this) { case INCOMING_PACKET: { - packet_t *packet; - message_t *message; - ike_sa_t *ike_sa; + packet_t *packet; + message_t *message; + ike_sa_t *ike_sa; ike_sa_id_t *ike_sa_id; - status_t status; + status_t status; incoming_packet_job_t *incoming_packet_job = (incoming_packet_job_t *)job; @@ -105,6 +105,7 @@ static void job_processing(private_thread_pool_t *this) mapping_find(job_type_m,job_type)); break; } + message = message_create_from_packet(packet); if (message == NULL) { @@ -173,6 +174,7 @@ static void job_processing(private_thread_pool_t *this) ike_sa_id->get_initiator_spi(ike_sa_id), ike_sa_id->get_responder_spi(ike_sa_id), ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder"); + ike_sa_id->destroy(ike_sa_id); status = global_ike_sa_manager->checkin(global_ike_sa_manager, ike_sa); if (status != SUCCESS) @@ -180,8 +182,6 @@ static void job_processing(private_thread_pool_t *this) this->worker_logger->log(this->worker_logger, ERROR, "checkin of IKE SA failed"); } message->destroy(message); - ike_sa_id->destroy(ike_sa_id); - break; } case INITIATE_IKE_SA: