From c0593835f40ba0a1d22968208084547524dc80d2 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 20 Jul 2006 14:57:49 +0000 Subject: [PATCH] reuse an existing IKE_SA to set up additional CHILD_SAs --- src/charon/Makefile.am | 4 +- .../queues/jobs/delete_half_open_ike_sa_job.c | 5 +- src/charon/queues/jobs/incoming_packet_job.c | 8 +- .../{initiate_ike_sa_job.c => initiate_job.c} | 48 ++-- .../{initiate_ike_sa_job.h => initiate_job.h} | 16 +- src/charon/queues/jobs/job.c | 2 +- src/charon/queues/jobs/job.h | 6 +- .../queues/jobs/retransmit_request_job.c | 5 +- src/charon/queues/jobs/send_dpd_job.c | 11 +- src/charon/queues/jobs/send_keepalive_job.c | 7 +- src/charon/sa/child_sa.c | 48 +++- src/charon/sa/ike_sa.c | 62 +++-- src/charon/sa/ike_sa_manager.c | 240 ++++++++++-------- src/charon/sa/ike_sa_manager.h | 35 +-- src/charon/sa/transactions/ike_auth.c | 2 +- src/charon/sa/transactions/ike_sa_init.c | 8 + src/charon/threads/stroke_interface.c | 64 ++--- src/libstrongswan/crypto/crypters/crypter.c | 28 +- src/libstrongswan/crypto/signers/signer.c | 12 +- 19 files changed, 346 insertions(+), 265 deletions(-) rename src/charon/queues/jobs/{initiate_ike_sa_job.c => initiate_job.c} (60%) rename src/charon/queues/jobs/{initiate_ike_sa_job.h => initiate_job.h} (77%) diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index a0f85417d..2a8735f53 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -38,10 +38,10 @@ encoding/payloads/vendor_id_payload.h encoding/payloads/proposal_substructure.c encoding/parser.h encoding/message.c encoding/generator.c encoding/message.h encoding/generator.h \ encoding/parser.c daemon.c daemon.h network/packet.c \ network/interfaces.c network/interfaces.h network/socket.c network/packet.h network/socket.h queues/jobs/job.h queues/jobs/job.c \ -queues/jobs/delete_established_ike_sa_job.c queues/jobs/retransmit_request_job.h queues/jobs/initiate_ike_sa_job.h \ +queues/jobs/delete_established_ike_sa_job.c queues/jobs/retransmit_request_job.h queues/jobs/initiate_job.h \ queues/jobs/incoming_packet_job.c queues/jobs/delete_half_open_ike_sa_job.c \ queues/jobs/delete_established_ike_sa_job.h queues/jobs/delete_half_open_ike_sa_job.h \ -queues/jobs/incoming_packet_job.h queues/jobs/retransmit_request_job.c queues/jobs/initiate_ike_sa_job.c \ +queues/jobs/incoming_packet_job.h queues/jobs/retransmit_request_job.c queues/jobs/initiate_job.c \ queues/jobs/send_keepalive_job.c queues/jobs/send_keepalive_job.h \ queues/jobs/rekey_child_sa_job.c queues/jobs/rekey_child_sa_job.h \ queues/jobs/delete_child_sa_job.c queues/jobs/delete_child_sa_job.h \ diff --git a/src/charon/queues/jobs/delete_half_open_ike_sa_job.c b/src/charon/queues/jobs/delete_half_open_ike_sa_job.c index 4e6fb08e1..7b79480bf 100644 --- a/src/charon/queues/jobs/delete_half_open_ike_sa_job.c +++ b/src/charon/queues/jobs/delete_half_open_ike_sa_job.c @@ -62,9 +62,10 @@ static status_t execute(private_delete_half_open_ike_sa_job_t *this) { ike_sa_t *ike_sa; - if (charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id, - &ike_sa) != SUCCESS) + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id); + if (ike_sa == NULL) { + /* hm, somebody was faster ;-) */ return DESTROY_ME; } diff --git a/src/charon/queues/jobs/incoming_packet_job.c b/src/charon/queues/jobs/incoming_packet_job.c index e24f625a1..d9661038e 100644 --- a/src/charon/queues/jobs/incoming_packet_job.c +++ b/src/charon/queues/jobs/incoming_packet_job.c @@ -142,8 +142,8 @@ static status_t execute(private_incoming_packet_job_t *this) ike_sa_id = message->get_ike_sa_id(message); ike_sa_id = ike_sa_id->clone(ike_sa_id); ike_sa_id->switch_initiator(ike_sa_id); - status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id, &ike_sa); - if (status != SUCCESS) + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id); + if (ike_sa == NULL) { this->logger->log(this->logger, ERROR, "received packet with SPIs %llx:%llx, but no such IKE_SA", @@ -158,11 +158,11 @@ static status_t execute(private_incoming_packet_job_t *this) status = ike_sa->process_message(ike_sa, message); if (status == DESTROY_ME) { - status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); } else { - status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } ike_sa_id->destroy(ike_sa_id); message->destroy(message); diff --git a/src/charon/queues/jobs/initiate_ike_sa_job.c b/src/charon/queues/jobs/initiate_job.c similarity index 60% rename from src/charon/queues/jobs/initiate_ike_sa_job.c rename to src/charon/queues/jobs/initiate_job.c index 38108cab8..43670485d 100644 --- a/src/charon/queues/jobs/initiate_ike_sa_job.c +++ b/src/charon/queues/jobs/initiate_job.c @@ -1,7 +1,7 @@ /** - * @file initiate_ike_sa_job.c + * @file initiate_job.c * - * @brief Implementation of initiate_ike_sa_job_t. + * @brief Implementation of initiate_job_t. * */ @@ -24,21 +24,21 @@ #include -#include "initiate_ike_sa_job.h" +#include "initiate_job.h" #include #include -typedef struct private_initiate_ike_sa_job_t private_initiate_ike_sa_job_t; +typedef struct private_initiate_job_t private_initiate_job_t; /** - * Private data of an initiate_ike_sa_job_t Object + * Private data of an initiate_job_t Object */ -struct private_initiate_ike_sa_job_t { +struct private_initiate_job_t { /** - * public initiate_ike_sa_job_t interface + * public initiate_job_t interface */ - initiate_ike_sa_job_t public; + initiate_job_t public; /** * associated connection to initiate @@ -57,37 +57,31 @@ struct private_initiate_ike_sa_job_t { }; /** - * Implements initiate_ike_sa_job_t.get_type. + * Implements initiate_job_t.get_type. */ -static job_type_t get_type(private_initiate_ike_sa_job_t *this) +static job_type_t get_type(private_initiate_job_t *this) { - return INITIATE_IKE_SA; + return INITIATE; } /** * Implementation of job_t.execute. */ -static status_t execute(private_initiate_ike_sa_job_t *this) +static status_t execute(private_initiate_job_t *this) { - /* Initiatie an IKE_SA: - * - is defined by a connection - * - create an empty IKE_SA via manager - * - call initiate() on this IKE_SA - */ ike_sa_t *ike_sa; - status_t status; - this->logger->log(this->logger, CONTROL|LEVEL2, "Creating and checking out IKE SA"); - charon->ike_sa_manager->create_and_checkout(charon->ike_sa_manager, &ike_sa); + this->logger->log(this->logger, CONTROL|LEVEL2, "getting an IKE SA"); + ike_sa = charon->ike_sa_manager->checkout_by_ids(charon->ike_sa_manager, + this->policy->get_my_id(this->policy), + this->policy->get_other_id(this->policy)); this->connection->get_ref(this->connection); this->policy->get_ref(this->policy); - status = ike_sa->initiate(ike_sa, this->connection, this->policy); - if (status != SUCCESS) + if (ike_sa->initiate(ike_sa, this->connection, this->policy) != SUCCESS) { this->logger->log(this->logger, ERROR, - "initiation returned %s, going to delete IKE_SA.", - mapping_find(status_m, status)); + "initiation failed, going to delete IKE_SA"); charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); return DESTROY_ME; } @@ -99,7 +93,7 @@ static status_t execute(private_initiate_ike_sa_job_t *this) /** * Implements job_t.destroy. */ -static void destroy(private_initiate_ike_sa_job_t *this) +static void destroy(private_initiate_job_t *this) { this->connection->destroy(this->connection); this->policy->destroy(this->policy); @@ -109,9 +103,9 @@ static void destroy(private_initiate_ike_sa_job_t *this) /* * Described in header */ -initiate_ike_sa_job_t *initiate_ike_sa_job_create(connection_t *connection, policy_t *policy) +initiate_job_t *initiate_job_create(connection_t *connection, policy_t *policy) { - private_initiate_ike_sa_job_t *this = malloc_thing(private_initiate_ike_sa_job_t); + private_initiate_job_t *this = malloc_thing(private_initiate_job_t); /* interface functions */ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; diff --git a/src/charon/queues/jobs/initiate_ike_sa_job.h b/src/charon/queues/jobs/initiate_job.h similarity index 77% rename from src/charon/queues/jobs/initiate_ike_sa_job.h rename to src/charon/queues/jobs/initiate_job.h index c119cf3fc..cb6acf39d 100644 --- a/src/charon/queues/jobs/initiate_ike_sa_job.h +++ b/src/charon/queues/jobs/initiate_job.h @@ -1,7 +1,7 @@ /** - * @file initiate_ike_sa_job.h + * @file initiate_job.h * - * @brief Interface of initiate_ike_sa_job_t. + * @brief Interface of initiate_job_t. */ /* @@ -29,7 +29,7 @@ #include -typedef struct initiate_ike_sa_job_t initiate_ike_sa_job_t; +typedef struct initiate_job_t initiate_job_t; /** * @brief Class representing an INITIATE_IKE_SA Job. @@ -37,11 +37,11 @@ typedef struct initiate_ike_sa_job_t initiate_ike_sa_job_t; * This job is created if an IKE_SA should be iniated. * * @b Constructors: - * - initiate_ike_sa_job_create() + * - initiate_job_create() * * @ingroup jobs */ -struct initiate_ike_sa_job_t { +struct initiate_job_t { /** * implements job_t interface */ @@ -51,13 +51,13 @@ struct initiate_ike_sa_job_t { /** * @brief Creates a job of type INITIATE_IKE_SA. * - * @param connection connection_t to initializes + * @param connection connection_t to initialize * @param policy policy to set up - * @return initiate_ike_sa_job_t object + * @return initiate_job_t object * * @ingroup jobs */ -initiate_ike_sa_job_t *initiate_ike_sa_job_create(connection_t *connection, +initiate_job_t *initiate_job_create(connection_t *connection, policy_t *policy); #endif /*INITIATE_IKE_SA_JOB_H_*/ diff --git a/src/charon/queues/jobs/job.c b/src/charon/queues/jobs/job.c index c870bafd3..1808a3faa 100644 --- a/src/charon/queues/jobs/job.c +++ b/src/charon/queues/jobs/job.c @@ -28,7 +28,7 @@ mapping_t job_type_m[] = { {INCOMING_PACKET, "INCOMING_PACKET"}, {RETRANSMIT_REQUEST, "RETRANSMIT_REQUEST"}, - {INITIATE_IKE_SA, "INITIATE_IKE_SA"}, + {INITIATE, "INITIATE"}, {DELETE_HALF_OPEN_IKE_SA, "DELETE_HALF_OPEN_IKE_SA"}, {DELETE_ESTABLISHED_IKE_SA, "DELETE_ESTABLISHED_IKE_SA"}, {SEND_KEEPALIVE, "SEND_KEEPALIVE"}, diff --git a/src/charon/queues/jobs/job.h b/src/charon/queues/jobs/job.h index 57fc8a8fb..6063a2108 100644 --- a/src/charon/queues/jobs/job.h +++ b/src/charon/queues/jobs/job.h @@ -51,11 +51,11 @@ enum job_type_t { RETRANSMIT_REQUEST, /** - * Establish an ike sa as initiator. + * Set up a CHILD_SA, optional with an IKE_SA. * - * Job is implemented in class initiate_ike_sa_job_t + * Job is implemented in class initiate_job_t */ - INITIATE_IKE_SA, + INITIATE, /** * Delete an ike sa which is still not established. diff --git a/src/charon/queues/jobs/retransmit_request_job.c b/src/charon/queues/jobs/retransmit_request_job.c index f3b75d2da..6a533ec7a 100644 --- a/src/charon/queues/jobs/retransmit_request_job.c +++ b/src/charon/queues/jobs/retransmit_request_job.c @@ -66,10 +66,9 @@ static job_type_t get_type(private_retransmit_request_job_t *this) static status_t execute(private_retransmit_request_job_t *this) { ike_sa_t *ike_sa; - status_t status; - status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id, &ike_sa); - if (status != SUCCESS) + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id); + if (ike_sa == NULL) { this->logger->log(this->logger, ERROR|LEVEL1, "IKE SA could not be checked out. Already deleted?"); diff --git a/src/charon/queues/jobs/send_dpd_job.c b/src/charon/queues/jobs/send_dpd_job.c index 56b1fac0d..b36593b88 100644 --- a/src/charon/queues/jobs/send_dpd_job.c +++ b/src/charon/queues/jobs/send_dpd_job.c @@ -65,16 +65,15 @@ static job_type_t get_type(private_send_dpd_job_t *this) static status_t execute(private_send_dpd_job_t *this) { ike_sa_t *ike_sa; - status_t status; - status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, - this->ike_sa_id, &ike_sa); - if (status != SUCCESS) + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->ike_sa_id); + if (ike_sa == NULL) { return DESTROY_ME; } - status = ike_sa->send_dpd(ike_sa); - if (status == DESTROY_ME) + + if (ike_sa->send_dpd(ike_sa) == DESTROY_ME) { charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); } diff --git a/src/charon/queues/jobs/send_keepalive_job.c b/src/charon/queues/jobs/send_keepalive_job.c index 6c7dceb3e..0a305faed 100644 --- a/src/charon/queues/jobs/send_keepalive_job.c +++ b/src/charon/queues/jobs/send_keepalive_job.c @@ -65,11 +65,10 @@ static job_type_t get_type(private_send_keepalive_job_t *this) static status_t execute(private_send_keepalive_job_t *this) { ike_sa_t *ike_sa; - status_t status; - status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, - this->ike_sa_id, &ike_sa); - if (status != SUCCESS) + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->ike_sa_id); + if (ike_sa == NULL) { return DESTROY_ME; } diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 38b4fa87a..580599362 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -110,6 +110,16 @@ struct private_child_sa_t { */ u_int32_t reqid; + /** + * encryption algorithm used for this SA + */ + algorithm_t encryption; + + /** + * integrity protection algorithm used for this SA + */ + algorithm_t integrity; + /** * time, on which SA was installed */ @@ -358,6 +368,8 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus enc_algo, int_algo, prf_plus, natt, mine); + this->encryption = *enc_algo; + this->integrity = *int_algo; this->install_time = time(NULL); return status; @@ -574,6 +586,8 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name) char use_in_str[12] = "unused"; char use_out_str[12] = "unused"; char rekey_str[12] = "disabled"; + char enc_str[32] = ""; + char int_str[32] = ""; u_int32_t use_in, use_out, use_fwd, now, rekeying; status_t status; @@ -604,10 +618,38 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name) snprintf(rekey_str, sizeof(rekey_str), "%ds", (int)rekeying); } + /* algorithms used */ + if (this->protocol == PROTO_ESP) + { + if (this->encryption.key_size) + { + snprintf(enc_str, sizeof(enc_str), "%s-%d,", + mapping_find(encryption_algorithm_m, this->encryption.algorithm), + this->encryption.key_size); + } + else + { + snprintf(enc_str, sizeof(enc_str), "%s,", + mapping_find(encryption_algorithm_m, this->encryption.algorithm)); + } + } + if (this->integrity.key_size) + { + snprintf(int_str, sizeof(int_str), "%s-%d", + mapping_find(integrity_algorithm_m, this->integrity.algorithm), + this->integrity.key_size); + } + else + { + snprintf(int_str, sizeof(int_str), "%s", + mapping_find(integrity_algorithm_m, this->integrity.algorithm)); + } + logger->log(logger, CONTROL|LEVEL1, - " \"%s\": using %s, SPIs (in/out): 0x%x/0x%x, reqid: %d", + " \"%s\": %s (%s%s), SPIs (in/out): 0x%x/0x%x, reqid: %d", name, this->protocol == PROTO_ESP ? "ESP" : "AH", + enc_str, int_str, htonl(this->me.spi), htonl(this->other.spi), this->reqid); logger->log(logger, CONTROL|LEVEL1, @@ -898,6 +940,10 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other, this->state = CHILD_CREATED; /* reuse old reqid if we are rekeying an existing CHILD_SA */ this->reqid = rekey ? rekey : ++reqid; + this->encryption.algorithm = ENCR_UNDEFINED; + this->encryption.key_size = 0; + this->integrity.algorithm = AUTH_UNDEFINED; + this->encryption.key_size = 0; this->policies = linked_list_create(); this->my_ts = linked_list_create(); this->other_ts = linked_list_create(); diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 569d8795e..bfffdad2f 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -782,23 +782,53 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) static status_t initiate(private_ike_sa_t *this, connection_t *connection, policy_t *policy) { - ike_sa_init_t *ike_sa_init; - - set_name(this, connection->get_name(connection)); - - /* apply hosts from connection */ - this->my_host = connection->get_my_host(connection); - this->my_host = this->my_host->clone(this->my_host); - this->other_host = connection->get_other_host(connection); - this->other_host = this->other_host->clone(this->other_host); - - this->message_id_out = 1; - ike_sa_init = ike_sa_init_create(&this->public); - ike_sa_init->set_config(ike_sa_init, connection, policy); - return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE); + switch (this->state) + { + case IKE_CREATED: + { + /* in state CREATED, we must do the ike_sa_init + * and ike_auth transactions. Along with these, + * a CHILD_SA with the supplied policy is set up. + */ + ike_sa_init_t *ike_sa_init; + + set_name(this, connection->get_name(connection)); + this->my_host = connection->get_my_host(connection); + this->my_host = this->my_host->clone(this->my_host); + this->other_host = connection->get_other_host(connection); + this->other_host = this->other_host->clone(this->other_host); + + this->message_id_out = 1; + ike_sa_init = ike_sa_init_create(&this->public); + ike_sa_init->set_config(ike_sa_init, connection, policy); + return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE); + } + case IKE_DELETING: + { + /* if we are in DELETING, we deny set up of a policy. */ + policy->destroy(policy); + connection->destroy(connection); + return FAILED; + } + case IKE_CONNECTING: + case IKE_ESTABLISHED: + { + /* if we are ESTABLISHED or CONNECTING,we queue the + * transaction to create the CHILD_SA. It gets processed + * when the IKE_SA is ready to do so. We don't need the + * connection, as the IKE_SA is already established/establishing. + */ + create_child_sa_t *create_child; + + connection->destroy(connection); + create_child = create_child_sa_create(&this->public); + create_child->set_policy(create_child, policy); + return queue_transaction(this, (transaction_t*)create_child, FALSE); + } + } + return FAILED; } - /** * Implementation of ike_sa_t.acquire. */ @@ -990,6 +1020,7 @@ static identification_t* get_my_id(private_ike_sa_t *this) */ static void set_my_id(private_ike_sa_t *this, identification_t *me) { + DESTROY_IF(this->my_id); this->my_id = me; } @@ -1006,6 +1037,7 @@ static identification_t* get_other_id(private_ike_sa_t *this) */ static void set_other_id(private_ike_sa_t *this, identification_t *other) { + DESTROY_IF(this->other_id); this->other_id = other; } diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index b0822acb7..c8e4d71da 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -333,6 +333,34 @@ static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *ent return status; } +/** + * Wait until no other thread is using an IKE_SA, return FALSE if entry not + * acquireable + */ +static bool wait_for_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *entry) +{ + if (entry->driveout_new_threads) + { + /* we are not allowed to get this */ + return FALSE; + } + while (entry->checked_out && !entry->driveout_waiting_threads) + { + /* so wait until we can get it for us. + * we register us as waiting. */ + entry->waiting_threads++; + pthread_cond_wait(&(entry->condvar), &(this->mutex)); + entry->waiting_threads--; + } + /* hm, a deletion request forbids us to get this SA, get next one */ + if (entry->driveout_waiting_threads) + { + /* we must signal here, others may be waiting on it, too */ + pthread_cond_signal(&(entry->condvar)); + return FALSE; + } + return TRUE; +} /** * Implementation of private_ike_sa_manager_t.get_next_spi. @@ -349,48 +377,92 @@ static u_int64_t get_next_spi(private_ike_sa_manager_t *this) /** * Implementation of of ike_sa_manager.create_and_checkout. */ -static void create_and_checkout(private_ike_sa_manager_t *this,ike_sa_t **ike_sa) +static ike_sa_t* checkout_by_ids(private_ike_sa_manager_t *this, + identification_t *my_id, + identification_t *other_id) { - u_int64_t initiator_spi; - ike_sa_entry_t *new_ike_sa_entry; - ike_sa_id_t *new_ike_sa_id; - - initiator_spi = this->get_next_spi(this); - new_ike_sa_id = ike_sa_id_create(0, 0, TRUE); - new_ike_sa_id->set_initiator_spi(new_ike_sa_id, initiator_spi); - - /* create entry */ - new_ike_sa_entry = ike_sa_entry_create(new_ike_sa_id); - this->logger->log(this->logger, CONTROL|LEVEL2, - "created IKE_SA %llx:%llx, role %s", - new_ike_sa_id->get_initiator_spi(new_ike_sa_id), - new_ike_sa_id->get_responder_spi(new_ike_sa_id), - new_ike_sa_id->is_initiator(new_ike_sa_id) ? "initiator" : "responder"); - new_ike_sa_id->destroy(new_ike_sa_id); - - /* each access is locked */ + iterator_t *iterator; + ike_sa_t *ike_sa = NULL; + pthread_mutex_lock(&(this->mutex)); - this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry); - - /* check ike_sa out */ - this->logger->log(this->logger, CONTROL|LEVEL1, - "new IKE_SA created and added to list of known IKE_SA's"); - new_ike_sa_entry->checked_out = TRUE; - *ike_sa = new_ike_sa_entry->ike_sa; - + iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE); + while (iterator->has_next(iterator)) + { + ike_sa_entry_t *entry; + identification_t *found_my_id, *found_other_id; + int wc; + + iterator->current(iterator, (void**)&entry); + if (!wait_for_entry(this, entry)) + { + continue; + } + + found_my_id = entry->ike_sa->get_my_id(entry->ike_sa); + found_other_id = entry->ike_sa->get_other_id(entry->ike_sa); + + if (!found_my_id || !found_other_id) + { + /* IKE_SA has no IDs yet, so we can't use it */ + continue; + } + + if (found_my_id->matches(found_my_id, my_id, &wc) && + found_other_id->matches(found_other_id, other_id, &wc)) + { + /* looks good, we take this one */ + this->logger->log(this->logger, CONTROL|LEVEL1, + "found an existing IKE_SA for IDs %s - %s", + my_id->get_string(my_id), other_id->get_string(other_id)); + entry->checked_out = TRUE; + ike_sa = entry->ike_sa; + } + } + iterator->destroy(iterator); + + if (!ike_sa) + { + u_int64_t initiator_spi; + ike_sa_entry_t *new_ike_sa_entry; + ike_sa_id_t *new_ike_sa_id; + + initiator_spi = this->get_next_spi(this); + new_ike_sa_id = ike_sa_id_create(0, 0, TRUE); + new_ike_sa_id->set_initiator_spi(new_ike_sa_id, initiator_spi); + + /* create entry */ + new_ike_sa_entry = ike_sa_entry_create(new_ike_sa_id); + this->logger->log(this->logger, CONTROL|LEVEL2, + "created IKE_SA %llx:%llx, role %s", + new_ike_sa_id->get_initiator_spi(new_ike_sa_id), + new_ike_sa_id->get_responder_spi(new_ike_sa_id), + new_ike_sa_id->is_initiator(new_ike_sa_id) ? "initiator" : "responder"); + new_ike_sa_id->destroy(new_ike_sa_id); + + this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry); + + /* check ike_sa out */ + this->logger->log(this->logger, CONTROL|LEVEL1, + "new IKE_SA created for IDs %s - %s", + my_id->get_string(my_id), other_id->get_string(other_id)); + new_ike_sa_entry->checked_out = TRUE; + ike_sa = new_ike_sa_entry->ike_sa; + } pthread_mutex_unlock(&(this->mutex)); + + return ike_sa; } /** * Implementation of of ike_sa_manager.checkout. */ -static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_t **ike_sa) +static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id) { bool responder_spi_set; bool initiator_spi_set; bool original_initiator; - status_t retval; + ike_sa_t *ike_sa = NULL; this->logger->log(this->logger, CONTROL|LEVEL2, "checkout IKE_SA %llx:%llx, role %s", @@ -418,56 +490,25 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, /* look for the entry */ if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) { - /* can we give this ike_sa out to new requesters?*/ - if (entry->driveout_new_threads) + if (wait_for_entry(this, entry)) { - this->logger->log(this->logger, CONTROL|LEVEL1, - "drive out new thread for existing IKE_SA"); - /* no we can't */ - retval = NOT_FOUND; + this->logger->log(this->logger, CONTROL|LEVEL2, + "IKE_SA successfully checked out"); + /* ok, this IKE_SA is finally ours */ + entry->checked_out = TRUE; + ike_sa = entry->ike_sa; } else { - /* is this IKE_SA already checked out ?? - * are we welcome to get this SA ? */ - while (entry->checked_out && !entry->driveout_waiting_threads) - { - /* so wait until we can get it for us. - * we register us as waiting. - */ - entry->waiting_threads++; - pthread_cond_wait(&(entry->condvar), &(this->mutex)); - entry->waiting_threads--; - } - - /* hm, a deletion request forbids us to get this SA, go home */ - if (entry->driveout_waiting_threads) - { - /* we must signal here, others are interested that we leave */ - pthread_cond_signal(&(entry->condvar)); - this->logger->log(this->logger, CONTROL|LEVEL1, - "drive out waiting thread for existing IKE_SA"); - retval = NOT_FOUND; - } - else - { - this->logger->log(this->logger, CONTROL|LEVEL2, - "IKE SA successfully checked out"); - /* ok, this IKE_SA is finally ours */ - entry->checked_out = TRUE; - *ike_sa = entry->ike_sa; - /* DON'T use return, we must unlock the mutex! */ - retval = SUCCESS; - } + this->logger->log(this->logger, CONTROL|LEVEL2, + "IKE_SA found, but not allowed to check it out"); } } else { this->logger->log(this->logger, ERROR|LEVEL1, - "IKE SA not stored in known IKE_SA list"); + "IKE_SA not stored in list"); /* looks like there is no such IKE_SA, better luck next time... */ - /* DON'T use return, we must unlock the mutex! */ - retval = NOT_FOUND; } } else if ((initiator_spi_set && !responder_spi_set) && (!original_initiator)) @@ -496,23 +537,18 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, /* check ike_sa out */ this->logger->log(this->logger, CONTROL|LEVEL1, - "IKE_SA added to list of known IKE_SA's"); + "IKE_SA added to list of known IKE_SAs"); new_ike_sa_entry->checked_out = TRUE; - *ike_sa = new_ike_sa_entry->ike_sa; - - retval = SUCCESS; + ike_sa = new_ike_sa_entry->ike_sa; } else { /* responder set, initiator not: here is something seriously wrong! */ - this->logger->log(this->logger, ERROR|LEVEL1, "invalid IKE_SA SPI's"); - /* DON'T use return, we must unlock the mutex! */ - retval = INVALID_ARG; + this->logger->log(this->logger, ERROR|LEVEL1, "invalid IKE_SA SPIs"); } pthread_mutex_unlock(&(this->mutex)); - /* OK, unlocked... */ - return retval; + return ike_sa; } /** @@ -533,34 +569,17 @@ static status_t checkout_by_child(private_ike_sa_manager_t *this, ike_sa_entry_t *entry; iterator->current(iterator, (void**)&entry); - if (entry->driveout_new_threads) + if (wait_for_entry(this, entry)) { - /* we are not allowed to get this, get next one */ - continue; - } - while (entry->checked_out && !entry->driveout_waiting_threads) - { - /* so wait until we can get it for us. - * we register us as waiting. */ - entry->waiting_threads++; - pthread_cond_wait(&(entry->condvar), &(this->mutex)); - entry->waiting_threads--; - } - /* hm, a deletion request forbids us to get this SA, get next one */ - if (entry->driveout_waiting_threads) - { - /* we must signal here, others may be waiting on it, too */ - pthread_cond_signal(&(entry->condvar)); - continue; - } - /* ok, access is exclusive for us, check for child */ - if (entry->ike_sa->get_child_sa(entry->ike_sa, protocol, spi, TRUE) != NULL) - { - /* match */ - entry->checked_out = TRUE; - *ike_sa = entry->ike_sa; - status = SUCCESS; - break; + /* ok, access is exclusive for us, check for child */ + if (entry->ike_sa->get_child_sa(entry->ike_sa, protocol, spi, TRUE) != NULL) + { + /* match */ + entry->checked_out = TRUE; + *ike_sa = entry->ike_sa; + status = SUCCESS; + break; + } } } iterator->destroy(iterator); @@ -638,9 +657,12 @@ static void log_status(private_ike_sa_manager_t* this, logger_t* logger, char* n while (iterator->has_next(iterator)) { ike_sa_entry_t *entry; - + iterator->current(iterator, (void**)&entry); - entry->ike_sa->log_status(entry->ike_sa, logger, name); + if (wait_for_entry(this, entry)) + { + entry->ike_sa->log_status(entry->ike_sa, logger, name); + } } iterator->destroy(iterator); @@ -891,8 +913,8 @@ ike_sa_manager_t *ike_sa_manager_create() /* assign public functions */ this->public.destroy = (void(*)(ike_sa_manager_t*))destroy; - this->public.create_and_checkout = (void(*)(ike_sa_manager_t*,ike_sa_t**))create_and_checkout; - this->public.checkout = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t*,ike_sa_t**))checkout; + this->public.checkout_by_ids = (ike_sa_t*(*)(ike_sa_manager_t*,identification_t*,identification_t*))checkout_by_ids; + this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout; this->public.checkout_by_child = (status_t(*)(ike_sa_manager_t*,protocol_id_t,u_int32_t,ike_sa_t**))checkout_by_child; this->public.get_ike_sa_list = (linked_list_t*(*)(ike_sa_manager_t*))get_ike_sa_list; this->public.get_ike_sa_list_by_name = (linked_list_t*(*)(ike_sa_manager_t*,const char*))get_ike_sa_list_by_name; diff --git a/src/charon/sa/ike_sa_manager.h b/src/charon/sa/ike_sa_manager.h index 4c40939f5..1c8dbad16 100644 --- a/src/charon/sa/ike_sa_manager.h +++ b/src/charon/sa/ike_sa_manager.h @@ -52,8 +52,8 @@ struct ike_sa_manager_t { /** * @brief Checkout an IKE_SA, create it when necesarry. * - * Checks out a SA by its ID. An SA will be created, when: - * - Responder SPI is not set (when received an IKE_SA_INIT from initiator) + * Checks out a SA by its ID. An SA will be created, when the responder + * SPI is not set (when received an IKE_SA_INIT from initiator). * Management of SPIs is the managers job, he will set it. * This function blocks until SA is available for checkout. * @@ -62,24 +62,27 @@ struct ike_sa_manager_t { * * @param this the manager object * @param[in/out] ike_sa_id the SA identifier, will be updated - * @param[out] ike_sa checked out SA * @returns - * - SUCCESS if checkout successful - * - NOT_FOUND when no such SA is available - * - CREATED if a new IKE_SA got created + * - checked out IKE_SA if found + * - NULL, if no such IKE_SA available */ - status_t (*checkout) (ike_sa_manager_t* this, ike_sa_id_t *sa_id, ike_sa_t **ike_sa); + ike_sa_t* (*checkout) (ike_sa_manager_t* this, ike_sa_id_t *sa_id); /** - * @brief Create and checkout an IKE_SA as original initator. - * - * Creates and checks out a SA as initiator. - * Management of SPIs is the managers job, he will set it. - * + * @brief Checkout an IKE_SA by two identifications. + * + * Allows the lookup of an IKE_SA by two user IDs. It returns the + * first found occurence, if there are multiple canddates. Supplied IDs + * may contain wildcards. If no IKE_SA is found, a new one is created. + * * @param this the manager object - * @param[out] ike_sa checked out SA + * @param my_id ID used by us + * @param other_id ID used by other + * @return checked out/created IKE_SA */ - void (*create_and_checkout) (ike_sa_manager_t* this,ike_sa_t **ike_sa); + ike_sa_t* (*checkout_by_ids) (ike_sa_manager_t* this, + identification_t *my_id, + identification_t *other_id); /** * @brief Check out an IKE_SA by protocol and SPI of one of its CHILD_SA. @@ -102,7 +105,7 @@ struct ike_sa_manager_t { /** * @brief Get a list of all IKE_SA SAs currently set up. * - * The resulting list with all IDs must be destroyd by + * The resulting list with all IDs must be destroyed by * the caller. There is no guarantee an ike_sa with the * corrensponding ID really exists, since it may be deleted * in the meantime by another thread. @@ -153,7 +156,7 @@ struct ike_sa_manager_t { * @brief Delete a SA, which was not checked out. * * If the state allows it, the IKE SA is destroyed immediately. If it is - * in the state ike_sa_established or further, a delete message + * in the state ESTABLSIHED, a delete message * is sent to the remote peer, which has to be acknowledged. * * @warning do not use this when the SA is already checked out, this will diff --git a/src/charon/sa/transactions/ike_auth.c b/src/charon/sa/transactions/ike_auth.c index 2bf12f754..f423665cf 100644 --- a/src/charon/sa/transactions/ike_auth.c +++ b/src/charon/sa/transactions/ike_auth.c @@ -228,7 +228,6 @@ static status_t get_request(private_ike_auth_t *this, message_t **result) { /* build ID payload */ my_id_payload = id_payload_create_from_identification(TRUE, my_id); request->add_payload(request, (payload_t*)my_id_payload); - this->ike_sa->set_my_id(this->ike_sa, my_id->clone(my_id)); } { /* TODO: build certreq payload */ @@ -889,6 +888,7 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, configured_other_id->get_string(configured_other_id)); return DESTROY_ME; } + /* update other ID. It was already set, but may contain wildcards */ this->ike_sa->set_other_id(this->ike_sa, other_id); } diff --git a/src/charon/sa/transactions/ike_sa_init.c b/src/charon/sa/transactions/ike_sa_init.c index 29cdcaf02..d69e6aa19 100644 --- a/src/charon/sa/transactions/ike_sa_init.c +++ b/src/charon/sa/transactions/ike_sa_init.c @@ -269,6 +269,7 @@ static status_t get_request(private_ike_sa_init_t *this, message_t **result) { message_t *request; host_t *me, *other; + identification_t *my_id, *other_id; /* check if we already have built a message (retransmission) */ if (this->message) @@ -280,6 +281,13 @@ static status_t get_request(private_ike_sa_init_t *this, message_t **result) me = this->connection->get_my_host(this->connection); other = this->connection->get_other_host(this->connection); + /* we already set up the IDs. Mine is already fully qualified, other + * will be updated in the ike_auth transaction */ + my_id = this->policy->get_my_id(this->policy); + other_id = this->policy->get_other_id(this->policy); + this->ike_sa->set_my_id(this->ike_sa, my_id->clone(my_id)); + this->ike_sa->set_other_id(this->ike_sa, other_id->clone(other_id)); + /* build the request */ request = message_create(); request->set_source(request, me->clone(me)); diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c index 2242ea24a..004e3ec1f 100755 --- a/src/charon/threads/stroke_interface.c +++ b/src/charon/threads/stroke_interface.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #define IKE_PORT 500 #define PATH_BUF 256 @@ -477,11 +477,9 @@ static void stroke_del_conn(private_stroke_t *this, stroke_msg_t *msg) */ static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg) { - initiate_ike_sa_job_t *job; + initiate_job_t *job; connection_t *connection; policy_t *policy; - linked_list_t *ike_sas; - ike_sa_id_t *ike_sa_id; pop_string(msg, &(msg->initiate.name)); this->logger->log(this->logger, CONTROL, @@ -495,49 +493,29 @@ static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg) this->stroke_logger->log(this->stroke_logger, ERROR, "no connection named \"%s\"", msg->initiate.name); + return; } - /* only initiate if it is an IKEv2 connection, ignore IKEv1 */ - else if (connection->is_ikev2(connection)) - { - - policy = charon->policies->get_policy_by_name(charon->policies, - msg->initiate.name); - if (policy == NULL) - { - this->stroke_logger->log(this->stroke_logger, ERROR, - "no policy named \"%s\"", - msg->initiate.name); - connection->destroy(connection); - return; - } - /* check for already set up IKE_SAs befor initiating */ - ike_sas = charon->ike_sa_manager->get_ike_sa_list_by_name(charon->ike_sa_manager, - msg->initiate.name); - if (ike_sas->get_count(ike_sas) > 0) - { - this->stroke_logger->log(this->stroke_logger, CONTROL, - "connection \"%s\" already up", - msg->initiate.name); - /* TODO: setup CHILD_SA with policy */ - connection->destroy(connection); - ike_sas->destroy(ike_sas); - return; - } - this->stroke_logger->log(this->stroke_logger, CONTROL, - "initiating connection \"%s\" (see log)...", - msg->initiate.name); - job = initiate_ike_sa_job_create(connection, policy); - charon->job_queue->add(charon->job_queue, (job_t*)job); - while (ike_sas->remove_last(ike_sas, (void**)&ike_sa_id) == SUCCESS) - { - ike_sa_id->destroy(ike_sa_id); - } - ike_sas->destroy(ike_sas); - } - else + if (!connection->is_ikev2(connection)) { connection->destroy(connection); + return; } + + policy = charon->policies->get_policy_by_name(charon->policies, + msg->initiate.name); + if (policy == NULL) + { + this->stroke_logger->log(this->stroke_logger, ERROR, + "no policy named \"%s\"", + msg->initiate.name); + connection->destroy(connection); + return; + } + this->stroke_logger->log(this->stroke_logger, CONTROL, + "initiating connection \"%s\" (see log)...", + msg->initiate.name); + job = initiate_job_create(connection, policy); + charon->job_queue->add(charon->job_queue, (job_t*)job); } /** diff --git a/src/libstrongswan/crypto/crypters/crypter.c b/src/libstrongswan/crypto/crypters/crypter.c index b5c1d951a..92f50e5fc 100644 --- a/src/libstrongswan/crypto/crypters/crypter.c +++ b/src/libstrongswan/crypto/crypters/crypter.c @@ -31,20 +31,20 @@ * String mappings for encryption_algorithm_t. */ mapping_t encryption_algorithm_m[] = { -{ENCR_UNDEFINED, "ENCR_UNDEFINED"}, -{ENCR_DES_IV64, "ENCR_DES_IV64"}, -{ENCR_DES, "ENCR_DES"}, -{ENCR_3DES, "ENCR_3DES"}, -{ENCR_RC5, "ENCR_RC5"}, -{ENCR_IDEA, "ENCR_IDEA"}, -{ENCR_CAST, "ENCR_CAST"}, -{ENCR_BLOWFISH, "ENCR_BLOWFISH"}, -{ENCR_3IDEA, "ENCR_3IDEA"}, -{ENCR_DES_IV32, "ENCR_DES_IV32"}, -{ENCR_NULL, "ENCR_NULL"}, -{ENCR_AES_CBC, "ENCR_AES_CBC"}, -{ENCR_AES_CTR, "ENCR_AES_CTR"}, -{MAPPING_END, NULL} + {ENCR_UNDEFINED, "UNDEFINED"}, + {ENCR_DES_IV64, "DES_IV64"}, + {ENCR_DES, "DES"}, + {ENCR_3DES, "3DES"}, + {ENCR_RC5, "RC5"}, + {ENCR_IDEA, "IDEA"}, + {ENCR_CAST, "CAST"}, + {ENCR_BLOWFISH, "BLOWFISH"}, + {ENCR_3IDEA, "3IDEA"}, + {ENCR_DES_IV32, "DES_IV32"}, + {ENCR_NULL, "NULL"}, + {ENCR_AES_CBC, "AES_CBC"}, + {ENCR_AES_CTR, "AES_CTR"}, + {MAPPING_END, NULL} }; /* diff --git a/src/libstrongswan/crypto/signers/signer.c b/src/libstrongswan/crypto/signers/signer.c index 78117462f..67fbbd69a 100644 --- a/src/libstrongswan/crypto/signers/signer.c +++ b/src/libstrongswan/crypto/signers/signer.c @@ -29,12 +29,12 @@ * String mappings for integrity_algorithm_t. */ mapping_t integrity_algorithm_m[] = { - {AUTH_UNDEFINED, "AUTH_UNDEFINED"}, - {AUTH_HMAC_MD5_96, "AUTH_HMAC_MD5_96"}, - {AUTH_HMAC_SHA1_96, "AUTH_HMAC_SHA1_96"}, - {AUTH_DES_MAC, "AUTH_DES_MAC"}, - {AUTH_KPDK_MD5, "AUTH_KPDK_MD5"}, - {AUTH_AES_XCBC_96, "AUTH_AES_XCBC_96"}, + {AUTH_UNDEFINED, "UNDEFINED"}, + {AUTH_HMAC_MD5_96, "HMAC_MD5_96"}, + {AUTH_HMAC_SHA1_96, "HMAC_SHA1_96"}, + {AUTH_DES_MAC, "DES_MAC"}, + {AUTH_KPDK_MD5, "KPDK_MD5"}, + {AUTH_AES_XCBC_96, "AES_XCBC_96"}, {MAPPING_END, NULL} };