aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2006-07-05 10:53:20 +0000
committerMartin Willi <martin@strongswan.org>2006-07-05 10:53:20 +0000
commit3dd3c5f39e57ef2f402870136579f7478a4eba34 (patch)
tree7438497060efb7eafe2eb866930adc5026a171d4
parentb12af2ead628521c8c55638b4f1eedc311864435 (diff)
downloadstrongswan-3dd3c5f39e57ef2f402870136579f7478a4eba34.tar.bz2
strongswan-3dd3c5f39e57ef2f402870136579f7478a4eba34.tar.xz
redesigned IKE_SA using a transaction mechanism:
removed old state machine reimplemented IKE_SA setup and delete implemented dead peer detection implemented keep-alives a lot of fixes no rekeying yet
-rw-r--r--src/charon/Makefile.am13
-rwxr-xr-xsrc/charon/config/configuration.c20
-rwxr-xr-xsrc/charon/config/configuration.h13
-rw-r--r--src/charon/config/connections/connection.c2
-rw-r--r--src/charon/config/policies/policy.c2
-rw-r--r--src/charon/config/proposal.c2
-rw-r--r--src/charon/daemon.c2
-rw-r--r--src/charon/doc/Todo-list.txt9
-rw-r--r--src/charon/encoding/message.c128
-rw-r--r--src/charon/encoding/message.h41
-rw-r--r--src/charon/encoding/payloads/cert_payload.c2
-rw-r--r--src/charon/encoding/payloads/ke_payload.c25
-rw-r--r--src/charon/encoding/payloads/ke_payload.h13
-rw-r--r--src/charon/encoding/payloads/nonce_payload.h9
-rw-r--r--src/charon/encoding/payloads/notify_payload.c126
-rw-r--r--src/charon/encoding/payloads/notify_payload.h16
-rw-r--r--src/charon/encoding/payloads/payload.c31
-rw-r--r--src/charon/encoding/payloads/payload.h5
-rw-r--r--src/charon/encoding/payloads/proposal_substructure.c10
-rw-r--r--src/charon/encoding/payloads/sa_payload.c2
-rw-r--r--src/charon/network/interfaces.c8
-rw-r--r--src/charon/network/interfaces.h10
-rw-r--r--src/charon/network/socket.c4
-rw-r--r--src/charon/queues/jobs/delete_half_open_ike_sa_job.c31
-rw-r--r--src/charon/queues/jobs/delete_half_open_ike_sa_job.h5
-rw-r--r--src/charon/queues/jobs/incoming_packet_job.c134
-rw-r--r--src/charon/queues/jobs/initiate_ike_sa_job.c33
-rw-r--r--src/charon/queues/jobs/retransmit_request_job.c70
-rw-r--r--src/charon/queues/jobs/send_dpd_job.c47
-rw-r--r--src/charon/queues/jobs/send_keepalive_job.c62
-rw-r--r--src/charon/queues/send_queue.c16
-rw-r--r--src/charon/sa/authenticator.c4
-rw-r--r--src/charon/sa/authenticator.h11
-rw-r--r--src/charon/sa/child_sa.c1
-rw-r--r--src/charon/sa/ike_sa.c1923
-rw-r--r--src/charon/sa/ike_sa.h616
-rw-r--r--src/charon/sa/ike_sa_id.c2
-rw-r--r--src/charon/sa/ike_sa_manager.c136
-rw-r--r--src/charon/sa/states/create_child_sa_requested.c435
-rw-r--r--src/charon/sa/states/create_child_sa_requested.h64
-rw-r--r--src/charon/sa/states/delete_child_sa_requested.c185
-rw-r--r--src/charon/sa/states/delete_child_sa_requested.h57
-rw-r--r--src/charon/sa/states/delete_ike_sa_requested.c163
-rw-r--r--src/charon/sa/states/delete_ike_sa_requested.h57
-rw-r--r--src/charon/sa/states/ike_auth_requested.c719
-rw-r--r--src/charon/sa/states/ike_auth_requested.h72
-rw-r--r--src/charon/sa/states/ike_sa_established.c671
-rw-r--r--src/charon/sa/states/ike_sa_established.h64
-rw-r--r--src/charon/sa/states/ike_sa_init_requested.c990
-rw-r--r--src/charon/sa/states/ike_sa_init_requested.h68
-rw-r--r--src/charon/sa/states/ike_sa_init_responded.c796
-rw-r--r--src/charon/sa/states/ike_sa_init_responded.h73
-rw-r--r--src/charon/sa/states/initiator_init.c440
-rw-r--r--src/charon/sa/states/initiator_init.h84
-rw-r--r--src/charon/sa/states/responder_init.c798
-rw-r--r--src/charon/sa/states/responder_init.h68
-rw-r--r--src/charon/sa/states/state.c41
-rw-r--r--src/charon/sa/states/state.h228
-rw-r--r--src/charon/sa/transactions/dead_peer_detection.c198
-rw-r--r--src/charon/sa/transactions/dead_peer_detection.h60
-rw-r--r--src/charon/sa/transactions/delete_ike_sa.c271
-rw-r--r--src/charon/sa/transactions/delete_ike_sa.h83
-rw-r--r--src/charon/sa/transactions/ike_auth.c1007
-rw-r--r--src/charon/sa/transactions/ike_auth.h86
-rw-r--r--src/charon/sa/transactions/ike_sa_init.c1079
-rw-r--r--src/charon/sa/transactions/ike_sa_init.h73
-rw-r--r--src/charon/sa/transactions/transaction.c147
-rw-r--r--src/charon/sa/transactions/transaction.h181
-rw-r--r--src/charon/testing/generator_test.c2
-rw-r--r--src/charon/testing/parser_test.c2
-rwxr-xr-xsrc/charon/threads/stroke_interface.c2
71 files changed, 4767 insertions, 8081 deletions
diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am
index 54028b0e1..09eab4649 100644
--- a/src/charon/Makefile.am
+++ b/src/charon/Makefile.am
@@ -1,4 +1,3 @@
-SUBDIRS = . testing
ipsec_PROGRAMS = charon
charon_SOURCES = \
@@ -9,13 +8,11 @@ config/policies/local_policy_store.c config/policies/policy_store.h config/polic
config/credentials/local_credential_store.c config/credentials/local_credential_store.h \
config/credentials/credential_store.h config/traffic_selector.c config/traffic_selector.h \
config/proposal.c config/proposal.h config/configuration.c config/configuration.h \
-sa/states/state.c sa/states/state.h sa/states/ike_sa_init_requested.c sa/states/ike_sa_init_requested.h \
-sa/states/ike_sa_init_responded.c sa/states/ike_sa_established.c sa/states/ike_sa_established.h \
-sa/states/responder_init.c sa/states/responder_init.h sa/states/initiator_init.c sa/states/initiator_init.h \
-sa/states/ike_sa_init_responded.h sa/states/ike_auth_requested.c sa/states/ike_auth_requested.h \
-sa/states/delete_ike_sa_requested.h sa/states/delete_ike_sa_requested.c \
-sa/states/delete_child_sa_requested.h sa/states/delete_child_sa_requested.c \
-sa/states/create_child_sa_requested.c sa/states/create_child_sa_requested.h \
+sa/transactions/transaction.h sa/transactions/transaction.c \
+sa/transactions/ike_sa_init.h sa/transactions/ike_sa_init.c \
+sa/transactions/ike_auth.h sa/transactions/ike_auth.c \
+sa/transactions/dead_peer_detection.h sa/transactions/dead_peer_detection.c \
+sa/transactions/delete_ike_sa.h sa/transactions/delete_ike_sa.c \
sa/child_sa.c sa/child_sa.h sa/ike_sa.c sa/ike_sa.h sa/ike_sa_manager.c sa/ike_sa_manager.h \
sa/ike_sa_id.c sa/ike_sa_id.h sa/authenticator.c sa/authenticator.h encoding/payloads/encryption_payload.c \
encoding/payloads/cert_payload.c encoding/payloads/payload.h encoding/payloads/traffic_selector_substructure.c \
diff --git a/src/charon/config/configuration.c b/src/charon/config/configuration.c
index cd205867e..2dcf0bb72 100755
--- a/src/charon/config/configuration.c
+++ b/src/charon/config/configuration.c
@@ -29,6 +29,7 @@
/**
* Timeout in milliseconds after that a half open IKE_SA gets deleted.
+ * Set to zero to disable
*/
#define HALF_OPEN_IKE_SA_TIMEOUT 30000
@@ -51,14 +52,14 @@
#define MAX_RETRANSMIT_COUNT 6
/**
- * Keepalive interval in milliseconds.
+ * Keepalive interval in seconds.
*/
-#define KEEPALIVE_INTERVAL 2000000
+#define KEEPALIVE_INTERVAL 20
/**
- * DPD interval in milliseconds.
+ * DPD interval in seconds.
*/
-#define DPD_INTERVAL 6000000
+#define DPD_INTERVAL 60
typedef struct private_configuration_t private_configuration_t;
@@ -78,16 +79,13 @@ struct private_configuration_t {
/**
* Implementation of configuration_t.get_retransmit_timeout.
*/
-static status_t get_retransmit_timeout (private_configuration_t *this, u_int32_t retransmit_count, u_int32_t *timeout)
+static u_int32_t get_retransmit_timeout (private_configuration_t *this, u_int32_t retransmit_count)
{
if (retransmit_count > MAX_RETRANSMIT_COUNT && MAX_RETRANSMIT_COUNT != 0)
{
- return FAILED;
+ return 0;
}
-
- *timeout = (u_int32_t)(RETRANSMIT_TIMEOUT * pow(RETRANSMIT_BASE, retransmit_count));
-
- return SUCCESS;
+ return (u_int32_t)(RETRANSMIT_TIMEOUT * pow(RETRANSMIT_BASE, retransmit_count));
}
/**
@@ -131,7 +129,7 @@ configuration_t *configuration_create()
/* public functions */
this->public.destroy = (void(*)(configuration_t*))destroy;
- this->public.get_retransmit_timeout = (status_t (*) (configuration_t *, u_int32_t retransmit_count, u_int32_t *timeout))get_retransmit_timeout;
+ this->public.get_retransmit_timeout = (u_int32_t (*) (configuration_t *, u_int32_t retransmit_count))get_retransmit_timeout;
this->public.get_half_open_ike_sa_timeout = (u_int32_t (*) (configuration_t *)) get_half_open_ike_sa_timeout;
this->public.get_keepalive_interval = (u_int32_t (*) (configuration_t *)) get_keepalive_interval;
this->public.get_dpd_interval = (u_int32_t (*) (configuration_t *)) get_dpd_interval;
diff --git a/src/charon/config/configuration.h b/src/charon/config/configuration.h
index 813b95788..553a01edd 100755
--- a/src/charon/config/configuration.h
+++ b/src/charon/config/configuration.h
@@ -41,18 +41,15 @@ struct configuration_t {
/**
* @brief Returns the retransmit timeout.
*
+ * A return value of zero means the request should not retransmitted again.
* The timeout values are managed by the configuration, so
* another backoff algorithm may be implemented here.
*
* @param this calling object
* @param retransmit_count number of times a message was retransmitted so far
- * @param[out] timeout the new retransmit timeout in milliseconds
- *
- * @return
- * - FAILED, if the message should not be retransmitted
- * - SUCCESS
+ * @return time in milliseconds, when to schedule next retransmit
*/
- status_t (*get_retransmit_timeout) (configuration_t *this, u_int32_t retransmit_count, u_int32_t *timeout);
+ u_int32_t (*get_retransmit_timeout) (configuration_t *this, u_int32_t retransmit_count);
/**
* @brief Returns the timeout for an half open IKE_SA in ms.
@@ -76,7 +73,7 @@ struct configuration_t {
* NAT keepalive packet should be sent.
*
* @param this calling object
- * @return interval in milliseconds (ms)
+ * @return interval in seconds
*/
u_int32_t (*get_keepalive_interval) (configuration_t *this);
@@ -87,7 +84,7 @@ struct configuration_t {
* DPD request packet should be sent.
*
* @param this calling object
- * @return interval in milliseconds (ms)
+ * @return interval in seconds
*/
u_int32_t (*get_dpd_interval) (configuration_t *this);
diff --git a/src/charon/config/connections/connection.c b/src/charon/config/connections/connection.c
index ce1f0f31a..e31466039 100644
--- a/src/charon/config/connections/connection.c
+++ b/src/charon/config/connections/connection.c
@@ -280,9 +280,9 @@ static bool check_dh_group(private_connection_t *this, diffie_hellman_group_t dh
return TRUE;
}
}
+ alg_iter->destroy(alg_iter);
}
prop_iter->destroy(prop_iter);
- alg_iter->destroy(alg_iter);
return FALSE;
}
diff --git a/src/charon/config/policies/policy.c b/src/charon/config/policies/policy.c
index 9e163f9de..0e2d148a4 100644
--- a/src/charon/config/policies/policy.c
+++ b/src/charon/config/policies/policy.c
@@ -503,7 +503,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
this->public.add_other_traffic_selector = (void(*)(policy_t*,traffic_selector_t*))add_other_traffic_selector;
this->public.add_proposal = (void(*)(policy_t*,proposal_t*))add_proposal;
this->public.add_authorities = (void(*)(policy_t*,identification_t*, identification_t*))add_authorities;
- this->public.add_updown = (void(*)(policy_t*,identification_t*,char*))add_updown;
+ this->public.add_updown = (void(*)(policy_t*,char*))add_updown;
this->public.get_soft_lifetime = (u_int32_t (*) (policy_t *))get_soft_lifetime;
this->public.get_hard_lifetime = (u_int32_t (*) (policy_t *))get_hard_lifetime;
this->public.clone = (policy_t*(*)(policy_t*))clone;
diff --git a/src/charon/config/proposal.c b/src/charon/config/proposal.c
index 3eb081544..503b4c1c6 100644
--- a/src/charon/config/proposal.c
+++ b/src/charon/config/proposal.c
@@ -572,6 +572,8 @@ proposal_t *proposal_create_default(protocol_id_t protocol)
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
break;
+ default:
+ break;
}
return &this->public;
diff --git a/src/charon/daemon.c b/src/charon/daemon.c
index 73d131ca1..d9ce83ee3 100644
--- a/src/charon/daemon.c
+++ b/src/charon/daemon.c
@@ -34,7 +34,7 @@
#include "daemon.h"
#include <types.h>
-#include <config/credentials/credential_store.h>
+#include <config/credentials/local_credential_store.h>
#include <config/connections/local_connection_store.h>
#include <config/policies/local_policy_store.h>
diff --git a/src/charon/doc/Todo-list.txt b/src/charon/doc/Todo-list.txt
index 8508d2492..7fb33e5a2 100644
--- a/src/charon/doc/Todo-list.txt
+++ b/src/charon/doc/Todo-list.txt
@@ -35,9 +35,9 @@
/ useable certificate support
+ more id types (use atodn from pluto)
+ rewrite certificate storage the clean way
- - further subjectAltName support
- - certificate validation/chaining
- - certificate exchange
+ + further subjectAltName support
+ + certificate validation/chaining
+ + certificate exchange
+ Apply -W's from Makefile.program to charon
+ do ipsec status via starter
@@ -45,7 +45,7 @@
+ stroke status should show configured connections
+ stroke loglevel update
-- stroke argument parsing via getopts/gperf?
++ stroke argument parsing via getopts/gperf?
- implement 3DES to load encrypted pem files
+ ipsec.secrets parsing
@@ -60,3 +60,4 @@
- add a crl fetch mechanism which synchronizes equal fetches
- replace state machine with something more transaction oriented
+- find existing IKE_SA on CHILD_SA initiation
diff --git a/src/charon/encoding/message.c b/src/charon/encoding/message.c
index 4f5f3b899..4593d33e8 100644
--- a/src/charon/encoding/message.c
+++ b/src/charon/encoding/message.c
@@ -22,6 +22,7 @@
*/
#include <stdlib.h>
+#include <string.h>
#include "message.h"
@@ -413,14 +414,9 @@ static void set_ike_sa_id (private_message_t *this,ike_sa_id_t *ike_sa_id)
/**
* Implementation of message_t.get_ike_sa_id.
*/
-static status_t get_ike_sa_id (private_message_t *this,ike_sa_id_t **ike_sa_id)
+static ike_sa_id_t* get_ike_sa_id (private_message_t *this)
{
- if (this->ike_sa_id == NULL)
- {
- return FAILED;
- }
- *ike_sa_id = this->ike_sa_id->clone(this->ike_sa_id);
- return SUCCESS;
+ return this->ike_sa_id;
}
/**
@@ -521,6 +517,20 @@ static exchange_type_t get_request (private_message_t *this)
}
/**
+ * Is this message in an encoded form?
+ */
+static bool is_encoded(private_message_t *this)
+{
+ chunk_t data = this->packet->get_data(this->packet);
+
+ if (data.ptr == NULL)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
* Implementation of message_t.add_payload.
*/
static void add_payload(private_message_t *this, payload_t *payload)
@@ -583,6 +593,48 @@ static iterator_t *get_payload_iterator(private_message_t *this)
return this->payloads->create_iterator(this->payloads, TRUE);
}
+/**
+ * Build a string containing short names for all payload in this message
+ */
+static void build_payload_string(private_message_t *this, char* buffer, size_t size)
+{
+ iterator_t *iterator;
+ payload_t *payload;
+ bool first = TRUE;
+
+ *buffer = '\0';
+ size--;
+
+ iterator = this->payloads->create_iterator(this->payloads, TRUE);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ payload_type_t type = payload->get_type(payload);
+ char *name = mapping_find(payload_type_short_m, type);
+ size_t name_len = strlen(name);
+ if (!first)
+ {
+ strncat(buffer, " ", size);
+ if (size)
+ {
+ size--;
+ }
+ }
+ else
+ {
+ first = FALSE;
+ }
+ strncat(buffer, name, size);
+ if (name_len > size)
+ {
+ size = 0;
+ }
+ else
+ {
+ size -= name_len;
+ }
+ }
+ iterator->destroy(iterator);
+}
/**
* Implementation of message_t.generate.
@@ -595,11 +647,20 @@ static status_t generate(private_message_t *this, crypter_t *crypter, signer_t*
iterator_t *iterator;
status_t status;
chunk_t packet_data;
+ char payload_names[128];
+
+ if (is_encoded(this))
+ {
+ /* already generated, return a new packet clone */
+ *packet = this->packet->clone(this->packet);
+ return SUCCESS;
+ }
- this->logger->log(this->logger, CONTROL, "generating %s %s, contains %d payloads",
+ build_payload_string(this, payload_names, sizeof(payload_names));
+ this->logger->log(this->logger, CONTROL, "generating %s %s [%s]",
mapping_find(exchange_type_m,this->exchange_type),
this->is_request ? "request" : "response",
- this->payloads->get_count(this->payloads));
+ payload_names);
if (this->exchange_type == EXCHANGE_TYPE_UNDEFINED)
{
@@ -711,20 +772,6 @@ static chunk_t get_packet_data (private_message_t *this)
}
/**
- * Implementation of message_t.is_encoded.
- */
-static bool is_encoded(private_message_t *this)
-{
- chunk_t data = this->packet->get_data(this->packet);
-
- if (data.ptr == NULL)
- {
- return FALSE;
- }
- return TRUE;
-}
-
-/**
* Implementation of message_t.parse_header.
*/
static status_t parse_header(private_message_t *this)
@@ -794,6 +841,7 @@ static status_t parse_body(private_message_t *this, crypter_t *crypter, signer_t
{
status_t status = SUCCESS;
payload_type_t current_payload_type;
+ char payload_names[128];
current_payload_type = this->first_payload;
@@ -815,7 +863,7 @@ static status_t parse_body(private_message_t *this, crypter_t *crypter, signer_t
{
this->logger->log(this->logger, ERROR, "payload type %s could not be parsed",
mapping_find(payload_type_m,current_payload_type));
- return status;
+ return PARSE_ERROR;
}
this->logger->log(this->logger, CONTROL|LEVEL2, "verify payload of type %s",
@@ -828,8 +876,7 @@ static status_t parse_body(private_message_t *this, crypter_t *crypter, signer_t
this->logger->log(this->logger, ERROR, "%s payload verification failed",
mapping_find(payload_type_m,current_payload_type));
current_payload->destroy(current_payload);
- status = VERIFY_ERROR;
- return status;
+ return VERIFY_ERROR;
}
this->logger->log(this->logger, CONTROL|LEVEL2, "%s payload verified. Adding to payload list",
@@ -862,14 +909,16 @@ static status_t parse_body(private_message_t *this, crypter_t *crypter, signer_t
if (status != SUCCESS)
{
this->logger->log(this->logger, ERROR, "verification of message failed");
+ return status;
}
- this->logger->log(this->logger, CONTROL, "parsed %s %s, contains %d payloads",
+ build_payload_string(this, payload_names, sizeof(payload_names));
+ this->logger->log(this->logger, CONTROL, "parsed %s %s [%s]",
mapping_find(exchange_type_m, this->exchange_type),
this->is_request ? "request" : "response",
- this->payloads->get_count(this->payloads));
+ payload_names);
- return status;
+ return SUCCESS;
}
/**
@@ -926,7 +975,7 @@ static status_t verify(private_message_t *this)
mapping_find(payload_type_m, current_payload_type),
this->message_rule->payload_rules[i].max_occurence, found_payloads);
iterator->destroy(iterator);
- return FAILED;
+ return VERIFY_ERROR;
}
}
}
@@ -937,7 +986,7 @@ static status_t verify(private_message_t *this)
mapping_find(payload_type_m, this->message_rule->payload_rules[i].payload_type),
this->message_rule->payload_rules[i].min_occurence, found_payloads);
iterator->destroy(iterator);
- return FAILED;
+ return VERIFY_ERROR;
}
if ((this->message_rule->payload_rules[i].sufficient) && (this->payloads->get_count(this->payloads) == total_found_payloads))
{
@@ -993,7 +1042,7 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig
/* encrypted payload is not last one */
this->logger->log(this->logger, ERROR, "encrypted payload is not last payload");
iterator->destroy(iterator);
- return FAILED;
+ return VERIFY_ERROR;
}
/* decrypt */
encryption_payload->set_transforms(encryption_payload, crypter, signer);
@@ -1003,7 +1052,7 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig
{
this->logger->log(this->logger, ERROR, "encryption payload signature invalid");
iterator->destroy(iterator);
- return status;
+ return FAILED;
}
this->logger->log(this->logger, CONTROL | LEVEL2, "decrypt content of encryption payload");
status = encryption_payload->decrypt(encryption_payload);
@@ -1013,7 +1062,7 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig
"encrypted payload could not be decrypted and parsed: %s",
mapping_find(status_m, status));
iterator->destroy(iterator);
- return status;
+ return PARSE_ERROR;
}
/* needed later to find out if a payload was encrypted */
@@ -1073,7 +1122,7 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig
this->logger->log(this->logger, ERROR, "payload type %s not allowed",
mapping_find(payload_type_m,current_payload_type));
iterator->destroy(iterator);
- return status;
+ return VERIFY_ERROR;
}
/* check if the payload was encrypted, and if it should been have encrypted */
@@ -1084,7 +1133,7 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig
mapping_find(payload_type_m,current_payload_type),
(payload_rule->encrypted) ? "encrypted" : "not encrypted");
iterator->destroy(iterator);
- return FAILED;
+ return VERIFY_ERROR;
}
}
/* advance to the next payload */
@@ -1188,8 +1237,6 @@ static void destroy (private_message_t *this)
{
iterator_t *iterator;
- this->logger->log(this->logger, CONTROL|LEVEL3, "going to destroy message_t object");
-
this->packet->destroy(this->packet);
if (this->ike_sa_id != NULL)
@@ -1202,8 +1249,6 @@ static void destroy (private_message_t *this)
{
payload_t *payload;
iterator->current(iterator, (void**)&payload);
- this->logger->log(this->logger, CONTROL|LEVEL3, "destroying payload of type %s",
- mapping_find(payload_type_m, payload->get_type(payload)));
payload->destroy(payload);
}
iterator->destroy(iterator);
@@ -1230,7 +1275,7 @@ message_t *message_create_from_packet(packet_t *packet)
this->public.get_initiator_spi = (u_int64_t(*)(message_t*))get_initiator_spi;
this->public.get_responder_spi = (u_int64_t(*)(message_t*))get_responder_spi;
this->public.set_ike_sa_id = (void(*)(message_t*, ike_sa_id_t *))set_ike_sa_id;
- this->public.get_ike_sa_id = (status_t(*)(message_t*, ike_sa_id_t **))get_ike_sa_id;
+ this->public.get_ike_sa_id = (ike_sa_id_t*(*)(message_t*))get_ike_sa_id;
this->public.set_exchange_type = (void(*)(message_t*, exchange_type_t))set_exchange_type;
this->public.get_exchange_type = (exchange_type_t(*)(message_t*))get_exchange_type;
this->public.set_request = (void(*)(message_t*, bool))set_request;
@@ -1246,7 +1291,6 @@ message_t *message_create_from_packet(packet_t *packet)
this->public.parse_body = (status_t (*) (message_t *,crypter_t*,signer_t*)) parse_body;
this->public.get_packet = (packet_t * (*) (message_t*)) get_packet;
this->public.get_packet_data = (chunk_t (*) (message_t *this)) get_packet_data;
- this->public.is_encoded = (bool (*) (message_t *this)) is_encoded;
this->public.destroy = (void(*)(message_t*))destroy;
/* private values */
diff --git a/src/charon/encoding/message.h b/src/charon/encoding/message.h
index 8c105e597..41edd4c75 100644
--- a/src/charon/encoding/message.h
+++ b/src/charon/encoding/message.h
@@ -120,27 +120,22 @@ struct message_t {
/**
* @brief Sets the IKE_SA ID of the message.
*
- * @warning ike_sa_id gets cloned internaly and
- * so can be destroyed afterwards.
+ * ike_sa_id gets cloned.
*
* @param this message_t object
* @param ike_sa_id ike_sa_id to set
*/
- void (*set_ike_sa_id) (message_t *this,ike_sa_id_t * ike_sa_id);
+ void (*set_ike_sa_id) (message_t *this, ike_sa_id_t * ike_sa_id);
/**
* @brief Gets the IKE_SA ID of the message.
- *
- * @warning The returned ike_sa_id is a clone of the internal one.
- * So it has to be destroyed by the caller.
+ *
+ * The ike_sa_id points to the message internal id, do not modify.
*
* @param this message_t object
- * @param ike_sa_id pointer to ike_sa_id pointer which will be set
- * @return
- * - SUCCESS
- * - FAILED if no ike_sa_id is set
+ * @return ike_sa_id of message
*/
- status_t (*get_ike_sa_id) (message_t *this,ike_sa_id_t **ike_sa_id);
+ ike_sa_id_t *(*get_ike_sa_id) (message_t *this);
/**
* @brief Sets the exchange type of the message.
@@ -219,11 +214,12 @@ struct message_t {
* @param crypter crypter to decrypt encryption payloads
* @param signer signer to verifiy a message with an encryption payload
* @return
- * - SUCCESS if header could be parsed
+ * - SUCCESS if parsing successful
* - NOT_SUPPORTED if ciritcal unknown payloads found
- * - FAILED if message type is not suppported!
- * - PARSE_ERROR if corrupted/invalid data found
- * - VERIFY_ERROR if verification of some payload failed
+ * - NOT_SUPPORTED if message type is not supported!
+ * - PARSE_ERROR if message parsing failed
+ * - VERIFY_ERROR if message verification failed (bad syntax)
+ * - FAILED if integrity check failed
* - INVALID_STATE if crypter/signer not supplied, but needed
*/
status_t (*parse_body) (message_t *this, crypter_t *crypter, signer_t *signer);
@@ -238,10 +234,12 @@ struct message_t {
* message.
* Crypter/signer can be omitted (by passing NULL) when no encryption
* payload is expected.
+ * Generation is only done once, multiple calls will just return a packet copy.
*
* @param this message_t object
* @param crypter crypter to use when a payload must be encrypted
* @param signer signer to build a mac
+ * @param packet copy of generated packet
* @return
* - SUCCESS if packet could be generated
* - INVALID_STATE if exchange type is currently not set
@@ -322,19 +320,6 @@ struct message_t {
chunk_t (*get_packet_data) (message_t *this);
/**
- * @brief Check if a message is encoded.
- *
- * Check if the packet is in a generated (and encrypted) form available
- * and can be passed down to the socket. If not, it has to be generated
- * first.
- *
- * @param this message_t object
- * @return TRUE if encoded, FALSE if not
- */
- bool (*is_encoded) (message_t *this);
-
-
- /**
* @brief Destroys a message and all including objects.
*
* @param this message_t object
diff --git a/src/charon/encoding/payloads/cert_payload.c b/src/charon/encoding/payloads/cert_payload.c
index 18bf24d47..1df30e1e0 100644
--- a/src/charon/encoding/payloads/cert_payload.c
+++ b/src/charon/encoding/payloads/cert_payload.c
@@ -291,4 +291,4 @@ cert_payload_t *cert_payload_create_from_x509(x509_t *cert)
this->set_cert_encoding(this, CERT_X509_SIGNATURE);
this->set_data(this, cert->get_certificate(cert));
return this;
-} \ No newline at end of file
+}
diff --git a/src/charon/encoding/payloads/ke_payload.c b/src/charon/encoding/payloads/ke_payload.c
index 0c92e033d..02af60187 100644
--- a/src/charon/encoding/payloads/ke_payload.c
+++ b/src/charon/encoding/payloads/ke_payload.c
@@ -216,9 +216,7 @@ static void set_key_exchange_data(private_ke_payload_t *this, chunk_t key_exchan
}
- this->key_exchange_data.ptr = clalloc(key_exchange_data.ptr,key_exchange_data.len);
-
- this->key_exchange_data.len = key_exchange_data.len;
+ this->key_exchange_data = chunk_clone(key_exchange_data);
this->compute_length(this);
}
@@ -268,9 +266,22 @@ ke_payload_t *ke_payload_create()
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length = KE_PAYLOAD_HEADER_LENGTH;
- this->key_exchange_data.ptr = NULL;
- this->key_exchange_data.len = 0;
- this->dh_group_number = 0;
+ this->key_exchange_data = CHUNK_INITIALIZER;
+ this->dh_group_number = MODP_NONE;
+
+ return &this->public;
+}
- return (&(this->public));
+/*
+ * Described in header
+ */
+ke_payload_t *ke_payload_create_from_diffie_hellman(diffie_hellman_t *dh)
+{
+ private_ke_payload_t *this = (private_ke_payload_t*)ke_payload_create();
+
+ dh->get_my_public_value(dh, &this->key_exchange_data);
+ this->dh_group_number = dh->get_dh_group(dh);
+ this->compute_length(this);
+
+ return &this->public;
}
diff --git a/src/charon/encoding/payloads/ke_payload.h b/src/charon/encoding/payloads/ke_payload.h
index 9490bef89..43a55fd9d 100644
--- a/src/charon/encoding/payloads/ke_payload.h
+++ b/src/charon/encoding/payloads/ke_payload.h
@@ -27,6 +27,8 @@
#include <encoding/payloads/payload.h>
#include <encoding/payloads/transform_substructure.h>
#include <utils/linked_list.h>
+#include <crypto/diffie_hellman.h>
+
/**
* KE payload length in bytes without any key exchange data.
*
@@ -106,5 +108,14 @@ struct ke_payload_t {
*/
ke_payload_t *ke_payload_create(void);
+/**
+ * @brief Creates a ke_payload_t from a diffie_hellman_t
+ *
+ * @param diffie_hellman diffie hellman object containing group and key
+ * @return ke_payload_t object
+ *
+ * @ingroup payloads
+ */
+ke_payload_t *ke_payload_create_from_diffie_hellman(diffie_hellman_t *diffie_hellman);
-#endif /*KE_PAYLOAD_H_*/
+#endif /* KE_PAYLOAD_H_ */
diff --git a/src/charon/encoding/payloads/nonce_payload.h b/src/charon/encoding/payloads/nonce_payload.h
index e875fb263..9365bb52b 100644
--- a/src/charon/encoding/payloads/nonce_payload.h
+++ b/src/charon/encoding/payloads/nonce_payload.h
@@ -27,6 +27,15 @@
#include <encoding/payloads/payload.h>
/**
+ * Nonce size in bytes for nonces sending to other peer.
+ *
+ * @warning Nonce size MUST be between 16 and 256 bytes.
+ *
+ * @ingroup payloads
+ */
+#define NONCE_SIZE 16
+
+/**
* Length of a nonce payload without a nonce in bytes.
*
* @ingroup payloads
diff --git a/src/charon/encoding/payloads/notify_payload.c b/src/charon/encoding/payloads/notify_payload.c
index 4242b4c1e..7d032ec6e 100644
--- a/src/charon/encoding/payloads/notify_payload.c
+++ b/src/charon/encoding/payloads/notify_payload.c
@@ -28,10 +28,12 @@
#include <daemon.h>
#include <encoding/payloads/encodings.h>
+#define SHA1_HASH_SIZE 20
+
/**
- * String mappings for notify_message_type_t.
+ * String mappings for notify_type_t.
*/
-mapping_t notify_message_type_m[] = {
+mapping_t notify_type_m[] = {
{UNSUPPORTED_CRITICAL_PAYLOAD, "UNSUPPORTED_CRITICAL_PAYLOAD"},
{INVALID_IKE_SPI, "INVALID_IKE_SPI"},
{INVALID_MAJOR_VERSION, "INVALID_MAJOR_VERSION"},
@@ -94,7 +96,7 @@ struct private_notify_payload_t {
/**
* Notify message type.
*/
- u_int16_t notify_message_type;
+ u_int16_t notify_type;
/**
* Security parameter index (spi).
@@ -146,7 +148,7 @@ encoding_rule_t notify_payload_encodings[] = {
/* SPI Size as 8 bit field*/
{ SPI_SIZE, offsetof(private_notify_payload_t, spi_size) },
/* Notify message type as 16 bit field*/
- { U_INT_16, offsetof(private_notify_payload_t, notify_message_type) },
+ { U_INT_16, offsetof(private_notify_payload_t, notify_type) },
/* SPI as variable length field*/
{ SPI, offsetof(private_notify_payload_t, spi) },
/* Key Exchange Data is from variable size */
@@ -195,31 +197,60 @@ static status_t verify(private_notify_payload_t *this)
return FAILED;
}
- /* TODO: Check all kinds of notify */
- if (this->notify_message_type == INVALID_KE_PAYLOAD)
+ switch (this->notify_type)
{
- /* check notification data */
- diffie_hellman_group_t dh_group;
- if (this->notification_data.len != 2)
+ case INVALID_KE_PAYLOAD:
{
- return FAILED;
+ /* check notification data */
+ diffie_hellman_group_t dh_group;
+ if (this->notification_data.len != 2)
+ {
+ return FAILED;
+ }
+ dh_group = ntohs(*((u_int16_t*)this->notification_data.ptr));
+ switch (dh_group)
+ {
+ case MODP_768_BIT:
+ case MODP_1024_BIT:
+ case MODP_1536_BIT:
+ case MODP_2048_BIT:
+ case MODP_3072_BIT:
+ case MODP_4096_BIT:
+ case MODP_6144_BIT:
+ case MODP_8192_BIT:
+ break;
+ default:
+ this->logger->log(this->logger, ERROR, "Bad DH group (%d)", dh_group);
+ return FAILED;
+ }
+ break;
}
- dh_group = ntohs(*((u_int16_t*)this->notification_data.ptr));
- switch (dh_group)
+ case NAT_DETECTION_SOURCE_IP:
+ case NAT_DETECTION_DESTINATION_IP:
{
- case MODP_768_BIT:
- case MODP_1024_BIT:
- case MODP_1536_BIT:
- case MODP_2048_BIT:
- case MODP_3072_BIT:
- case MODP_4096_BIT:
- case MODP_6144_BIT:
- case MODP_8192_BIT:
- break;
- default:
- this->logger->log(this->logger, ERROR, "Bad DH group (%d)", dh_group);
+ if (this->notification_data.len != SHA1_HASH_SIZE)
+ {
+ this->logger->log(this->logger, ERROR, "invalid %s notify length",
+ mapping_find(notify_type_m, this->notify_type));
+ return FAILED;
+ }
+ break;
+ }
+ case INVALID_SYNTAX:
+ case INVALID_MAJOR_VERSION:
+ case NO_PROPOSAL_CHOSEN:
+ {
+ if (this->notification_data.len != 0)
+ {
+ this->logger->log(this->logger, ERROR, "invalid %s notify",
+ mapping_find(notify_type_m, this->notify_type));
return FAILED;
+ }
+ break;
}
+ default:
+ /* TODO: verify */
+ break;
}
return SUCCESS;
}
@@ -300,19 +331,19 @@ static void set_protocol_id(private_notify_payload_t *this, u_int8_t protocol_id
}
/**
- * Implementation of notify_payload_t.get_notify_message_type.
+ * Implementation of notify_payload_t.get_notify_type.
*/
-static notify_message_type_t get_notify_message_type(private_notify_payload_t *this)
+static notify_type_t get_notify_type(private_notify_payload_t *this)
{
- return this->notify_message_type;
+ return this->notify_type;
}
/**
- * Implementation of notify_payload_t.set_notify_message_type.
+ * Implementation of notify_payload_t.set_notify_type.
*/
-static void set_notify_message_type(private_notify_payload_t *this, u_int16_t notify_message_type)
+static void set_notify_type(private_notify_payload_t *this, u_int16_t notify_type)
{
- this->notify_message_type = notify_message_type;
+ this->notify_type = notify_type;
}
/**
@@ -363,20 +394,9 @@ static chunk_t get_notification_data(private_notify_payload_t *this)
*/
static status_t set_notification_data(private_notify_payload_t *this, chunk_t notification_data)
{
- /* destroy existing data first */
- if (this->notification_data.ptr != NULL)
- {
- /* free existing value */
- free(this->notification_data.ptr);
- this->notification_data.ptr = NULL;
- this->notification_data.len = 0;
-
- }
-
- this->notification_data.ptr = clalloc(notification_data.ptr,notification_data.len);
- this->notification_data.len = notification_data.len;
+ chunk_free(&this->notification_data);
+ this->notification_data = chunk_clone(notification_data);
this->compute_length(this);
-
return SUCCESS;
}
@@ -385,14 +405,8 @@ static status_t set_notification_data(private_notify_payload_t *this, chunk_t no
*/
static status_t destroy(private_notify_payload_t *this)
{
- if (this->notification_data.ptr != NULL)
- {
- free(this->notification_data.ptr);
- }
- if (this->spi.ptr != NULL)
- {
- free(this->spi.ptr);
- }
+ chunk_free(&this->notification_data);
+ chunk_free(&this->spi);
free(this);
return SUCCESS;
}
@@ -416,8 +430,8 @@ notify_payload_t *notify_payload_create()
/* public functions */
this->public.get_protocol_id = (u_int8_t (*) (notify_payload_t *)) get_protocol_id;
this->public.set_protocol_id = (void (*) (notify_payload_t *,u_int8_t)) set_protocol_id;
- this->public.get_notify_message_type = (notify_message_type_t (*) (notify_payload_t *)) get_notify_message_type;
- this->public.set_notify_message_type = (void (*) (notify_payload_t *,notify_message_type_t)) set_notify_message_type;
+ this->public.get_notify_type = (notify_type_t (*) (notify_payload_t *)) get_notify_type;
+ this->public.set_notify_type = (void (*) (notify_payload_t *,notify_type_t)) set_notify_type;
this->public.get_spi = (u_int32_t (*) (notify_payload_t *)) get_spi;
this->public.set_spi = (void (*) (notify_payload_t *,u_int32_t)) set_spi;
this->public.get_notification_data = (chunk_t (*) (notify_payload_t *)) get_notification_data;
@@ -432,7 +446,7 @@ notify_payload_t *notify_payload_create()
this->next_payload = NO_PAYLOAD;
this->payload_length = NOTIFY_PAYLOAD_HEADER_LENGTH;
this->protocol_id = 0;
- this->notify_message_type = 0;
+ this->notify_type = 0;
this->spi.ptr = NULL;
this->spi.len = 0;
this->spi_size = 0;
@@ -440,17 +454,17 @@ notify_payload_t *notify_payload_create()
this->notification_data.len = 0;
this->logger = logger_manager->get_logger(logger_manager, PAYLOAD);
- return (&(this->public));
+ return &this->public;
}
/*
* Described in header.
*/
-notify_payload_t *notify_payload_create_from_protocol_and_type(protocol_id_t protocol_id, notify_message_type_t notify_message_type)
+notify_payload_t *notify_payload_create_from_protocol_and_type(protocol_id_t protocol_id, notify_type_t notify_type)
{
notify_payload_t *notify = notify_payload_create();
- notify->set_notify_message_type(notify,notify_message_type);
+ notify->set_notify_type(notify,notify_type);
notify->set_protocol_id(notify,protocol_id);
return notify;
diff --git a/src/charon/encoding/payloads/notify_payload.h b/src/charon/encoding/payloads/notify_payload.h
index 2d2e4ba45..660fdcb81 100644
--- a/src/charon/encoding/payloads/notify_payload.h
+++ b/src/charon/encoding/payloads/notify_payload.h
@@ -37,7 +37,7 @@
*/
#define NOTIFY_PAYLOAD_HEADER_LENGTH 8
-typedef enum notify_message_type_t notify_message_type_t;
+typedef enum notify_type_t notify_type_t;
/**
@@ -47,7 +47,7 @@ typedef enum notify_message_type_t notify_message_type_t;
*
* @ingroup payloads
*/
-enum notify_message_type_t {
+enum notify_type_t {
UNSUPPORTED_CRITICAL_PAYLOAD = 1,
INVALID_IKE_SPI = 4,
INVALID_MAJOR_VERSION = 5,
@@ -72,11 +72,11 @@ enum notify_message_type_t {
};
/**
- * String mappings for notify_message_type_t.
+ * String mappings for notify_type_t.
*
* @ingroup payloads
*/
-extern mapping_t notify_message_type_m[];
+extern mapping_t notify_type_m[];
typedef struct notify_payload_t notify_payload_t;
@@ -122,7 +122,7 @@ struct notify_payload_t {
* @param this calling notify_payload_t object
* @return notify message type of this payload
*/
- notify_message_type_t (*get_notify_message_type) (notify_payload_t *this);
+ notify_type_t (*get_notify_type) (notify_payload_t *this);
/**
* @brief Sets notify message type of this payload.
@@ -130,7 +130,7 @@ struct notify_payload_t {
* @param this calling notify_payload_t object
* @param type notify message type to set
*/
- void (*set_notify_message_type) (notify_payload_t *this, notify_message_type_t type);
+ void (*set_notify_type) (notify_payload_t *this, notify_type_t type);
/**
* @brief Returns the currently set spi of this payload.
@@ -193,12 +193,12 @@ notify_payload_t *notify_payload_create(void);
* @brief Creates an notify_payload_t object of specific type for specific protocol id.
*
* @param protocol_id protocol id (IKE, AH or ESP)
- * @param notify_message_type notify type (see notify_message_type_t)
+ * @param type notify type (see notify_type_t)
* @return notify_payload_t object
*
* @ingroup payloads
*/
-notify_payload_t *notify_payload_create_from_protocol_and_type(protocol_id_t protocol_id, notify_message_type_t notify_message_type);
+notify_payload_t *notify_payload_create_from_protocol_and_type(protocol_id_t protocol_id, notify_type_t type);
#endif /*NOTIFY_PAYLOAD_H_*/
diff --git a/src/charon/encoding/payloads/payload.c b/src/charon/encoding/payloads/payload.c
index be58adf8e..13e7515b4 100644
--- a/src/charon/encoding/payloads/payload.c
+++ b/src/charon/encoding/payloads/payload.c
@@ -74,6 +74,37 @@ mapping_t payload_type_m[] = {
};
/*
+ * build the short mappings for payload_type_t
+ */
+mapping_t payload_type_short_m[] = {
+ {NO_PAYLOAD, "--"},
+ {SECURITY_ASSOCIATION, "SA"},
+ {KEY_EXCHANGE, "KE"},
+ {ID_INITIATOR, "IDi"},
+ {ID_RESPONDER, "IDr"},
+ {CERTIFICATE, "CERT"},
+ {CERTIFICATE_REQUEST, "CERTREQ"},
+ {AUTHENTICATION, "AUTH"},
+ {NONCE, "No"},
+ {NOTIFY, "N"},
+ {DELETE, "D"},
+ {VENDOR_ID, "V"},
+ {TRAFFIC_SELECTOR_INITIATOR, "TSi"},
+ {TRAFFIC_SELECTOR_RESPONDER, "TSr"},
+ {ENCRYPTED, "E"},
+ {CONFIGURATION, "CP"},
+ {EXTENSIBLE_AUTHENTICATION, "EAP"},
+ {HEADER, "HDR"},
+ {PROPOSAL_SUBSTRUCTURE, "PROP"},
+ {TRANSFORM_SUBSTRUCTURE, "TRANS"},
+ {TRANSFORM_ATTRIBUTE, "TRANSATTR"},
+ {TRAFFIC_SELECTOR_SUBSTRUCTURE, "TSSUB"},
+ {CONFIGURATION_ATTRIBUTE, "CPATTR"},
+ {UNKNOWN_PAYLOAD, "??"},
+ {MAPPING_END, NULL}
+};
+
+/*
* see header
*/
payload_t *payload_create(payload_type_t type)
diff --git a/src/charon/encoding/payloads/payload.h b/src/charon/encoding/payloads/payload.h
index bc593f618..68e22b31d 100644
--- a/src/charon/encoding/payloads/payload.h
+++ b/src/charon/encoding/payloads/payload.h
@@ -188,6 +188,11 @@ enum payload_type_t{
*/
extern mapping_t payload_type_m[];
+/**
+ * Special string mappings for payload_type_t in a short form.
+ */
+extern mapping_t payload_type_short_m[];
+
typedef struct payload_t payload_t;
diff --git a/src/charon/encoding/payloads/proposal_substructure.c b/src/charon/encoding/payloads/proposal_substructure.c
index f72fbb1c2..e7a4058f2 100644
--- a/src/charon/encoding/payloads/proposal_substructure.c
+++ b/src/charon/encoding/payloads/proposal_substructure.c
@@ -632,15 +632,11 @@ proposal_substructure_t *proposal_substructure_create_from_proposal(proposal_t *
iterator->destroy(iterator);
/* take over general infos */
- this->spi_size = proposal->get_protocol(proposal) == PROTO_IKE ? 8 : 4;
+ this->spi_size = proposal->get_protocol(proposal) == PROTO_IKE ? 0 : 4;
this->spi.len = this->spi_size;
- this->spi.ptr = malloc(this->spi_size);
- if (this->spi_size == 8)
- {
- *((u_int64_t*)this->spi.ptr) = proposal->get_spi(proposal);
- }
- else
+ if (this->spi_size == 4)
{
+ this->spi.ptr = malloc(this->spi_size);
*((u_int32_t*)this->spi.ptr) = proposal->get_spi(proposal);
}
this->proposal_number = 0;
diff --git a/src/charon/encoding/payloads/sa_payload.c b/src/charon/encoding/payloads/sa_payload.c
index 0c752b81f..8e5022dd6 100644
--- a/src/charon/encoding/payloads/sa_payload.c
+++ b/src/charon/encoding/payloads/sa_payload.c
@@ -303,7 +303,7 @@ static linked_list_t *get_proposals(private_sa_payload_t *this)
if (ignore_struct_number < struct_number)
{
/* remova an already added, if first of series */
- proposal_list->remove_last(proposal_list, (void**)proposal);
+ proposal_list->remove_last(proposal_list, (void**)&proposal);
proposal->destroy(proposal);
ignore_struct_number = struct_number;
}
diff --git a/src/charon/network/interfaces.c b/src/charon/network/interfaces.c
index ce0141849..7578d579c 100644
--- a/src/charon/network/interfaces.c
+++ b/src/charon/network/interfaces.c
@@ -50,11 +50,11 @@ struct private_interfaces_t {
};
/**
- * Implements interfaces_t.get_addresses
+ * Implements interfaces_t.create_address_iterator
*/
-static linked_list_t* get_addresses(private_interfaces_t *this)
+static iterator_t* create_address_iterator(private_interfaces_t *this)
{
- return this->addresses;
+ return this->addresses->create_iterator(this->addresses, TRUE);
}
/**
@@ -138,7 +138,7 @@ interfaces_t *interfaces_create(u_int16_t port)
this->port = port;
- this->public.get_addresses = (linked_list_t* (*) (interfaces_t*)) get_addresses;
+ this->public.create_address_iterator = (iterator_t* (*) (interfaces_t*)) create_address_iterator;
this->public.is_local_address = (bool (*) (interfaces_t*, host_t*)) is_local_address;
this->public.destroy = (void (*) (interfaces_t*)) destroy;
diff --git a/src/charon/network/interfaces.h b/src/charon/network/interfaces.h
index 6500460cf..33143e07c 100644
--- a/src/charon/network/interfaces.h
+++ b/src/charon/network/interfaces.h
@@ -41,12 +41,12 @@ typedef struct interfaces_t interfaces_t;
struct interfaces_t {
/**
- * @brief Get addresses of local interfaces
+ * @brief Get an iterator over addresses of local interfaces
*
* @param this calling object
- * @return linked_list_t of host_t objects
+ * @return iterator over host_t objects
*/
- linked_list_t* (*get_addresses) (interfaces_t *ifaces);
+ iterator_t* (*create_address_iterator) (interfaces_t *this);
/**
* @brief Check if address is associated with a local interface
@@ -55,7 +55,7 @@ struct interfaces_t {
* @param host address to set as destination
* @return TRUE if address is associated with a local interface, FALSE otherwise
*/
- bool (*is_local_address) (interfaces_t *ifaces, host_t *host);
+ bool (*is_local_address) (interfaces_t *this, host_t *host);
/**
* @brief Destroy the object, freeing contained data.
@@ -77,4 +77,4 @@ struct interfaces_t {
interfaces_t *interfaces_create(u_int16_t port);
-#endif /*INTERFACES_H_*/
+#endif /* INTERFACES_H_ */
diff --git a/src/charon/network/socket.c b/src/charon/network/socket.c
index 0d5470c2a..78c793e98 100644
--- a/src/charon/network/socket.c
+++ b/src/charon/network/socket.c
@@ -164,7 +164,7 @@ static status_t receiver(private_socket_t *this, packet_t **packet)
pkt->set_source(pkt, source);
pkt->set_destination(pkt, dest);
- this->logger->log(this->logger, CONTROL, "received packet: from %s:%d to %s:%d",
+ this->logger->log(this->logger, CONTROL|LEVEL1, "received packet: from %s:%d to %s:%d",
source->get_address(source), source->get_port(source),
dest->get_address(dest), dest->get_port(dest));
@@ -202,7 +202,7 @@ status_t sender(private_socket_t *this, packet_t *packet)
dst = packet->get_destination(packet);
data = packet->get_data(packet);
- this->logger->log(this->logger, CONTROL, "sending packet: from %s:%d to %s:%d",
+ this->logger->log(this->logger, CONTROL|LEVEL1, "sending packet: from %s:%d to %s:%d",
src->get_address(src), src->get_port(src),
dst->get_address(dst), dst->get_port(dst));
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 c81783446..864711b4d 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
@@ -60,40 +60,27 @@ static job_type_t get_type(private_delete_half_open_ike_sa_job_t *this)
static status_t execute(private_delete_half_open_ike_sa_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) && (status != CREATED))
+ if (charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id,
+ &ike_sa) != SUCCESS)
{
- this->logger->log(this->logger, CONTROL | LEVEL3, "IKE SA seems to be already deleted");
return DESTROY_ME;
}
switch (ike_sa->get_state(ike_sa))
{
- case INITIATOR_INIT:
- case RESPONDER_INIT:
- case IKE_SA_INIT_REQUESTED:
- case IKE_SA_INIT_RESPONDED:
- case IKE_AUTH_REQUESTED:
- case DELETE_IKE_SA_REQUESTED:
+ case SA_ESTABLISHED:
{
- /* IKE_SA is half open and gets deleted! */
- status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Could not checkin and delete checked out IKE_SA!");
- }
+ /* IKE_SA is established and so is not getting destroyed */
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
return DESTROY_ME;
}
default:
{
- /* IKE_SA is established and so is not getting deleted! */
- status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Could not checkin a checked out IKE_SA!");
- }
+ /* IKE_SA is half open and gets destroyed */
+ this->logger->log(this->logger, AUDIT,
+ "deleting half open IKE_SA after timeout");
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
return DESTROY_ME;
}
}
diff --git a/src/charon/queues/jobs/delete_half_open_ike_sa_job.h b/src/charon/queues/jobs/delete_half_open_ike_sa_job.h
index b26750cc1..ff4f5220d 100644
--- a/src/charon/queues/jobs/delete_half_open_ike_sa_job.h
+++ b/src/charon/queues/jobs/delete_half_open_ike_sa_job.h
@@ -34,7 +34,7 @@ typedef struct delete_half_open_ike_sa_job_t delete_half_open_ike_sa_job_t;
* @brief Class representing an DELETE_HALF_OPEN_IKE_SA Job.
*
* This job is responsible for deleting of half open IKE_SAs. A half
- * open IKE_SA is every IKE_SA which hasn't reache the ike_sa_established
+ * open IKE_SA is every IKE_SA which hasn't reache the SA_ESTABLISHED
* state.
*
* @b Constructors:
@@ -43,6 +43,7 @@ typedef struct delete_half_open_ike_sa_job_t delete_half_open_ike_sa_job_t;
* @ingroup jobs
*/
struct delete_half_open_ike_sa_job_t {
+
/**
* The job_t interface.
*/
@@ -59,4 +60,4 @@ struct delete_half_open_ike_sa_job_t {
*/
delete_half_open_ike_sa_job_t *delete_half_open_ike_sa_job_create(ike_sa_id_t *ike_sa_id);
-#endif /*DELETE_HALF_OPEN_IKE_SA_JOB_H_*/
+#endif /* DELETE_HALF_OPEN_IKE_SA_JOB_H_ */
diff --git a/src/charon/queues/jobs/incoming_packet_job.c b/src/charon/queues/jobs/incoming_packet_job.c
index fbd52b7a6..fa6eb331d 100644
--- a/src/charon/queues/jobs/incoming_packet_job.c
+++ b/src/charon/queues/jobs/incoming_packet_job.c
@@ -57,6 +57,47 @@ static job_type_t get_type(private_incoming_packet_job_t *this)
}
/**
+ * send a notify back to the sender
+ */
+static void send_notify_response(private_incoming_packet_job_t *this,
+ message_t *request,
+ notify_type_t type)
+{
+ notify_payload_t *notify;
+ message_t *response;
+ host_t *src, *dst;
+ packet_t *packet;
+ ike_sa_id_t *ike_sa_id;
+
+ ike_sa_id = request->get_ike_sa_id(request);
+ ike_sa_id = ike_sa_id->clone(ike_sa_id);
+ ike_sa_id->switch_initiator(ike_sa_id);
+
+ response = message_create();
+ dst = request->get_source(request);
+ src = request->get_destination(request);
+ response->set_source(response, src->clone(src));
+ response->set_destination(response, dst->clone(dst));
+ response->set_exchange_type(response, IKE_SA_INIT);
+ response->set_request(response, FALSE);
+ response->set_message_id(response, 0);
+ response->set_ike_sa_id(response, ike_sa_id);
+ notify = notify_payload_create_from_protocol_and_type(PROTO_NONE, type);
+ response->add_payload(response, (payload_t *)notify);
+ if (response->generate(response, NULL, NULL, &packet) != SUCCESS)
+ {
+ response->destroy(response);
+ return;
+ }
+ this->logger->log(this->logger, CONTROL, "sending %s notify",
+ mapping_find(notify_type_m, type));
+ charon->send_queue->add(charon->send_queue, packet);
+ response->destroy(response);
+ ike_sa_id->destroy(ike_sa_id);
+ return;
+}
+
+/**
* Implementation of job_t.execute.
*/
static status_t execute(private_incoming_packet_job_t *this)
@@ -65,104 +106,55 @@ static status_t execute(private_incoming_packet_job_t *this)
ike_sa_t *ike_sa;
ike_sa_id_t *ike_sa_id;
status_t status;
- packet_t *packet;
+ host_t *src, *dst;
message = message_create_from_packet(this->packet->clone(this->packet));
+ src = message->get_source(message);
+ dst = message->get_destination(message);
+ this->logger->log(this->logger, CONTROL, "received packet: from %s:%d to %s:%d",
+ src->get_address(src), src->get_port(src),
+ dst->get_address(dst), dst->get_port(dst));
+
status = message->parse_header(message);
if (status != SUCCESS)
{
- this->logger->log(this->logger, ERROR, "Message header could not be verified!");
+ this->logger->log(this->logger, ERROR, "received message with invalid IKE header, ignored");
message->destroy(message);
return DESTROY_ME;
}
- this->logger->log(this->logger, CONTROL|LEVEL2, "Message is a %s %s",
- mapping_find(exchange_type_m, message->get_exchange_type(message)),
- message->get_request(message) ? "request" : "reply");
-
if ((message->get_major_version(message) != IKE_MAJOR_VERSION) ||
(message->get_minor_version(message) != IKE_MINOR_VERSION))
{
- this->logger->log(this->logger, ERROR | LEVEL2,
- "IKE version %d.%d not supported",
+ this->logger->log(this->logger, ERROR,
+ "received a packet with IKE version %d.%d, not supported",
message->get_major_version(message),
message->get_minor_version(message));
if ((message->get_exchange_type(message) == IKE_SA_INIT) && (message->get_request(message)))
{
- notify_payload_t *notify;
- message_t *response;
- host_t *src, *dst;
-
- message->get_ike_sa_id(message, &ike_sa_id);
- ike_sa_id->switch_initiator(ike_sa_id);
-
- response = message_create();
- src = message->get_source(message);
- dst = message->get_destination(message);
- response->set_source(response, src->clone(src));
- response->set_destination(response, dst->clone(dst));
- response->set_exchange_type(response, IKE_SA_INIT);
- response->set_request(response, FALSE);
- response->set_message_id(response, 0);
- response->set_ike_sa_id(response, ike_sa_id);
-
- notify = notify_payload_create_from_protocol_and_type(PROTO_NONE, INVALID_MAJOR_VERSION);
- response->add_payload(response, (payload_t *)notify);
-
- status = response->generate(response, NULL, NULL, &packet);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Could not generate packet from message");
- response->destroy(response);
- return DESTROY_ME;
- }
- this->logger->log(this->logger, ERROR, "Send notify reply of type INVALID_MAJOR_VERSION");
- charon->send_queue->add(charon->send_queue, packet);
- response->destroy(response);
- return DESTROY_ME;
+ send_notify_response(this, message, INVALID_MAJOR_VERSION);
}
message->destroy(message);
return DESTROY_ME;
}
- message->get_ike_sa_id(message, &ike_sa_id);
+ 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);
- this->logger->log(this->logger, CONTROL|LEVEL3, "Checking out IKE SA %lld:%lld, role %s",
- 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");
-
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id, &ike_sa);
- if ((status != SUCCESS) && (status != CREATED))
+ if (status != SUCCESS)
{
- this->logger->log(this->logger, ERROR, "IKE SA could not be checked out");
+ this->logger->log(this->logger, ERROR,
+ "received packet with SPIs %llx:%llx, but no such IKE_SA",
+ ike_sa_id->get_initiator_spi(ike_sa_id),
+ ike_sa_id->get_responder_spi(ike_sa_id));
+ send_notify_response(this, message, INVALID_IKE_SPI);
ike_sa_id->destroy(ike_sa_id);
message->destroy(message);
-
- /* TODO: send notify reply of type INVALID_IKE_SPI if SPI could not be found ? */
return DESTROY_ME;
}
-
- if (status == CREATED)
- {
- job_t *delete_job;
- this->logger->log(this->logger, CONTROL|LEVEL3,
- "Create Job to delete half open IKE_SA.");
-
- delete_job = (job_t *) delete_half_open_ike_sa_job_create(ike_sa_id);
- charon->event_queue->add_relative(charon->event_queue, delete_job,
- charon->configuration->get_half_open_ike_sa_timeout(charon->configuration));
- }
status = ike_sa->process_message(ike_sa, message);
-
- this->logger->log(this->logger, CONTROL|LEVEL3, "%s IKE SA %lld:%lld, role %s",
- status == DESTROY_ME ? "Checkin and delete" : "Checkin",
- 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);
-
if (status == DESTROY_ME)
{
status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
@@ -171,11 +163,7 @@ static status_t execute(private_incoming_packet_job_t *this)
{
status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
-
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!");
- }
+ ike_sa_id->destroy(ike_sa_id);
message->destroy(message);
return DESTROY_ME;
}
diff --git a/src/charon/queues/jobs/initiate_ike_sa_job.c b/src/charon/queues/jobs/initiate_ike_sa_job.c
index 16e440768..6c1d7bf9a 100644
--- a/src/charon/queues/jobs/initiate_ike_sa_job.c
+++ b/src/charon/queues/jobs/initiate_ike_sa_job.c
@@ -63,41 +63,28 @@ static job_type_t get_type(private_initiate_ike_sa_job_t *this)
*/
static status_t execute(private_initiate_ike_sa_job_t *this)
{
- /*
- * Initiatie an IKE_SA:
- * - is defined by a name of a configuration
- * - create an empty IKE_SA via manager
- * - call initiate_connection on this sa
- */
+ /* 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;
- job_t *delete_job;
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);
- status = ike_sa->initiate_connection(ike_sa, this->connection->clone(this->connection));
+ status = ike_sa->initiate(ike_sa, this->connection->clone(this->connection));
if (status != SUCCESS)
{
- this->logger->log(this->logger, ERROR, "Initiation returned %s, going to delete IKE_SA.",
- mapping_find(status_m, status));
+ this->logger->log(this->logger, ERROR,
+ "initiation returned %s, going to delete IKE_SA.",
+ mapping_find(status_m, status));
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
return DESTROY_ME;
}
- this->logger->log(this->logger, CONTROL|LEVEL3, "Create Job to delete half open IKE_SA.");
-
- delete_job = (job_t *) delete_half_open_ike_sa_job_create(ike_sa->get_id(ike_sa));
- charon->event_queue->add_relative(charon->event_queue, delete_job,
- charon->configuration->get_half_open_ike_sa_timeout(charon->configuration));
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "Checking in IKE SA");
- status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Could not checkin IKE_SA (%s)",
- mapping_find(status_m, status));
- }
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
return DESTROY_ME;
}
diff --git a/src/charon/queues/jobs/retransmit_request_job.c b/src/charon/queues/jobs/retransmit_request_job.c
index 40f2ffd94..7c2d742dc 100644
--- a/src/charon/queues/jobs/retransmit_request_job.c
+++ b/src/charon/queues/jobs/retransmit_request_job.c
@@ -46,11 +46,6 @@ struct private_retransmit_request_job_t {
ike_sa_id_t *ike_sa_id;
/**
- * Number of times a request was retransmitted
- */
- u_int32_t retransmit_count;
-
- /**
* Logger reference
*/
logger_t *logger;
@@ -69,79 +64,27 @@ static job_type_t get_type(private_retransmit_request_job_t *this)
*/
static status_t execute(private_retransmit_request_job_t *this)
{
- bool stop_retransmitting = FALSE, timed_out = FALSE;
- u_int32_t timeout;
ike_sa_t *ike_sa;
status_t status;
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s",
- this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
- this->ike_sa_id->get_responder_spi(this->ike_sa_id),
- this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id, &ike_sa);
- if ((status != SUCCESS) && (status != CREATED))
+ if (status != SUCCESS)
{
this->logger->log(this->logger, ERROR|LEVEL1,
"IKE SA could not be checked out. Already deleted?");
return DESTROY_ME;
}
- this->retransmit_count++;
- status = charon->configuration->get_retransmit_timeout(charon->configuration,
- this->retransmit_count, &timeout);
- timed_out = (status != SUCCESS);
-
- if (ike_sa->retransmit_possible(ike_sa, this->message_id))
+ if (ike_sa->retransmit_request(ike_sa, this->message_id) == DESTROY_ME)
{
- if (!timed_out)
- {
- status = ike_sa->retransmit_request(ike_sa, this->message_id);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, CONTROL|LEVEL3,
- "Message doesn't have to be retransmitted");
- stop_retransmitting = TRUE;
- }
- }
+ /* retransmission hopeless, kill SA */
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
}
else
{
- stop_retransmitting = TRUE;
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "Checkin IKE SA %lld:%lld, role %s",
- this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
- this->ike_sa_id->get_responder_spi(this->ike_sa_id),
- this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
-
- status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!");
- }
-
- if (timed_out)
- {
- /*
- * XXX: We should act depending on DPD policy here, or not act at all.
- */
- this->logger->log(this->logger, CONTROL|LEVEL2, "Timeout: Deleting SA!");
- status = charon->ike_sa_manager->delete(charon->ike_sa_manager, this->ike_sa_id);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR|LEVEL1, "Cannot delete SA!");
- }
- return DESTROY_ME;
- }
-
- if (stop_retransmitting)
- {
- return DESTROY_ME;
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
-
- charon->event_queue->add_relative(charon->event_queue, (job_t *)this, timeout);
- return SUCCESS;
+ return DESTROY_ME;
}
/**
@@ -167,7 +110,6 @@ retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,ike
/* private variables */
this->message_id = message_id;
- this->retransmit_count = 0;
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
this->logger = logger_manager->get_logger(logger_manager, WORKER);
diff --git a/src/charon/queues/jobs/send_dpd_job.c b/src/charon/queues/jobs/send_dpd_job.c
index 3c38110b0..56b1fac0d 100644
--- a/src/charon/queues/jobs/send_dpd_job.c
+++ b/src/charon/queues/jobs/send_dpd_job.c
@@ -66,58 +66,23 @@ static status_t execute(private_send_dpd_job_t *this)
{
ike_sa_t *ike_sa;
status_t status;
- u_int32_t dt;
- u_int32_t interval = charon->configuration->get_dpd_interval(charon->configuration);
- struct timeval last_msg_tv, current_tv;
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s",
- this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
- this->ike_sa_id->get_responder_spi(this->ike_sa_id),
- this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
- this->ike_sa_id, &ike_sa);
+ this->ike_sa_id, &ike_sa);
if (status != SUCCESS)
{
- this->logger->log(this->logger, ERROR|LEVEL1,
- "IKE SA could not be checked out. Already deleted?");
return DESTROY_ME;
}
-
- last_msg_tv = ike_sa->get_last_traffic_in_tv(ike_sa);
- if (0 > gettimeofday(&current_tv, NULL) )
- {
- this->logger->log(this->logger, ERROR|LEVEL1,
- "Warning: Failed to get time of day.");
- }
- dt = (current_tv.tv_sec - last_msg_tv.tv_sec) * 1000
- + (current_tv.tv_usec - last_msg_tv.tv_usec) / 1000;
-
- if (dt >= interval)
+ status = ike_sa->send_dpd(ike_sa);
+ if (status == DESTROY_ME)
{
- ike_sa->send_dpd_request(ike_sa);
- this->logger->log(this->logger, CONTROL|LEVEL1,
- "DPD request packet scheduled");
-
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
}
else
{
- charon->event_queue->add_relative(charon->event_queue, (job_t*) this, interval - dt);
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
-
- this->logger->log(this->logger, CONTROL|LEVEL2,
- "Checkin IKE SA %lld:%lld, role %s",
- this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
- this->ike_sa_id->get_responder_spi(this->ike_sa_id),
- this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
-
- status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!");
- }
-
- return SUCCESS;
+ return DESTROY_ME;
}
/**
diff --git a/src/charon/queues/jobs/send_keepalive_job.c b/src/charon/queues/jobs/send_keepalive_job.c
index f17296af6..6c7dceb3e 100644
--- a/src/charon/queues/jobs/send_keepalive_job.c
+++ b/src/charon/queues/jobs/send_keepalive_job.c
@@ -60,74 +60,22 @@ static job_type_t get_type(private_send_keepalive_job_t *this)
}
/**
- * Implementation of job_t.execute.
+ * Implementation of job_t.execute.
*/
static status_t execute(private_send_keepalive_job_t *this)
{
ike_sa_t *ike_sa;
status_t status;
- u_int32_t dt;
- u_int32_t interval = charon->configuration->get_keepalive_interval(charon->configuration);
- struct timeval last_msg_tv, current_tv;
- packet_t *packet;
- host_t *host;
- connection_t *connection;
- chunk_t data;
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s",
- this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
- this->ike_sa_id->get_responder_spi(this->ike_sa_id),
- this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
- this->ike_sa_id, &ike_sa);
+ this->ike_sa_id, &ike_sa);
if (status != SUCCESS)
{
- this->logger->log(this->logger, ERROR|LEVEL1,
- "IKE SA could not be checked out. Already deleted?");
return DESTROY_ME;
}
-
- last_msg_tv = ike_sa->get_last_traffic_out_tv(ike_sa);
- if (0 > gettimeofday(&current_tv, NULL) )
- {
- this->logger->log(this->logger, ERROR|LEVEL1,
- "Warning: Failed to get time of day.");
- }
- dt = (current_tv.tv_sec - last_msg_tv.tv_sec) * 1000
- + (current_tv.tv_usec - last_msg_tv.tv_usec) / 1000;
-
- if (dt >= interval)
- {
- packet = packet_create();
- connection = ike_sa->get_connection(ike_sa);
- host = connection->get_my_host(connection);
- packet->set_source(packet, host->clone(host));
- host = connection->get_other_host(connection);
- packet->set_destination(packet, host->clone(host));
- data = chunk_alloc(1);
- data.ptr[0] = 0xFF;
- packet->set_data(packet, data);
- charon->send_queue->add(charon->send_queue, packet);
- dt = 0;
- this->logger->log(this->logger, CONTROL|LEVEL1,
- "NAT keepalive packet scheduled");
- }
- charon->event_queue->add_relative(charon->event_queue, (job_t*) this, interval - dt);
-
- this->logger->log(this->logger, CONTROL|LEVEL2,
- "Checkin IKE SA %lld:%lld, role %s",
- this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
- this->ike_sa_id->get_responder_spi(this->ike_sa_id),
- this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
-
- status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!");
- }
-
- return SUCCESS;
+ ike_sa->send_keepalive(ike_sa);
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ return DESTROY_ME;
}
/**
diff --git a/src/charon/queues/send_queue.c b/src/charon/queues/send_queue.c
index 6a55d96ab..f3a6b0f12 100644
--- a/src/charon/queues/send_queue.c
+++ b/src/charon/queues/send_queue.c
@@ -25,6 +25,7 @@
#include "send_queue.h"
#include <utils/linked_list.h>
+#include <utils/logger_manager.h>
typedef struct private_send_queue_t private_send_queue_t;
@@ -54,8 +55,12 @@ struct private_send_queue_t {
* This condvar is used to wake up such a thread
*/
pthread_cond_t condvar;
-};
+ /**
+ * Logger reference
+ */
+ logger_t *logger;
+};
/**
* implements send_queue_t.get_count
@@ -100,6 +105,14 @@ static packet_t *get(private_send_queue_t *this)
*/
static void add(private_send_queue_t *this, packet_t *packet)
{
+ host_t *src, *dst;
+
+ src = packet->get_source(packet);
+ dst = packet->get_destination(packet);
+ this->logger->log(this->logger, CONTROL, "sending packet: from %s:%d to %s:%d",
+ src->get_address(src), src->get_port(src),
+ dst->get_address(dst), dst->get_port(dst));
+
pthread_mutex_lock(&(this->mutex));
this->list->insert_last(this->list,packet);
pthread_cond_signal( &(this->condvar));
@@ -148,6 +161,7 @@ send_queue_t *send_queue_create(void)
this->list = linked_list_create();
pthread_mutex_init(&(this->mutex), NULL);
pthread_cond_init(&(this->condvar), NULL);
+ this->logger = logger_manager->get_logger(logger_manager, SOCKET);
return (&this->public);
}
diff --git a/src/charon/sa/authenticator.c b/src/charon/sa/authenticator.c
index aefd1e941..029dd8ea9 100644
--- a/src/charon/sa/authenticator.c
+++ b/src/charon/sa/authenticator.c
@@ -47,7 +47,7 @@ struct private_authenticator_t {
/**
* Assigned IKE_SA. Needed to get objects of type prf_t and logger_t.
*/
- protected_ike_sa_t *ike_sa;
+ ike_sa_t *ike_sa;
/**
* PRF taken from the IKE_SA.
@@ -404,7 +404,7 @@ static void destroy (private_authenticator_t *this)
/*
* Described in header.
*/
-authenticator_t *authenticator_create(protected_ike_sa_t *ike_sa)
+authenticator_t *authenticator_create(ike_sa_t *ike_sa)
{
private_authenticator_t *this = malloc_thing(private_authenticator_t);
diff --git a/src/charon/sa/authenticator.h b/src/charon/sa/authenticator.h
index b6bc317ac..143cdb6fd 100644
--- a/src/charon/sa/authenticator.h
+++ b/src/charon/sa/authenticator.h
@@ -120,19 +120,12 @@ struct authenticator_t {
/**
* @brief Creates an authenticator object.
*
- * @warning: The following functions of the assigned protected_ike_sa_t object
- * must return a valid value:
- * - protected_ike_sa_t.get_policy
- * - protected_ike_sa_t.get_prf
- * - protected_ike_sa_t.get_logger
- * This preconditions are not given in IKE_SA states INITIATOR_INIT or RESPONDER_INIT!
- *
- * @param ike_sa object of type protected_ike_sa_t
+ * @param ike_sa associated ike_sa
*
* @return authenticator_t object
*
* @ingroup sa
*/
-authenticator_t *authenticator_create(protected_ike_sa_t *ike_sa);
+authenticator_t *authenticator_create(ike_sa_t *ike_sa);
#endif /* AUTHENTICATOR_H_ */
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c
index 895c9676e..5ff67be9a 100644
--- a/src/charon/sa/child_sa.c
+++ b/src/charon/sa/child_sa.c
@@ -858,6 +858,7 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add;
this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update;
+ this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,int,int))update_hosts;
this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
this->public.set_rekeyed = (void (*)(child_sa_t*))set_rekeyed;
diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c
index 4bff80846..863a32994 100644
--- a/src/charon/sa/ike_sa.c
+++ b/src/charon/sa/ike_sa.c
@@ -31,7 +31,6 @@
#include <definitions.h>
#include <utils/linked_list.h>
#include <utils/logger_manager.h>
-#include <utils/randomizer.h>
#include <crypto/diffie_hellman.h>
#include <crypto/prf_plus.h>
#include <crypto/crypters/crypter.h>
@@ -43,16 +42,27 @@
#include <encoding/payloads/transform_substructure.h>
#include <encoding/payloads/transform_attribute.h>
#include <encoding/payloads/ts_payload.h>
-#include <sa/states/initiator_init.h>
-#include <sa/states/responder_init.h>
-#include <sa/states/create_child_sa_requested.h>
-#include <sa/states/delete_child_sa_requested.h>
-#include <sa/states/delete_ike_sa_requested.h>
+#include <sa/transactions/transaction.h>
+#include <sa/transactions/ike_sa_init.h>
+#include <sa/transactions/delete_ike_sa.h>
+#include <sa/transactions/dead_peer_detection.h>
#include <queues/jobs/retransmit_request_job.h>
#include <queues/jobs/delete_established_ike_sa_job.h>
#include <queues/jobs/delete_half_open_ike_sa_job.h>
+#include <queues/jobs/send_dpd_job.h>
+#include <queues/jobs/send_keepalive_job.h>
+/**
+ * String mappings for ike_sa_state_t.
+ */
+mapping_t ike_sa_state_m[] = {
+ {SA_CREATED, "CREATED"},
+ {SA_CONNECTING, "CONNECTING"},
+ {SA_ESTABLISHED, "ESTABLISHED"},
+ {SA_DELETING, "DELETING"},
+ {MAPPING_END, NULL}
+};
typedef struct private_ike_sa_t private_ike_sa_t;
@@ -63,19 +73,9 @@ typedef struct private_ike_sa_t private_ike_sa_t;
struct private_ike_sa_t {
/**
- * Protected part of a ike_sa_t object.
+ * Public members
*/
- protected_ike_sa_t protected;
-
- /**
- * Update a timestamp on ike traffic
- */
- void (*update_timestamp)(private_ike_sa_t *this, bool in);
-
- /**
- * Returns the time since last traffic on kernel policies
- */
- struct timeval (*get_last_esp_traffic_tv)(private_ike_sa_t * this, bool inbound);
+ ike_sa_t public;
/**
* Identifier for the current IKE_SA.
@@ -88,18 +88,9 @@ struct private_ike_sa_t {
linked_list_t *child_sas;
/**
- * Current state of the IKE_SA represented as state_t object.
- *
- * A state object representates one of the following states and is processing
- * messages in the specific state:
- * - INITIATOR_INIT
- * - RESPONDER_INIT
- * - IKE_SA_INIT_REQUESTED
- * - IKE_SA_INIT_RESPONDED
- * - IKE_AUTH_REQUESTED
- * -IKE_SA_ESTABLISHED
+ * Current state of the IKE_SA
*/
- state_t *current_state;
+ ike_sa_state_t state;
/**
* Connection definition used for this IKE_SA
@@ -112,41 +103,24 @@ struct private_ike_sa_t {
policy_t *policy;
/**
- * This SA's source for random data.
- *
- * Is available in every state.
- */
- randomizer_t *randomizer;
-
- /**
- * The last responded message.
- */
- message_t *last_responded_message;
-
- /**
- * The ast requested message.
- */
- message_t *last_requested_message;
-
- /**
- * Crypter object for initiator.
+ * crypter for inbound traffic
*/
- crypter_t *crypter_initiator;
+ crypter_t *crypter_in;
/**
- * Crypter object for responder.
+ * crypter for outbound traffic
*/
- crypter_t *crypter_responder;
+ crypter_t *crypter_out;
/**
- * Signer object for initiator.
+ * Signer for inbound traffic
*/
- signer_t *signer_initiator;
+ signer_t *signer_in;
/**
- * Signer object for responder.
+ * Signer for outbound traffic
*/
- signer_t *signer_responder;
+ signer_t *signer_out;
/**
* Multi purpose prf, set key, use it, forget it
@@ -167,21 +141,6 @@ struct private_ike_sa_t {
* PRF, with key set to pr_key, used for authentication
*/
prf_t *prf_auth_r;
-
- /**
- * Next message id to receive.
- */
- u_int32_t message_id_in;
-
- /**
- * Next message id to send.
- */
- u_int32_t message_id_out;
-
- /**
- * Last reply id which was successfully received.
- */
- int32_t last_replied_message_id;
/**
* A logger for this IKE_SA.
@@ -202,236 +161,819 @@ struct private_ike_sa_t {
* NAT status of remote host.
*/
bool nat_there;
+
+ /**
+ * message ID for next outgoung request
+ */
+ u_int32_t message_id_out;
/**
* Timestamp of last IKE message received on this SA
*/
- struct timeval last_msg_in_tv;
+ time_t time_inbound;
/**
* Timestamp of last IKE message sent on this SA
*/
- struct timeval last_msg_out_tv;
+ time_t time_outbound;
+
+ /**
+ * List of queued transactions to process
+ */
+ linked_list_t *transaction_queue;
+
+ /**
+ * Transaction currently initiated
+ * (only one supported yet, window size = 1)
+ */
+ transaction_t *transaction_out;
+
+ /**
+ * last transaction initiated by peer processed.
+ * (only one supported yet, window size = 1)
+ * Stored for retransmission.
+ */
+ transaction_t *transaction_in;
+
+ /**
+ * Next incoming transaction expected. Used to
+ * do multi transaction operations.
+ */
+ transaction_t *transaction_in_next;
+};
+
+/**
+ * get the time of the latest traffic processed by the kernel
+ */
+static time_t get_esp_time(private_ike_sa_t* this, bool inbound)
+{
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+ time_t latest = 0, use_time;
+
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ if (child_sa->get_use_time(child_sa, inbound, &use_time) == SUCCESS)
+ {
+ latest = max(latest, use_time);
+ }
+ }
+ iterator->destroy(iterator);
+
+ return latest;
+}
+
+/**
+ * get the time of the latest received traffice
+ */
+static time_t get_time_inbound(private_ike_sa_t *this)
+{
+ return max(this->time_inbound, get_esp_time(this, TRUE));
+}
+/**
+ * get the time of the latest sent traffic
+ */
+static time_t get_time_outbound(private_ike_sa_t *this)
+{
+ return max(this->time_outbound, get_esp_time(this, FALSE));
+}
+
+
+/**
+ * Update connection host, as addresses may change (NAT)
+ */
+static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
+{
/*
- * Message ID of last DPD message
+ * Quoting RFC 4306:
+ *
+ * 2.11. Address and Port Agility
+ *
+ * IKE runs over UDP ports 500 and 4500, and implicitly sets up ESP and
+ * AH associations for the same IP addresses it runs over. The IP
+ * addresses and ports in the outer header are, however, not themselves
+ * cryptographically protected, and IKE is designed to work even through
+ * Network Address Translation (NAT) boxes. An implementation MUST
+ * accept incoming requests even if the source port is not 500 or 4500,
+ * and MUST respond to the address and port from which the request was
+ * received. It MUST specify the address and port at which the request
+ * was received as the source address and port in the response. IKE
+ * functions identically over IPv4 or IPv6.
+ *
+ * [...]
+ *
+ * There are cases where a NAT box decides to remove mappings that
+ * are still alive (for example, the keepalive interval is too long,
+ * or the NAT box is rebooted). To recover in these cases, hosts
+ * that are not behind a NAT SHOULD send all packets (including
+ * retransmission packets) to the IP address and port from the last
+ * valid authenticated packet from the other end (i.e., dynamically
+ * update the address). A host behind a NAT SHOULD NOT do this
+ * because it opens a DoS attack possibility. Any authenticated IKE
+ * packet or any authenticated UDP-encapsulated ESP packet can be
+ * used to detect that the IP address or the port has changed.
*/
- u_int32_t last_dpd_message_id;
-};
+ host_t *old_other = NULL;
+ iterator_t *iterator = NULL;
+ child_sa_t *child_sa = NULL;
+ int my_changes, other_changes;
+
+ my_changes = me->get_differences(me, this->connection->get_my_host(this->connection));
+
+ old_other = this->connection->get_other_host(this->connection);
+ other_changes = other->get_differences(other, old_other);
+
+ if (!my_changes && !other_changes)
+ {
+ return;
+ }
+
+ if (my_changes)
+ {
+ this->connection->update_my_host(this->connection, me->clone(me));
+ }
+
+ if (!this->nat_here)
+ {
+ /* update without restrictions if we are not NATted */
+ if (other_changes)
+ {
+ this->connection->update_other_host(this->connection, other->clone(other));
+ }
+ }
+ else
+ {
+ /* if we are natted, only port may change */
+ if (other_changes & HOST_DIFF_ADDR)
+ {
+ return;
+ }
+ else if (other_changes & HOST_DIFF_PORT)
+ {
+ old_other->set_port(old_other, other->get_port(other));
+ }
+ }
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ child_sa->update_hosts(child_sa,
+ this->connection->get_my_host(this->connection),
+ this->connection->get_other_host(this->connection),
+ my_changes, other_changes);
+ /* TODO: what to do if update fails? Delete CHILD_SA? */
+ }
+ iterator->destroy(iterator);
+}
/**
- * Implementation of protected_ike_sa_t.build_message.
+ * send a request and schedule retransmission
*/
-static void build_message(private_ike_sa_t *this, exchange_type_t type, bool request, message_t **message)
+static status_t transmit_request(private_ike_sa_t *this)
{
- message_t *new_message;
- host_t *me, *other;
+ message_t *request;
+ packet_t *packet;
+ status_t status;
+ retransmit_request_job_t *job;
+ u_int32_t transmitted;
+ u_int32_t timeout;
+ transaction_t *transaction = this->transaction_out;
+ u_int32_t message_id = transaction->get_message_id(transaction);
+
+ transmitted = transaction->requested(transaction);
+ timeout = charon->configuration->get_retransmit_timeout(charon->configuration,
+ transmitted);
+ if (timeout == 0)
+ {
+ this->logger->log(this->logger, ERROR,
+ "giving up after %d retransmits, deleting IKE_SA",
+ transmitted - 1);
+ return DESTROY_ME;
+ }
- me = this->connection->get_my_host(this->connection);
- other = this->connection->get_other_host(this->connection);
+ status = transaction->get_request(transaction, &request);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ /* if we retransmit, the request is already generated */
+ if (transmitted == 0)
+ {
+ status = request->generate(request, this->crypter_out, this->signer_out, &packet);
+ if (status != SUCCESS)
+ {
+ return FAILED;
+ }
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL,
+ "sending retransmit %d for %s request with message ID %d",
+ transmitted,
+ mapping_find(exchange_type_m, request->get_exchange_type(request)),
+ message_id);
+ packet = request->get_packet(request);
+ }
+ /* finally send */
+ charon->send_queue->add(charon->send_queue, packet);
+ this->time_outbound = time(NULL);
+
+ /* schedule retransmission job */
+ job = retransmit_request_job_create(message_id, this->ike_sa_id);
+ charon->event_queue->add_relative(charon->event_queue, (job_t*)job, timeout);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of ike_sa.retransmit_request.
+ */
+static status_t retransmit_request(private_ike_sa_t *this, u_int32_t message_id)
+{
+ if (this->transaction_out == NULL ||
+ this->transaction_out->get_message_id(this->transaction_out) != message_id)
+ {
+ /* no retransmit necessary, transaction did already complete */
+ return SUCCESS;
+ }
+ return transmit_request(this);
+}
- this->logger->log(this->logger, CONTROL|LEVEL2, "build empty message");
- new_message = message_create();
- new_message->set_source(new_message, me->clone(me));
- new_message->set_destination(new_message, other->clone(other));
- new_message->set_exchange_type(new_message, type);
- new_message->set_request(new_message, request);
- new_message->set_message_id(new_message, (request) ? this->message_id_out : this->message_id_in);
- new_message->set_ike_sa_id(new_message, this->ike_sa_id);
+/**
+ * Check for transactions in the queue and initiate the first transaction found.
+ */
+static status_t process_transaction_queue(private_ike_sa_t *this)
+{
+ if (this->transaction_out)
+ {
+ /* already a transaction in progress */
+ return SUCCESS;
+ }
+
+ while (TRUE)
+ {
+ if (this->transaction_queue->remove_first(this->transaction_queue,
+ (void**)&this->transaction_out) != SUCCESS)
+ {
+ /* transaction queue empty */
+ return SUCCESS;
+ }
+ switch (transmit_request(this))
+ {
+ case SUCCESS:
+ return SUCCESS;
+ case DESTROY_ME:
+ /* critical, IKE_SA unusable, destroy immediately */
+ this->logger->log(this->logger, ERROR,
+ "transaction initiaton failed, deleting IKE_SA");
+ return DESTROY_ME;
+ default:
+ /* discard transaction, process next one */
+ this->logger->log(this->logger, ERROR,
+ "transaction initiation failed, discarded");
+ this->transaction_out->destroy(this->transaction_out);
+ this->transaction_out = NULL;
+ /* handle next transaction */
+ continue;
+ }
+ }
+}
- *message = new_message;
+/**
+ * Queue a new transaction and execute the next outstanding transaction
+ */
+static status_t queue_transaction(private_ike_sa_t *this, transaction_t *transaction, bool prefer)
+{
+ /* inject next transaction */
+ if (transaction)
+ {
+ if (prefer)
+ {
+ this->transaction_queue->insert_first(this->transaction_queue, transaction);
+ }
+ else
+ {
+ this->transaction_queue->insert_last(this->transaction_queue, transaction);
+ }
+ }
+ /* process a transaction */
+ return process_transaction_queue(this);
}
/**
- * Implementation of ike_sa_t.get_state.
+ * process an incoming request.
*/
-static ike_sa_state_t get_state(private_ike_sa_t *this)
+static status_t process_request(private_ike_sa_t *this, message_t *request)
{
- return this->current_state->get_state(this->current_state);
+ transaction_t *last, *current = NULL;
+ message_t *response;
+ packet_t *packet;
+ u_int32_t request_mid;
+ status_t status;
+
+ request_mid = request->get_message_id(request);
+ last = this->transaction_in;
+
+ /* check if message ID is correct */
+ if (last)
+ {
+ u_int32_t last_mid = last->get_message_id(last);
+
+ if (last_mid == request_mid)
+ {
+ /* retransmit detected */
+ this->logger->log(this->logger, ERROR,
+ "received retransmitted request for message ID %d, retransmitting response",
+ request_mid);
+ last->get_response(last, request, &response, &this->transaction_in_next);
+ packet = response->get_packet(response);
+ charon->send_queue->add(charon->send_queue, packet);
+ this->time_outbound = time(NULL);
+ return SUCCESS;
+ }
+
+ if (last_mid > request_mid)
+ {
+ /* something seriously wrong here, message id may not decrease */
+ this->logger->log(this->logger, ERROR,
+ "received request with message ID %d, excepted %d, ingored",
+ request_mid, last_mid + 1);
+ return FAILED;
+ }
+ /* we allow jumps in message IDs, as long as they are incremental */
+ if (last_mid + 1 < request_mid)
+ {
+ this->logger->log(this->logger, ERROR,
+ "received request with message ID %d, excepted %d",
+ request_mid, last_mid + 1);
+ }
+ }
+ else
+ {
+ if (request_mid != 0)
+ {
+ /* warn, but allow it */
+ this->logger->log(this->logger, CONTROL,
+ "first received request has message ID %d, excepted 0",
+ request_mid);
+ }
+ }
+
+ /* check if we already have a pre-created transaction for this request */
+ if (this->transaction_in_next)
+ {
+ u_int32_t trans_mid = this->transaction_in_next->get_message_id(this->transaction_in_next);
+
+ /* check message id consistency */
+ if (trans_mid == request_mid)
+ {
+ /* use it */
+ current = this->transaction_in_next;
+ }
+ else
+ {
+ /* discard queued transaction */
+ this->transaction_in_next->destroy(this->transaction_in_next);
+ }
+ this->transaction_in_next = NULL;
+ }
+ /* create new transaction if "next" unusable */
+ if (current == NULL)
+ {
+ current = transaction_create(&this->public, request);
+ if (current == NULL)
+ {
+ this->logger->log(this->logger, ERROR,
+ "no idea how to handle received message (%d), ignored",
+ request->get_exchange_type(request));
+ return FAILED;
+ }
+ }
+
+ /* send message. get_request() always gives a valid response */
+ status = current->get_response(current, request, &response, &this->transaction_in_next);
+ if (response->generate(response, this->crypter_out, this->signer_out, &packet) != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR,
+ "response generation failed, discarding transaction");
+ current->destroy(current);
+ return FAILED;
+ }
+
+ charon->send_queue->add(charon->send_queue, packet);
+ this->time_outbound = time(NULL);
+ /* act depending on transaction result */
+ switch (status)
+ {
+ case DESTROY_ME:
+ /* transactions says we should destroy the IKE_SA, so do it */
+ current->destroy(current);
+ return DESTROY_ME;
+ default:
+ /* store for retransmission, destroy old transaction */
+ this->transaction_in = current;
+ if (last)
+ {
+ last->destroy(last);
+ }
+ return SUCCESS;
+ }
}
+
+/**
+ * process an incoming response
+ */
+static status_t process_response(private_ike_sa_t *this, message_t *response)
+{
+ transaction_t *current, *new = NULL;
+ current = this->transaction_out;
+ /* check if message ID is that of our currently active transaction */
+ if (current == NULL ||
+ current->get_message_id(current) !=
+ response->get_message_id(response))
+ {
+ this->logger->log(this->logger, ERROR,
+ "received response with message ID %d not requested, ignored");
+ return FAILED;
+ }
+
+ switch (current->conclude(current, response, &new))
+ {
+ case DESTROY_ME:
+ /* state requested to destroy IKE_SA */
+ return DESTROY_ME;
+ default:
+ /* discard transaction, process next one */
+ break;
+ }
+ /* transaction comleted, remove */
+ current->destroy(current);
+ this->transaction_out = NULL;
+
+ /* queue new transaction */
+ return queue_transaction(this, new, TRUE);
+}
+
/**
- * Implementation of protected_ike_sa_t.set_new_state.
+ * send a notify back to the sender
*/
-static void set_new_state(private_ike_sa_t *this, state_t *state)
+static void send_notify_response(private_ike_sa_t *this,
+ message_t *request,
+ notify_type_t type)
{
- this->logger->log(this->logger, CONTROL, "state change: %s => %s",
- mapping_find(ike_sa_state_m, get_state(this)),
- mapping_find(ike_sa_state_m, state->get_state(state)));
- this->current_state = state;
+ notify_payload_t *notify;
+ message_t *response;
+ host_t *src, *dst;
+ packet_t *packet;
+
+ response = message_create();
+ dst = request->get_source(request);
+ src = request->get_destination(request);
+ response->set_source(response, src->clone(src));
+ response->set_destination(response, dst->clone(dst));
+ response->set_exchange_type(response, request->get_exchange_type(request));
+ response->set_request(response, FALSE);
+ response->set_message_id(response, request->get_message_id(request));
+ response->set_ike_sa_id(response, this->ike_sa_id);
+ notify = notify_payload_create_from_protocol_and_type(PROTO_NONE, type);
+ response->add_payload(response, (payload_t *)notify);
+ if (response->generate(response, this->crypter_out, this->signer_out, &packet) != SUCCESS)
+ {
+ response->destroy(response);
+ return;
+ }
+ charon->send_queue->add(charon->send_queue, packet);
+ this->time_outbound = time(NULL);
+ response->destroy(response);
+ return;
}
+
/**
- * Implementation of protected_ike_sa_t.get_connection.
+ * Implementation of ike_sa_t.process_message.
*/
-static connection_t *get_connection(private_ike_sa_t *this)
+static status_t process_message(private_ike_sa_t *this, message_t *message)
{
- return this->connection;
+ status_t status;
+ bool is_request;
+
+ is_request = message->get_request(message);
+
+ status = message->parse_body(message, this->crypter_in, this->signer_in);
+ if (status != SUCCESS)
+ {
+ switch (status)
+ {
+ case NOT_SUPPORTED:
+ this->logger->log(this->logger, ERROR,
+ "ciritcal unknown payloads found");
+ if (is_request)
+ {
+ send_notify_response(this, message, UNSUPPORTED_CRITICAL_PAYLOAD);
+ }
+ break;
+ case PARSE_ERROR:
+ this->logger->log(this->logger, ERROR,
+ "message parsing failed");
+ if (is_request)
+ {
+ send_notify_response(this, message, INVALID_SYNTAX);
+ }
+ break;
+ case VERIFY_ERROR:
+ this->logger->log(this->logger, ERROR,
+ "message verification failed");
+ if (is_request)
+ {
+ send_notify_response(this, message, INVALID_SYNTAX);
+ }
+ break;
+ case FAILED:
+ this->logger->log(this->logger, ERROR,
+ "integrity check failed");
+ /* ignored */
+ break;
+ case INVALID_STATE:
+ this->logger->log(this->logger, ERROR,
+ "found encrypted message, but no keys available");
+ if (is_request)
+ {
+ send_notify_response(this, message, INVALID_SYNTAX);
+ }
+ default:
+ break;
+ }
+ this->logger->log(this->logger, ERROR,
+ "%s %s with message ID %d processing failed",
+ mapping_find(exchange_type_m, message->get_exchange_type(message)),
+ message->get_request(message) ? "request" : "response",
+ message->get_message_id(message));
+ }
+ else
+ {
+ /* check if message is trustworthy, and update connection information */
+ if ((this->state == SA_CREATED && this->connection) ||
+ message->get_exchange_type(message) != IKE_SA_INIT)
+ {
+ update_hosts(this, message->get_destination(message),
+ message->get_source(message));
+ this->time_inbound = time(NULL);
+ }
+ if (is_request)
+ {
+ status = process_request(this, message);
+ }
+ else
+ {
+ status = process_response(this, message);
+ }
+ }
+ return status;
}
/**
- * Implementation of protected_ike_sa_t.set_connection.
+ * Implementation of ike_sa_t.initiate.
*/
-static void set_connection(private_ike_sa_t *this,connection_t * connection)
+static status_t initiate(private_ike_sa_t *this, connection_t *connection)
{
+ ike_sa_init_t *ike_sa_init;
+
+ /* set connection and policy */
this->connection = connection;
+ this->policy = charon->policies->get_policy_by_name(charon->policies,
+ this->connection->get_name(this->connection));
+ if (this->policy == NULL)
+ {
+ this->logger->log(this->logger, ERROR,
+ "no policy found for connection %s, aborting",
+ connection->get_name(connection));
+ return DESTROY_ME;
+ }
+ ike_sa_init = ike_sa_init_create(&this->public, 0);
+ this->message_id_out = 2;
+ return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE);
}
/**
- * Implementation of protected_ike_sa_t.get_policy.
+ * Implementation of ike_sa_t.send_dpd
*/
-static policy_t *get_policy(private_ike_sa_t *this)
+static status_t send_dpd(private_ike_sa_t *this)
{
- return this->policy;
+ send_dpd_job_t *job;
+ time_t diff, interval;
+ status_t status = SUCCESS;
+
+ interval = charon->configuration->get_dpd_interval(charon->configuration);
+
+ if (this->transaction_out)
+ {
+ /* there is a transaction in progress. Come back later */
+ diff = 0;
+ }
+ else
+ {
+ /* check if there was any inbound traffic */
+ time_t last_in, now;
+ last_in = get_time_inbound(this);
+ now = time(NULL);
+ diff = now - last_in;
+ if (diff >= interval)
+ {
+ /* to long ago, initiate dead peer detection */
+ dead_peer_detection_t *dpd;
+ this->logger->log(this->logger, CONTROL, "sending DPD request");
+ dpd = dead_peer_detection_create(&this->public, this->message_id_out++);
+ status = queue_transaction(this, (transaction_t*)dpd, FALSE);
+ diff = 0;
+ }
+ }
+ /* recheck in "interval" seconds */
+ job = send_dpd_job_create(this->ike_sa_id);
+ charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
+ (interval - diff) * 1000);
+ return SUCCESS;
}
/**
- * Implementation of protected_ike_sa_t.set_policy.
+ * Implementation of ike_sa_t.send_keepalive
*/
-static void set_policy(private_ike_sa_t *this,policy_t * policy)
+static void send_keepalive(private_ike_sa_t *this)
{
- this->policy = policy;
+ send_keepalive_job_t *job;
+ time_t last_out, now, diff, interval;
+
+ last_out = get_time_outbound(this);
+ now = time(NULL);
+
+ diff = now - last_out;
+ interval = charon->configuration->get_keepalive_interval(charon->configuration);
+
+ if (diff >= interval)
+ {
+ host_t *me, *other;
+ packet_t *packet;
+ chunk_t data;
+
+ packet = packet_create();
+ me = this->connection->get_my_host(this->connection);
+ other = this->connection->get_other_host(this->connection);
+ packet->set_source(packet, me->clone(me));
+ packet->set_destination(packet, other->clone(other));
+ data.ptr = malloc(1);
+ data.ptr[0] = 0xFF;
+ data.len = 1;
+ packet->set_data(packet, data);
+ charon->send_queue->add(charon->send_queue, packet);
+ this->logger->log(this->logger, CONTROL, "sending keep alive");
+ diff = 0;
+ }
+ job = send_keepalive_job_create(this->ike_sa_id);
+ charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
+ (interval - diff) * 1000);
}
/**
- * Implementation of protected_ike_sa_t.get_prf.
+ * Implementation of ike_sa_t.get_state.
*/
-static prf_t *get_prf(private_ike_sa_t *this)
+static ike_sa_state_t get_state(private_ike_sa_t *this)
{
- return this->prf;
+ return this->state;
}
/**
- * Implementation of protected_ike_sa_t.get_prf.
+ * Implementation of ike_sa_t.set_state.
*/
-static prf_t *get_child_prf(private_ike_sa_t *this)
+static void set_state(private_ike_sa_t *this, ike_sa_state_t state)
{
- return this->child_prf;
+ this->logger->log(this->logger, CONTROL, "state change: %s => %s",
+ mapping_find(ike_sa_state_m, this->state),
+ mapping_find(ike_sa_state_m, state));
+ if (state == SA_ESTABLISHED)
+ {
+ host_t *my_host, *other_host;
+ identification_t *my_id, *other_id;
+ my_host = this->connection->get_my_host(this->connection);
+ other_host = this->connection->get_other_host(this->connection);
+ my_id = this->policy->get_my_id(this->policy);
+ other_id = this->policy->get_other_id(this->policy);
+ this->logger->log(this->logger, AUDIT, "IKE_SA established: %s[%s]...%s[%s]",
+ my_host->get_address(my_host),
+ my_id->get_string(my_id),
+ other_host->get_address(other_host),
+ other_id->get_string(other_id));
+
+ send_dpd(this);
+ }
+ this->state = state;
}
/**
- * Implementation of protected_ike_sa_t.get_prf_auth_i.
+ * Implementation of protected_ike_sa_t.get_connection.
*/
-static prf_t *get_prf_auth_i(private_ike_sa_t *this)
+static connection_t *get_connection(private_ike_sa_t *this)
{
- return this->prf_auth_i;
+ return this->connection;
}
/**
- * Implementation of protected_ike_sa_t.get_prf_auth_r.
+ * Implementation of protected_ike_sa_t.set_connection.
*/
-static prf_t *get_prf_auth_r(private_ike_sa_t *this)
+static void set_connection(private_ike_sa_t *this,connection_t * connection)
{
- return this->prf_auth_r;
+ this->connection = connection;
}
+
/**
- * Implementation of ike_sa_t.get_id.
+ * Implementation of protected_ike_sa_t.get_policy.
*/
-static ike_sa_id_t* get_id(private_ike_sa_t *this)
+static policy_t *get_policy(private_ike_sa_t *this)
{
- return this->ike_sa_id;
+ return this->policy;
}
/**
- * Implementation of ike_sa_t.get_my_host.
+ * Implementation of protected_ike_sa_t.set_policy.
*/
-static host_t* get_my_host(private_ike_sa_t *this)
+static void set_policy(private_ike_sa_t *this,policy_t * policy)
{
- return this->connection->get_my_host(this->connection);;
+ this->policy = policy;
}
/**
- * Implementation of ike_sa_t.get_other_host.
+ * Implementation of protected_ike_sa_t.get_prf.
*/
-static host_t* get_other_host(private_ike_sa_t *this)
+static prf_t *get_prf(private_ike_sa_t *this)
{
- return this->connection->get_other_host(this->connection);
+ return this->prf;
}
/**
- * Implementation of ike_sa_t.get_my_id.
+ * Implementation of protected_ike_sa_t.get_prf.
*/
-static identification_t* get_my_id(private_ike_sa_t *this)
+static prf_t *get_child_prf(private_ike_sa_t *this)
{
- return this->policy->get_my_id(this->policy);
+ return this->child_prf;
}
/**
- * Implementation of ike_sa_t.get_other_id.
+ * Implementation of protected_ike_sa_t.get_prf_auth_i.
*/
-static identification_t* get_other_id(private_ike_sa_t *this)
+static prf_t *get_prf_auth_i(private_ike_sa_t *this)
{
- return this->policy->get_other_id(this->policy);
+ return this->prf_auth_i;
}
/**
- * Implementation of ike_sa_t.retransmit_possible.
+ * Implementation of protected_ike_sa_t.get_prf_auth_r.
*/
-static bool retransmit_possible(private_ike_sa_t *this, u_int32_t message_id)
+static prf_t *get_prf_auth_r(private_ike_sa_t *this)
{
- return ((this->last_requested_message)
- && (message_id != this->last_replied_message_id)
- && (message_id == this->last_requested_message->get_message_id(
- this->last_requested_message)));
+ return this->prf_auth_r;
}
-
/**
- * Implementation of ike_sa_t.retransmit_request.
+ * Implementation of ike_sa_t.get_id.
*/
-static status_t retransmit_request(private_ike_sa_t *this, u_int32_t message_id)
+static ike_sa_id_t* get_id(private_ike_sa_t *this)
{
- packet_t *packet;
-
- if (!this->protected.public.retransmit_possible(&this->protected.public, message_id))
- {
- return NOT_FOUND;
- }
-
- this->logger->log(this->logger, CONTROL | LEVEL1, "going to retransmit message with id %d",message_id);
- packet = this->last_requested_message->get_packet(this->last_requested_message);
- charon->send_queue->add(charon->send_queue, packet);
- this->update_timestamp(this, FALSE);
- return SUCCESS;
+ return this->ike_sa_id;
}
/**
* Implementation of protected_ike_sa_t.build_transforms.
*/
-static status_t build_transforms(private_ike_sa_t *this, proposal_t *proposal, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
+static status_t build_transforms(private_ike_sa_t *this, proposal_t *proposal,
+ diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r,
+ bool initiator)
{
chunk_t nonces, nonces_spis, skeyseed, key, secret;
u_int64_t spi_i, spi_r;
prf_plus_t *prf_plus;
algorithm_t *algo;
size_t key_size;
+ crypter_t *crypter_i, *crypter_r;
+ signer_t *signer_i, *signer_r;
- /*
- * Build the PRF+ instance for deriving keys
- */
- if (this->prf != NULL)
- {
- this->prf->destroy(this->prf);
- }
+ /* Build the PRF+ instance for deriving keys */
if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo))
{
- this->logger->log(this->logger, ERROR|LEVEL2, "no PRF algoithm selected!?");
+ this->logger->log(this->logger, ERROR, "no PSEUDO_RANDOM_FUNCTION selected!");
return FAILED;
}
this->prf = prf_create(algo->algorithm);
if (this->prf == NULL)
{
- this->logger->log(this->logger, ERROR|LEVEL1,
- "PSEUDO_RANDOM_FUNCTION %s not supported!",
+ this->logger->log(this->logger, ERROR, "PSEUDO_RANDOM_FUNCTION %s not supported!",
mapping_find(pseudo_random_function_m, algo->algorithm));
return FAILED;
}
- /* concatenate nonces = nonce_i | nonce_r */
+ /* nonces = nonce_i | nonce_r */
nonces = chunk_alloc(nonce_i.len + nonce_r.len);
memcpy(nonces.ptr, nonce_i.ptr, nonce_i.len);
memcpy(nonces.ptr + nonce_i.len, nonce_r.ptr, nonce_r.len);
- /* concatenate prf_seed = nonce_i | nonce_r | spi_i | spi_r */
+ /* prf_seed = nonce_i | nonce_r | spi_i | spi_r */
nonces_spis = chunk_alloc(nonces.len + 16);
memcpy(nonces_spis.ptr, nonces.ptr, nonces.len);
spi_i = this->ike_sa_id->get_initiator_spi(this->ike_sa_id);
@@ -441,17 +983,15 @@ static status_t build_transforms(private_ike_sa_t *this, proposal_t *proposal, d
/* SKEYSEED = prf(Ni | Nr, g^ir) */
dh->get_shared_secret(dh, &secret);
- this->logger->log_chunk(this->logger, PRIVATE, "shared Diffie-Hellman secret", secret);
+ this->logger->log_chunk(this->logger, PRIVATE, "shared Diffie Hellman secret", secret);
this->prf->set_key(this->prf, nonces);
this->prf->allocate_bytes(this->prf, secret, &skeyseed);
- this->logger->log_chunk(this->logger, PRIVATE | LEVEL1, "SKEYSEED", skeyseed);
+ this->logger->log_chunk(this->logger, PRIVATE|LEVEL1, "SKEYSEED", skeyseed);
chunk_free(&secret);
/* prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr )
- * = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr
- *
- * we use the prf directly for prf+
- */
+ * = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr
+ */
this->prf->set_key(this->prf, skeyseed);
prf_plus = prf_plus_create(this->prf, nonces_spis);
@@ -460,13 +1000,6 @@ static status_t build_transforms(private_ike_sa_t *this, proposal_t *proposal, d
chunk_free(&nonces_spis);
chunk_free(&skeyseed);
-
- /*
- * We now can derive all of our key. We build the transforms
- * directly.
- */
-
-
/* SK_d used for prf+ to derive keys for child SAs */
this->child_prf = prf_create(algo->algorithm);
key_size = this->child_prf->get_key_size(this->child_prf);
@@ -475,62 +1008,53 @@ static status_t build_transforms(private_ike_sa_t *this, proposal_t *proposal, d
this->child_prf->set_key(this->child_prf, key);
chunk_free(&key);
-
/* SK_ai/SK_ar used for integrity protection */
if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &algo))
{
- this->logger->log(this->logger, ERROR, "no integrity algoithm selected?!");
+ this->logger->log(this->logger, ERROR, "no INTEGRITY_ALGORITHM selected?!");
return FAILED;
}
- if (this->signer_initiator != NULL)
- {
- this->signer_initiator->destroy(this->signer_initiator);
- }
- if (this->signer_responder != NULL)
- {
- this->signer_responder->destroy(this->signer_responder);
- }
- this->signer_initiator = signer_create(algo->algorithm);
- this->signer_responder = signer_create(algo->algorithm);
- if (this->signer_initiator == NULL || this->signer_responder == NULL)
+ signer_i = signer_create(algo->algorithm);
+ signer_r = signer_create(algo->algorithm);
+ if (signer_i == NULL || signer_r == NULL)
{
- this->logger->log(this->logger, ERROR,
- "INTEGRITY_ALGORITHM %s not supported!",
+ this->logger->log(this->logger, ERROR, "INTEGRITY_ALGORITHM %s not supported!",
mapping_find(integrity_algorithm_m,algo->algorithm));
return FAILED;
}
- key_size = this->signer_initiator->get_key_size(this->signer_initiator);
+ key_size = signer_i->get_key_size(signer_i);
prf_plus->allocate_bytes(prf_plus, key_size, &key);
this->logger->log_chunk(this->logger, CONTROL|LEVEL1, "Sk_ai secret", key);
- this->signer_initiator->set_key(this->signer_initiator, key);
+ signer_i->set_key(signer_i, key);
chunk_free(&key);
prf_plus->allocate_bytes(prf_plus, key_size, &key);
this->logger->log_chunk(this->logger, CONTROL|LEVEL1, "Sk_ar secret", key);
- this->signer_responder->set_key(this->signer_responder, key);
+ signer_r->set_key(signer_r, key);
chunk_free(&key);
-
- /* SK_ei/SK_er used for encryption */
- if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &algo))
+ if (initiator)
{
- this->logger->log(this->logger, ERROR, "no encryption algoithm selected!?");
- return FAILED;
+ this->signer_in = signer_i;
+ this->signer_out = signer_r;
}
- if (this->crypter_initiator != NULL)
- {
- this->crypter_initiator->destroy(this->crypter_initiator);
- }
- if (this->crypter_responder != NULL)
+ else
{
- this->crypter_responder->destroy(this->crypter_responder);
+ this->signer_in = signer_r;
+ this->signer_out = signer_i;
}
- this->crypter_initiator = crypter_create(algo->algorithm, algo->key_size / 8);
- this->crypter_responder = crypter_create(algo->algorithm, algo->key_size / 8);
- if (this->crypter_initiator == NULL || this->crypter_responder == NULL)
+ /* SK_ei/SK_er used for encryption */
+ if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &algo))
+ {
+ this->logger->log(this->logger, ERROR, "no ENCRYPTION_ALGORITHM selected!");
+ return FAILED;
+ }
+ crypter_i = crypter_create(algo->algorithm, algo->key_size / 8);
+ crypter_r = crypter_create(algo->algorithm, algo->key_size / 8);
+ if (crypter_i == NULL || crypter_r == NULL)
{
this->logger->log(this->logger, ERROR,
"ENCRYPTION_ALGORITHM %s (key size %d) not supported!",
@@ -538,28 +1062,30 @@ static status_t build_transforms(private_ike_sa_t *this, proposal_t *proposal, d
algo->key_size);
return FAILED;
}
- key_size = this->crypter_initiator->get_key_size(this->crypter_initiator);
+ key_size = crypter_i->get_key_size(crypter_i);
prf_plus->allocate_bytes(prf_plus, key_size, &key);
this->logger->log_chunk(this->logger, PRIVATE, "Sk_ei secret", key);
- this->crypter_initiator->set_key(this->crypter_initiator, key);
+ crypter_i->set_key(crypter_i, key);
chunk_free(&key);
prf_plus->allocate_bytes(prf_plus, key_size, &key);
this->logger->log_chunk(this->logger, PRIVATE, "Sk_er secret", key);
- this->crypter_responder->set_key(this->crypter_responder, key);
+ crypter_r->set_key(crypter_r, key);
chunk_free(&key);
- /* SK_pi/SK_pr used for authentication */
- if (this->prf_auth_i != NULL)
+ if (initiator)
{
- this->prf_auth_i->destroy(this->prf_auth_i);
+ this->crypter_in = crypter_i;
+ this->crypter_out = crypter_r;
}
- if (this->prf_auth_r != NULL)
+ else
{
- this->prf_auth_r->destroy(this->prf_auth_r);
+ this->crypter_in = crypter_r;
+ this->crypter_out = crypter_i;
}
+ /* SK_pi/SK_pr used for authentication */
proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo);
this->prf_auth_i = prf_create(algo->algorithm);
this->prf_auth_r = prf_create(algo->algorithm);
@@ -582,260 +1108,6 @@ static status_t build_transforms(private_ike_sa_t *this, proposal_t *proposal, d
}
/**
- * Implementation of protected_ike_sa_t.get_randomizer.
- */
-static randomizer_t *get_randomizer(private_ike_sa_t *this)
-{
- return this->randomizer;
-}
-
-/**
- * Implementation of protected_ike_sa_t.get_crypter_initiator.
- */
-static crypter_t *get_crypter_initiator(private_ike_sa_t *this)
-{
- return this->crypter_initiator;
-}
-
-/**
- * Implementation of protected_ike_sa_t.get_signer_initiator.
- */
-static signer_t *get_signer_initiator(private_ike_sa_t *this)
-{
- return this->signer_initiator;
-}
-
-/**
- * Implementation of protected_ike_sa_t.get_crypter_responder.
- */
-static crypter_t *get_crypter_responder(private_ike_sa_t *this)
-{
- return this->crypter_responder;
-}
-
-/**
- * Implementation of protected_ike_sa_t.get_signer_responder.
- */
-static signer_t *get_signer_responder(private_ike_sa_t *this)
-{
- return this->signer_responder;
-}
-
-/**
- * Implementation of protected_ike_sa_t.update_timestamp
- */
-static void update_timestamp(private_ike_sa_t *this, bool in)
-{
- /* bump last message sent timestamp */
- struct timeval *tv = in ? &this->last_msg_in_tv : &this->last_msg_out_tv;
- if (0 > gettimeofday(tv, NULL))
- {
- this->logger->log(this->logger, ERROR|LEVEL1,
- "warning: failed to get time of day.");
- }
-}
-
-/**
- * Implementation of protected_ike_sa_t.send_request.
- */
-static status_t send_request(private_ike_sa_t *this, message_t *message)
-{
- retransmit_request_job_t *retransmit_job;
- u_int32_t timeout;
- crypter_t *crypter;
- signer_t *signer;
- packet_t *packet;
- status_t status;
-
- if (message->get_message_id(message) != this->message_id_out)
- {
- this->logger->log(this->logger, ERROR, "message could not be sent cause id (%d) was not as expected (%d)",
- message->get_message_id(message),this->message_id_out);
- return FAILED;
- }
-
- /* generate packet */
- this->logger->log(this->logger, CONTROL|LEVEL2, "generate packet from message");
-
- if (this->ike_sa_id->is_initiator(this->ike_sa_id))
- {
- crypter = this->crypter_initiator;
- signer = this->signer_initiator;
- }
- else
- {
- crypter = this->crypter_responder;
- signer =this->signer_responder;
- }
-
- status = message->generate(message, crypter,signer, &packet);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "could not generate packet from message");
- return FAILED;
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL3,
- "add request packet with message id %d to global send queue",
- this->message_id_out);
- charon->send_queue->add(charon->send_queue, packet);
-
- /* replace last message for retransmit with current */
- if (this->last_requested_message != NULL)
- {
- this->last_requested_message->destroy(this->last_requested_message);
- }
- this->logger->log(this->logger, CONTROL|LEVEL3, "replace last requested message with new one");
- this->last_requested_message = message;
-
- /* schedule a job for retransmission */
- status = charon->configuration->get_retransmit_timeout(charon->configuration, 0, &timeout);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, CONTROL|LEVEL2, "no retransmit job for message created!");
- }
- else
- {
- this->logger->log(this->logger, CONTROL|LEVEL2, "request will be retransmitted in %d ms.", timeout);
- retransmit_job = retransmit_request_job_create(this->message_id_out, this->ike_sa_id);
- charon->event_queue->add_relative(charon->event_queue, (job_t *)retransmit_job, timeout);
- }
-
- /* message counter can now be increased */
- this->logger->log(this->logger, CONTROL|LEVEL3,
- "increase message counter for outgoing messages from %d",
- this->message_id_out);
- this->message_id_out++;
-
- this->update_timestamp(this, FALSE);
- return SUCCESS;
-}
-
-/**
- * Implementation of protected_ike_sa_t.send_response.
- */
-static status_t send_response(private_ike_sa_t *this, message_t *message)
-{
- crypter_t *crypter;
- signer_t *signer;
- packet_t *packet;
- status_t status;
-
- if (message->get_message_id(message) != this->message_id_in)
- {
-
- this->logger->log(this->logger, ERROR, "message could not be sent cause id (%d) was not as expected (%d)",
- message->get_message_id(message),this->message_id_in);
- return FAILED;
- }
-
- if (this->ike_sa_id->is_initiator(this->ike_sa_id))
- {
- crypter = this->crypter_initiator;
- signer = this->signer_initiator;
- }
- else
- {
- crypter = this->crypter_responder;
- signer =this->signer_responder;
- }
-
- status = message->generate(message, crypter,signer, &packet);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "could not generate packet from message");
- return FAILED;
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL3,
- "add response packet with message id %d to global send queue",
- this->message_id_in);
- charon->send_queue->add(charon->send_queue, packet);
-
- if (this->last_responded_message != NULL)
- {
- /* destroy message */
- this->last_responded_message->destroy(this->last_responded_message);
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL3, "replace last responded message with new one");
- this->last_responded_message = message;
-
- /* message counter can now be increased */
- this->logger->log(this->logger, CONTROL|LEVEL3, "increase message counter for incoming messages");
- this->message_id_in++;
-
- this->update_timestamp(this, FALSE);
-
- return SUCCESS;
-}
-
-/**
- * Implementation of of private_responder_init_t.send_notify_reply.
- */
-static void send_notify(private_ike_sa_t *this, exchange_type_t exchange_type, notify_message_type_t type, chunk_t data)
-{
- notify_payload_t *payload;
- message_t *response;
- packet_t *packet;
- status_t status;
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "going to build message with notify payload");
- /* set up the reply */
- build_message(this, exchange_type, FALSE, &response);
- payload = notify_payload_create_from_protocol_and_type(PROTO_NONE, type);
- if ((data.ptr != NULL) && (data.len > 0))
- {
- this->logger->log(this->logger, CONTROL|LEVEL2, "add Data to notify payload");
- payload->set_notification_data(payload,data);
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add Notify payload to message");
- response->add_payload(response,(payload_t *) payload);
-
- /* generate packet */
- this->logger->log(this->logger, CONTROL|LEVEL2, "generate packet from message");
- status = response->generate(response, this->crypter_responder, this->signer_responder, &packet);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR|LEVEL1, "could not generate notify message");
- response->destroy(response);
- return;
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add packet to global send queue");
- charon->send_queue->add(charon->send_queue, packet);
- this->logger->log(this->logger, CONTROL|LEVEL2, "destroy message");
- response->destroy(response);
-
- this->update_timestamp(this, FALSE);
-}
-
-/**
- * Implementation of protected_ike_sa_t.set_last_replied_message_id.
- */
-static void set_last_replied_message_id (private_ike_sa_t *this,u_int32_t message_id)
-{
- this->last_replied_message_id = message_id;
-}
-
-/**
- * Implementation of protected_ike_sa_t.get_last_responded_message.
- */
-static message_t *get_last_responded_message (private_ike_sa_t *this)
-{
- return this->last_responded_message;
-}
-
-/**
- * Implementation of protected_ike_sa_t.get_last_requested_message.
- */
-static message_t *get_last_requested_message(private_ike_sa_t *this)
-{
- return this->last_requested_message;
-}
-
-/**
* Implementation of protected_ike_sa_t.add_child_sa.
*/
static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa)
@@ -844,306 +1116,39 @@ static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa)
}
/**
- * Implementation of ike_sa_t.process_message.
- */
-static status_t process_message(private_ike_sa_t *this, message_t *message)
-{
- u_int32_t message_id;
- exchange_type_t exchange_type;
- bool is_request;
-
- /* 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|LEVEL1, "process %s of exchange type %s",
- (is_request) ? "request" : "response",
- mapping_find(exchange_type_m, exchange_type));
-
- message_id = message->get_message_id(message);
-
- /* check if message already received, and retransmit its reply */
- if (is_request && (message_id == (this->message_id_in - 1)))
- {
- /* resend last message, if any */
- if (this->last_responded_message)
- {
- packet_t *packet = this->last_responded_message->get_packet(this->last_responded_message);
- this->logger->log(this->logger, CONTROL|LEVEL1, "resent request detected. Send stored reply.");
- charon->send_queue->add(charon->send_queue, packet);
- this->update_timestamp(this, FALSE);
- return SUCCESS;
- }
- else
- {
- /* somebody does something nasty here... */
- return FAILED;
- }
- }
-
- /* Now, the message id is checked for request AND reply */
- if (is_request)
- {
- /* In a request, the message has to be this->message_id_in (other case is already handled) */
- if (message_id != this->message_id_in)
- {
- this->logger->log(this->logger, ERROR | LEVEL1,
- "message request with message id %d received, but %d expected",
- message_id,this->message_id_in);
- return FAILED;
- }
- }
- else
- {
- /* In a reply, the message has to be this->message_id_out -1 cause it is the reply to the last sent message*/
- if (message_id != (this->message_id_out - 1))
- {
- this->logger->log(this->logger, ERROR | LEVEL1,
- "message reply with message id %d received, but %d expected",
- message_id,this->message_id_in);
- return FAILED;
- }
- }
-
- this->update_timestamp(this, TRUE);
-
- /* now the message is processed by the current state object.
- * The specific state object is responsible to check if a message can be received in
- * the state it represents.
- * The current state is also responsible to change the state object to the next state
- * by calling protected_ike_sa_t.set_new_state
- */
- return this->current_state->process_message(this->current_state, message);
-}
-
-/**
- * Implementation of protected_ike_sa_t.initiate_connection.
- */
-static status_t initiate_connection(private_ike_sa_t *this, connection_t *connection)
-{
- initiator_init_t *current_state;
-
- /* Work is done in state object of type INITIATOR_INIT. All other states are not
- * initial states and so don't have a initiate_connection function */
-
- if (this->current_state->get_state(this->current_state) != INITIATOR_INIT)
- {
- return FAILED;
- }
-
- current_state = (initiator_init_t *) this->current_state;
-
- return current_state->initiate_connection(current_state, connection);
-}
-
-/**
- * Implementation of protected_ike_sa_t.update_connection_hosts.
- *
- * Quoting RFC 4306:
- *
- * 2.11. Address and Port Agility
- *
- * IKE runs over UDP ports 500 and 4500, and implicitly sets up ESP and
- * AH associations for the same IP addresses it runs over. The IP
- * addresses and ports in the outer header are, however, not themselves
- * cryptographically protected, and IKE is designed to work even through
- * Network Address Translation (NAT) boxes. An implementation MUST
- * accept incoming requests even if the source port is not 500 or 4500,
- * and MUST respond to the address and port from which the request was
- * received. It MUST specify the address and port at which the request
- * was received as the source address and port in the response. IKE
- * functions identically over IPv4 or IPv6.
- *
- * [...]
- *
- * There are cases where a NAT box decides to remove mappings that
- * are still alive (for example, the keepalive interval is too long,
- * or the NAT box is rebooted). To recover in these cases, hosts
- * that are not behind a NAT SHOULD send all packets (including
- * retransmission packets) to the IP address and port from the last
- * valid authenticated packet from the other end (i.e., dynamically
- * update the address). A host behind a NAT SHOULD NOT do this
- * because it opens a DoS attack possibility. Any authenticated IKE
- * packet or any authenticated UDP-encapsulated ESP packet can be
- * used to detect that the IP address or the port has changed.
- */
-static status_t update_connection_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
-{
- host_t *old_other = NULL;
- iterator_t *iterator = NULL;
- child_sa_t *child_sa = NULL;
- int my_changes, other_changes;
- ike_sa_state_t s;
-
- my_changes = me->get_differences(me, this->connection->get_my_host(this->connection));
-
- old_other = this->connection->get_other_host(this->connection);
- other_changes = other->get_differences(other, old_other);
-
- if (!my_changes && !other_changes) {
- return SUCCESS;
- }
-
- if (my_changes)
- {
- this->connection->update_my_host(this->connection, me->clone(me));
- }
-
- s = this->protected.public.get_state(&this->protected.public);
-
- if (s == RESPONDER_INIT || s == IKE_SA_INIT_REQUESTED || !this->nat_here)
- {
- if (other_changes)
- {
- this->connection->update_other_host(this->connection, other->clone(other));
- }
- }
- else
- {
- if (other_changes & HOST_DIFF_ADDR)
- {
- this->logger->log(this->logger, ERROR|LEVEL1,
- "destination ip changed from %s to %s. As we are NATed this is not allowed!",
- old_other->get_address(old_other), other->get_address(other));
- return DESTROY_ME;
- }
- else if (other_changes & HOST_DIFF_PORT)
- {
- old_other->set_port(old_other, other->get_port(other));
- }
- }
-
- iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
- while (iterator->iterate(iterator, (void**)&child_sa))
- {
- child_sa->update_hosts(child_sa,
- this->connection->get_my_host(this->connection),
- this->connection->get_other_host(this->connection),
- my_changes, other_changes);
- /* XXX error handling */
- }
- iterator->destroy(iterator);
-
- return SUCCESS;
-}
-
-/**
- * Implementation of protected_ike_sa_t.build_transforms.
- * TODO: IPv6 support.
- */
-static chunk_t generate_natd_hash(private_ike_sa_t *this, u_int64_t spi_i, u_int64_t spi_r, host_t *host)
-{
- chunk_t natd_string;
- chunk_t natd_hash;
- void *p;
- struct sockaddr_in* sai;
- char buf[512];
-
- natd_hash = chunk_alloc(this->nat_hasher->get_hash_size(this->nat_hasher));
- natd_string = chunk_alloc(8 + 8 + 4 + 2);
-
- sai = (struct sockaddr_in*)host->get_sockaddr(host);
- p = natd_string.ptr;
- *(u_int64_t*)p = spi_i; p += sizeof(spi_i);
- *(u_int64_t*)p = spi_r; p += sizeof(spi_r);
- *(u_int32_t*)p = sai->sin_addr.s_addr; p += sizeof(sai->sin_addr.s_addr);
- *(u_int16_t*)p = sai->sin_port; p += sizeof(sai->sin_port);
-
- this->nat_hasher->get_hash(this->nat_hasher, natd_string, natd_hash.ptr);
- this->nat_hasher->reset(this->nat_hasher);
-
- sprintf(buf, "natd_hash(%016llx %016llx %s:%d)\n == SHA1(", spi_i, spi_r,
- host->get_address(host), host->get_port(host));
- chunk_to_hex(buf + strlen(buf), sizeof(buf) - strlen(buf), natd_string);
- strcat(buf, ") == ");
- chunk_to_hex(buf + strlen(buf), sizeof(buf) - strlen(buf), natd_hash);
- this->logger->log(this->logger, CONTROL|LEVEL3, buf);
-
- chunk_free(&natd_string);
- return natd_hash;
-}
-
-/**
- * Implementation of ike_sa_t.send_dpd_request.
- */
-static status_t send_dpd_request(private_ike_sa_t *this)
-{
- message_t *dpd_msg;
- status_t status;
- this->protected.build_message(&this->protected, INFORMATIONAL, TRUE, &dpd_msg);
- status = this->protected.send_request(&this->protected, dpd_msg);
- if (status != SUCCESS)
- {
- dpd_msg->destroy(dpd_msg);
- }
- this->last_dpd_message_id = dpd_msg->get_message_id(dpd_msg);
- return status;
-}
-
-/**
- * Implementation of ike_sa_t.get_last_dpd_message_id
- */
-static u_int32_t get_last_dpd_message_id(private_ike_sa_t *this)
-{
- return this->last_dpd_message_id;
-}
-
-/**
- * Implementation of ike_sa_t.get_child_sa.
- */
-static child_sa_t *get_child_sa(private_ike_sa_t *this, u_int32_t reqid)
-{
- iterator_t *iterator;
- child_sa_t *current, *found = NULL;
-
- iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
- while (iterator->has_next(iterator))
- {
- iterator->current(iterator, (void**)&current);
- if (current->get_reqid(current) == reqid)
- {
- found = current;
- break;
- }
- }
- iterator->destroy(iterator);
- return found;
-}
-
-/**
* Implementation of ike_sa_t.delete_child_sa.
*/
-static status_t delete_child_sa(private_ike_sa_t *this, u_int32_t reqid)
+static status_t delete_child_sa(private_ike_sa_t *this, u_int32_t spi)
{
- message_t *request;
- child_sa_t *child_sa;
- delete_payload_t *delete_payload;
- state_t *old_state;
-
- if (this->current_state->get_state(this->current_state) != IKE_SA_ESTABLISHED)
- {
- this->logger->log(this->logger, ERROR|LEVEL1,
- "delete of a CHILD_SA whose IKE_SA not in state IKE_SA_ESTABLISHED, aborting");
- return FAILED;
- }
-
- child_sa = get_child_sa(this, reqid);
- if (child_sa == NULL)
- {
- this->logger->log(this->logger, ERROR|LEVEL1,
- "IKE_SA does not contain a CHILD_SA with reqid %d", reqid);
- return FAILED;
- }
- build_message(this, INFORMATIONAL, TRUE, &request);
- delete_payload = delete_payload_create(child_sa->get_protocol(child_sa));
- delete_payload->add_spi(delete_payload, child_sa->get_spi(child_sa, TRUE));
- request->add_payload(request, (payload_t*)delete_payload);
-
- send_request(this, request);
-
- old_state = this->current_state;
- set_new_state(this, (state_t*)delete_child_sa_requested_create(&this->protected));
- old_state->destroy(old_state);
+ /* TODO: Reimplement */
+// message_t *request;
+// child_sa_t *child_sa;
+// delete_payload_t *delete_payload;
+//
+// if (this->current_state->get_state(this->current_state) != IKE_SA_ESTABLISHED)
+// {
+// this->logger->log(this->logger, ERROR|LEVEL1,
+// "Delete of a CHILD_SA whose IKE_SA not in state IKE_SA_ESTABLISHED, aborting");
+// return FAILED;
+// }
+//
+// child_sa = get_child_sa(this, reqid);
+// if (child_sa == NULL)
+// {
+// this->logger->log(this->logger, ERROR|LEVEL1,
+// "IKE_SA does not contain a CHILD_SA with reqid %d", reqid);
+// return FAILED;
+// }
+// build_message(this, INFORMATIONAL, TRUE, &request);
+// delete_payload = delete_payload_create(child_sa->get_protocol(child_sa));
+// delete_payload->add_spi(delete_payload, child_sa->get_spi(child_sa, TRUE));
+// request->add_payload(request, (payload_t*)delete_payload);
+//
+// send_request(this, request);
+//
+// old_state = this->current_state;
+// set_new_state(this, (state_t*)delete_child_sa_requested_create(&this->protected));
+// old_state->destroy(old_state);
return SUCCESS;
}
@@ -1185,7 +1190,7 @@ static u_int32_t destroy_child_sa(private_ike_sa_t *this, u_int32_t spi)
/**
* Implementation of protected_ike_sa_t.get_child_sa.
*/
-static child_sa_t* get_child_sa_by_spi(private_ike_sa_t *this, u_int32_t spi)
+static child_sa_t* get_child_sa(private_ike_sa_t *this, u_int32_t spi)
{
iterator_t *iterator;
child_sa_t *current, *found = NULL;
@@ -1206,8 +1211,9 @@ static child_sa_t* get_child_sa_by_spi(private_ike_sa_t *this, u_int32_t spi)
/**
* Implementation of ike_sa_t.rekey_child_sa.
*/
-static status_t rekey_child_sa(private_ike_sa_t *this, u_int32_t reqid)
+static status_t rekey_child_sa(private_ike_sa_t *this, u_int32_t spi)
{
+/* TODO reimplement
message_t *request;
child_sa_t *child_sa;
notify_payload_t *notify;
@@ -1217,7 +1223,6 @@ static status_t rekey_child_sa(private_ike_sa_t *this, u_int32_t reqid)
linked_list_t *proposals;
chunk_t nonce;
linked_list_t *my_ts, *other_ts;
- state_t *old_state;
if (this->current_state->get_state(this->current_state) != IKE_SA_ESTABLISHED)
{
@@ -1272,58 +1277,11 @@ static status_t rekey_child_sa(private_ike_sa_t *this, u_int32_t reqid)
old_state = this->current_state;
set_new_state(this, (state_t*)create_child_sa_requested_create(&this->protected, child_sa, nonce, reqid));
- old_state->destroy(old_state);
+ old_state->destroy(old_state);*/
return SUCCESS;
}
-/**
- * Implementation of protected_ike_sa_t.establish.
- */
-static void establish(private_ike_sa_t *this)
-{
- protected_ike_sa_t *ike_sa = (protected_ike_sa_t *)this;
-
- connection_t *connection = ike_sa->get_connection(ike_sa);
- host_t *my_host = connection->get_my_host(connection);
- host_t *other_host = connection->get_other_host(connection);
- policy_t *policy = ike_sa->get_policy(ike_sa);
- identification_t *my_id = policy->get_my_id(policy);
- identification_t *other_id = policy->get_other_id(policy);
-
- ike_sa->set_new_state(ike_sa, (state_t*)ike_sa_established_create(ike_sa));
-
- this->logger->log(this->logger, AUDIT, "IKE_SA established %s[%s]...%s[%s]",
- my_host->get_address(my_host),
- my_id->get_string(my_id),
- other_host->get_address(other_host),
- other_id->get_string(other_id));
-}
-
-/**
- * Implementation of protected_ike_sa_t.reset_message_buffers.
- */
-static void reset_message_buffers(private_ike_sa_t *this)
-{
- this->logger->log(this->logger, CONTROL|LEVEL2, "reset message counters and destroy stored messages");
- /* destroy stored requested message */
- if (this->last_requested_message != NULL)
- {
- this->last_requested_message->destroy(this->last_requested_message);
- this->last_requested_message = NULL;
- }
-
- /* destroy stored responded messages */
- if (this->last_responded_message != NULL)
- {
- this->last_responded_message->destroy(this->last_responded_message);
- this->last_responded_message = NULL;
- }
-
- this->message_id_out = 0;
- this->message_id_in = 0;
- this->last_replied_message_id = -1;
-}
/**
* Implementation of protected_ike_sa_t.log_status.
@@ -1364,7 +1322,7 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name)
}
logger->log(logger, CONTROL|LEVEL1, " \"%s\": IKE_SA in state %s, SPIs: 0x%.16llx 0x%.16llx",
name,
- mapping_find(ike_sa_state_m, this->current_state->get_state(this->current_state)),
+ mapping_find(ike_sa_state_m, this->state),
this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
this->ike_sa_id->get_responder_spi(this->ike_sa_id));
logger->log(logger, CONTROL, " \"%s\": %s[%s]...%s[%s]",
@@ -1388,129 +1346,38 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name)
*/
static status_t delete_(private_ike_sa_t *this)
{
- message_t *informational_request;
- delete_payload_t *delete_payload;
- u_int32_t timeout;
- delete_half_open_ike_sa_job_t *job;
- state_t *old_state;
-
- if (get_state(this) != IKE_SA_ESTABLISHED)
- {
- return INVALID_STATE;
- }
-
- build_message(this, INFORMATIONAL, TRUE, &informational_request);
- /* delete for the full IKE_SA, this deletes all child_sa's implicit */
- delete_payload = delete_payload_create(PROTO_IKE);
-
- informational_request->add_payload(informational_request, (payload_t*)delete_payload);
+ delete_ike_sa_t *delete_ike_sa;
+ delete_ike_sa = delete_ike_sa_create(&this->public, this->message_id_out++);
- if (send_request(this, informational_request) != SUCCESS)
- {
- /* send failed, but we ignore this, SA will get deleted anyway later */
- informational_request->destroy(informational_request);
- }
-
- /* transit to state delete_ike_sa_requested */
- old_state = this->current_state;
- set_new_state(this, (state_t*)delete_ike_sa_requested_create(&this->protected));
- old_state->destroy(old_state);
-
- /* there is no guarantee that the other peer will acknowledge the delete,
- * so we have to set a timeout where we destroy the SA... This is done with
- * the delete_half_open_ike_sa_job as used in IKE SA setup.
- */
- timeout = charon->configuration->get_half_open_ike_sa_timeout(charon->configuration);
- job = delete_half_open_ike_sa_job_create(this->ike_sa_id);
- charon->event_queue->add_relative(charon->event_queue, (job_t*)job, timeout);
- return SUCCESS;
-}
-
-/**
- * Implementation of ike_sa_t.is_my_host_behind_nat.
- */
-static bool is_my_host_behind_nat (private_ike_sa_t *this)
-{
- return this->nat_here;
+ return queue_transaction(this, (transaction_t*)delete_ike_sa, FALSE);
}
/**
- * Implementation of ike_sa_t.is_other_host_behind_nat.
+ * Implementation of ike_sa_t.is_natt_enabled.
*/
-static bool is_other_host_behind_nat (private_ike_sa_t *this)
-{
- return this->nat_there;
-}
-
-/**
- * Implementation of ike_sa_t.is_any_host_behind_nat.
- */
-static bool is_any_host_behind_nat (private_ike_sa_t *this)
+static bool is_natt_enabled (private_ike_sa_t *this)
{
return this->nat_here || this->nat_there;
}
/**
- * Implementation of protected_ike_sa_t.set_my_host_behind_nat.
- */
-static void set_my_host_behind_nat (private_ike_sa_t *this, bool nat)
-{
- this->nat_here = nat;
-}
-
-/**
- * Implementation of protected_ike_sa_t.set_other_host_behind_nat.
- */
-static void set_other_host_behind_nat (private_ike_sa_t *this, bool nat)
-{
- this->nat_there = nat;
-}
-
-/**
- * Implementation of private_ike_sa_t.get_last_esp_traffic_tv
+ * Implementation of protected_ike_sa_t.enable_natt.
*/
-static struct timeval get_last_esp_traffic_tv(private_ike_sa_t * this, bool inbound)
+static void enable_natt (private_ike_sa_t *this, bool local)
{
- iterator_t *iterator;
- child_sa_t *child_sa;
- bool ret = TRUE;
- time_t use_time = 0;
- struct timeval tv = {0, 0};
-
- iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
- while (iterator->iterate(iterator, (void**)&child_sa))
+ if (local)
{
- if (child_sa->get_use_time(child_sa, inbound, &use_time) == SUCCESS
- && use_time != 0)
- {
- tv.tv_sec = max(tv.tv_sec, use_time);
- }
+ this->logger->log(this->logger, CONTROL,
+ "local host is behind NAT, using NAT-T, scheduled keep alives");
+ this->nat_here = TRUE;
+ send_keepalive(this);
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL,
+ "remote host is behind NAT, using NAT-T");
+ this->nat_there = TRUE;
}
- iterator->destroy(iterator);
-
- return tv;
-}
-
-/**
- * Implementation of ike_sa_t.get_last_traffic_in_tv.
- */
-static struct timeval get_last_traffic_in_tv (private_ike_sa_t *this)
-{
- struct timeval esp_tv = this->get_last_esp_traffic_tv(this, TRUE);
- return this->last_msg_in_tv.tv_sec > esp_tv.tv_sec ? this->last_msg_in_tv
- : this->last_msg_in_tv.tv_sec < esp_tv.tv_sec ? esp_tv
- : this->last_msg_in_tv.tv_usec > esp_tv.tv_usec ? this->last_msg_in_tv : esp_tv;
-}
-
-/**
- * Implementation of ike_sa_t.get_last_traffic_out_tv.
- */
-static struct timeval get_last_traffic_out_tv (private_ike_sa_t *this)
-{
- struct timeval esp_tv = this->get_last_esp_traffic_tv(this, FALSE);
- return this->last_msg_out_tv.tv_sec > esp_tv.tv_sec ? this->last_msg_out_tv
- : this->last_msg_out_tv.tv_sec < esp_tv.tv_sec ? esp_tv
- : this->last_msg_out_tv.tv_usec > esp_tv.tv_usec ? this->last_msg_out_tv : esp_tv;
}
/**
@@ -1519,15 +1386,17 @@ static struct timeval get_last_traffic_out_tv (private_ike_sa_t *this)
static void destroy(private_ike_sa_t *this)
{
child_sa_t *child_sa;
+ transaction_t *transaction;
this->logger->log(this->logger, CONTROL|LEVEL2, "going to destroy IKE SA %llu:%llu, role %s",
this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
this->ike_sa_id->get_responder_spi(this->ike_sa_id),
this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
- if (get_state(this) == IKE_SA_ESTABLISHED)
+ if (this->state == SA_ESTABLISHED)
{
- this->logger->log(this->logger, ERROR, "destroying an established IKE SA without knowledge from remote peer!");
+ this->logger->log(this->logger, ERROR,
+ "destroying an established IKE SA without knowledge from remote peer!");
}
while (this->child_sas->remove_last(this->child_sas, (void**)&child_sa) == SUCCESS)
@@ -1536,21 +1405,38 @@ static void destroy(private_ike_sa_t *this)
}
this->child_sas->destroy(this->child_sas);
- if (this->crypter_initiator)
+ while (this->transaction_queue->remove_last(this->transaction_queue, (void**)&transaction) == SUCCESS)
{
- this->crypter_initiator->destroy(this->crypter_initiator);
+ transaction->destroy(transaction);
}
- if (this->crypter_responder)
+ this->transaction_queue->destroy(this->transaction_queue);
+ if (this->transaction_in)
{
- this->crypter_responder->destroy(this->crypter_responder);
+ this->transaction_in->destroy(this->transaction_in);
}
- if (this->signer_initiator)
+ if (this->transaction_in_next)
{
- this->signer_initiator->destroy(this->signer_initiator);
+ this->transaction_in_next->destroy(this->transaction_in_next);
}
- if (this->signer_responder)
+ if (this->transaction_out)
{
- this->signer_responder->destroy(this->signer_responder);
+ this->transaction_out->destroy(this->transaction_out);
+ }
+ if (this->crypter_in)
+ {
+ this->crypter_in->destroy(this->crypter_in);
+ }
+ if (this->crypter_out)
+ {
+ this->crypter_out->destroy(this->crypter_out);
+ }
+ if (this->signer_in)
+ {
+ this->signer_in->destroy(this->signer_in);
+ }
+ if (this->signer_out)
+ {
+ this->signer_out->destroy(this->signer_out);
}
if (this->prf)
{
@@ -1591,18 +1477,7 @@ static void destroy(private_ike_sa_t *this)
{
this->policy->destroy(this->policy);
}
- if (this->last_requested_message)
- {
- this->last_requested_message->destroy(this->last_requested_message);
- }
- if (this->last_responded_message)
- {
- this->last_responded_message->destroy(this->last_responded_message);
- }
- this->nat_hasher->destroy(this->nat_hasher);
this->ike_sa_id->destroy(this->ike_sa_id);
- this->randomizer->destroy(this->randomizer);
- this->current_state->destroy(this->current_state);
free(this);
}
@@ -1614,109 +1489,59 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
private_ike_sa_t *this = malloc_thing(private_ike_sa_t);
/* Public functions */
- this->protected.public.process_message = (status_t (*) (ike_sa_t*,message_t*)) process_message;
- this->protected.public.initiate_connection = (status_t (*) (ike_sa_t*,connection_t*)) initiate_connection;
- this->protected.public.delete_child_sa = (status_t (*) (ike_sa_t*,u_int32_t)) delete_child_sa;
- this->protected.public.rekey_child_sa = (status_t (*) (ike_sa_t*,u_int32_t)) rekey_child_sa;
- this->protected.public.get_child_sa = (child_sa_t* (*) (ike_sa_t*,u_int32_t))get_child_sa;
- this->protected.public.get_id = (ike_sa_id_t* (*) (ike_sa_t*)) get_id;
- this->protected.public.get_my_host = (host_t* (*) (ike_sa_t*)) get_my_host;
- this->protected.public.get_other_host = (host_t* (*) (ike_sa_t*)) get_other_host;
- this->protected.public.get_my_id = (identification_t* (*) (ike_sa_t*)) get_my_id;
- this->protected.public.get_other_id = (identification_t* (*) (ike_sa_t*)) get_other_id;
- this->protected.public.get_connection = (connection_t* (*) (ike_sa_t*)) get_connection;
- this->protected.public.retransmit_possible = (bool (*) (ike_sa_t*,u_int32_t)) retransmit_possible;
- this->protected.public.retransmit_request = (status_t (*) (ike_sa_t*,u_int32_t)) retransmit_request;
- this->protected.public.get_state = (ike_sa_state_t (*) (ike_sa_t*)) get_state;
- this->protected.public.log_status = (void (*) (ike_sa_t*,logger_t*,char*))log_status;
- this->protected.public.delete = (status_t (*) (ike_sa_t*))delete_;
- this->protected.public.destroy = (void (*) (ike_sa_t*))destroy;
- this->protected.public.is_my_host_behind_nat = (bool (*) (ike_sa_t*)) is_my_host_behind_nat;
- this->protected.public.is_other_host_behind_nat = (bool (*) (ike_sa_t*)) is_other_host_behind_nat;
- this->protected.public.is_any_host_behind_nat = (bool (*) (ike_sa_t*)) is_any_host_behind_nat;
- this->protected.public.get_last_traffic_in_tv = (struct timeval (*) (ike_sa_t*)) get_last_traffic_in_tv;
- this->protected.public.get_last_traffic_out_tv = (struct timeval (*) (ike_sa_t*)) get_last_traffic_out_tv;
- this->protected.public.send_dpd_request = (status_t (*) (ike_sa_t*)) send_dpd_request;
-
- /* protected functions */
- this->protected.build_message = (void (*) (protected_ike_sa_t*,exchange_type_t,bool,message_t**)) build_message;
- this->protected.get_prf = (prf_t *(*) (protected_ike_sa_t*)) get_prf;
- this->protected.get_child_prf = (prf_t* (*) (protected_ike_sa_t*)) get_child_prf;
- this->protected.get_prf_auth_i = (prf_t* (*) (protected_ike_sa_t*)) get_prf_auth_i;
- this->protected.get_prf_auth_r = (prf_t* (*) (protected_ike_sa_t*)) get_prf_auth_r;
- this->protected.add_child_sa = (void (*) (protected_ike_sa_t*,child_sa_t*)) add_child_sa;
- this->protected.establish = (void (*) (protected_ike_sa_t*)) establish;
- this->protected.set_connection = (void (*) (protected_ike_sa_t*,connection_t*)) set_connection;
- this->protected.get_connection = (connection_t* (*) (protected_ike_sa_t*)) get_connection;
- this->protected.set_policy = (void (*) (protected_ike_sa_t *,policy_t*)) set_policy;
- this->protected.get_policy = (policy_t* (*) (protected_ike_sa_t*)) get_policy;
- this->protected.get_randomizer = (randomizer_t* (*) (protected_ike_sa_t*)) get_randomizer;
- this->protected.send_request = (status_t (*) (protected_ike_sa_t*,message_t*)) send_request;
- this->protected.send_response = (status_t (*) (protected_ike_sa_t*,message_t*)) send_response;
- this->protected.send_notify = (void (*) (protected_ike_sa_t*,exchange_type_t,notify_message_type_t,chunk_t)) send_notify;
- this->protected.build_transforms = (status_t (*) (protected_ike_sa_t*,proposal_t*,diffie_hellman_t*,chunk_t,chunk_t)) build_transforms;
- this->protected.set_new_state = (void (*) (protected_ike_sa_t*,state_t*)) set_new_state;
- this->protected.get_crypter_initiator = (crypter_t* (*) (protected_ike_sa_t*)) get_crypter_initiator;
- this->protected.get_signer_initiator = (signer_t* (*) (protected_ike_sa_t*)) get_signer_initiator;
- this->protected.get_crypter_responder = (crypter_t* (*) (protected_ike_sa_t*)) get_crypter_responder;
- this->protected.get_signer_responder = (signer_t* (*) (protected_ike_sa_t*)) get_signer_responder;
- this->protected.reset_message_buffers = (void (*) (protected_ike_sa_t*)) reset_message_buffers;
- this->protected.get_last_responded_message = (message_t* (*) (protected_ike_sa_t*)) get_last_responded_message;
- this->protected.get_last_requested_message = (message_t* (*) (protected_ike_sa_t*)) get_last_requested_message;
- this->protected.set_last_replied_message_id = (void (*) (protected_ike_sa_t*,u_int32_t)) set_last_replied_message_id;
- this->protected.destroy_child_sa = (u_int32_t (*) (protected_ike_sa_t*,u_int32_t))destroy_child_sa;
- this->protected.get_child_sa = (child_sa_t* (*) (protected_ike_sa_t*,u_int32_t))get_child_sa_by_spi;
- this->protected.set_my_host_behind_nat = (void (*) (protected_ike_sa_t*,bool)) set_my_host_behind_nat;
- this->protected.set_other_host_behind_nat = (void (*) (protected_ike_sa_t*,bool)) set_other_host_behind_nat;
- this->protected.generate_natd_hash = (chunk_t (*) (protected_ike_sa_t*,u_int64_t, u_int64_t, host_t*)) generate_natd_hash;
- this->protected.get_last_dpd_message_id = (u_int32_t (*) (protected_ike_sa_t*)) get_last_dpd_message_id;
- this->protected.update_connection_hosts = (status_t (*) (protected_ike_sa_t*,host_t*,host_t*)) update_connection_hosts;
-
- /* private functions */
- this->update_timestamp = (void (*) (private_ike_sa_t*,bool))update_timestamp;
- this->get_last_esp_traffic_tv = (struct timeval (*) (private_ike_sa_t*,bool))get_last_esp_traffic_tv;
-
+ this->public.get_state = (ike_sa_state_t(*)(ike_sa_t*)) get_state;
+ this->public.set_state = (void(*)(ike_sa_t*,ike_sa_state_t)) set_state;
+ this->public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message;
+ this->public.initiate = (status_t(*)(ike_sa_t*,connection_t*)) initiate;
+ this->public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id;
+ this->public.get_connection = (connection_t*(*)(ike_sa_t*)) get_connection;
+ this->public.retransmit_request = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit_request;
+ this->public.log_status = (void (*) (ike_sa_t*,logger_t*,char*))log_status;
+ this->public.delete = (status_t(*)(ike_sa_t*))delete_;
+ this->public.destroy = (void(*)(ike_sa_t*))destroy;
+ this->public.send_dpd = (status_t (*)(ike_sa_t*)) send_dpd;
+ this->public.send_keepalive = (void (*)(ike_sa_t*)) send_keepalive;
+ this->public.get_prf = (prf_t *(*) (ike_sa_t *)) get_prf;
+ this->public.get_child_prf = (prf_t *(*) (ike_sa_t *)) get_child_prf;
+ this->public.get_prf_auth_i = (prf_t *(*) (ike_sa_t *)) get_prf_auth_i;
+ this->public.get_prf_auth_r = (prf_t *(*) (ike_sa_t *)) get_prf_auth_r;
+ this->public.add_child_sa = (void (*) (ike_sa_t*,child_sa_t*)) add_child_sa;
+ this->public.set_connection = (void (*) (ike_sa_t *,connection_t *)) set_connection;
+ this->public.get_connection = (connection_t *(*) (ike_sa_t *)) get_connection;
+ this->public.set_policy = (void (*) (ike_sa_t *,policy_t *)) set_policy;
+ this->public.get_policy = (policy_t *(*) (ike_sa_t *)) get_policy;
+ this->public.build_transforms = (status_t (*) (ike_sa_t *,proposal_t*,diffie_hellman_t*,chunk_t,chunk_t,bool)) build_transforms;
+ this->public.destroy_child_sa = (u_int32_t (*)(ike_sa_t*,u_int32_t))destroy_child_sa;
+ this->public.get_child_sa = (child_sa_t* (*)(ike_sa_t*,u_int32_t)) get_child_sa;
+ this->public.delete_child_sa = (status_t(*)(ike_sa_t*,u_int32_t)) delete_child_sa;
+ this->public.rekey_child_sa = (status_t(*)(ike_sa_t*,u_int32_t)) rekey_child_sa;
+ this->public.enable_natt = (void(*)(ike_sa_t*, bool)) enable_natt;
+ this->public.is_natt_enabled = (bool(*)(ike_sa_t*)) is_natt_enabled;
+
/* initialize private fields */
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
-
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
this->child_sas = linked_list_create();
- this->randomizer = randomizer_create();
-
- this->last_requested_message = NULL;
- this->last_responded_message = NULL;
- this->message_id_out = 0;
- this->message_id_in = 0;
- this->last_replied_message_id = -1;
- this->crypter_initiator = NULL;
- this->crypter_responder = NULL;
- this->signer_initiator = NULL;
- this->signer_responder = NULL;
+ this->crypter_in = NULL;
+ this->crypter_out = NULL;
+ this->signer_in = NULL;
+ this->signer_out = NULL;
this->prf = NULL;
this->prf_auth_i = NULL;
this->prf_auth_r = NULL;
this->child_prf = NULL;
this->connection = NULL;
this->policy = NULL;
- this->nat_hasher = hasher_create(HASH_SHA1);
this->nat_here = FALSE;
this->nat_there = FALSE;
- this->last_msg_in_tv.tv_sec = 0;
- this->last_msg_in_tv.tv_usec = 0;
- this->last_msg_out_tv.tv_sec = 0;
- this->last_msg_out_tv.tv_usec = 0;
- this->last_dpd_message_id = 0;
-
- /* at creation time, IKE_SA is in a initiator state */
- if (ike_sa_id->is_initiator(ike_sa_id))
- {
- this->logger->log(this->logger, CONTROL | LEVEL2, "create first state_t object of type INITIATOR_INIT");
- this->current_state = (state_t *) initiator_init_create(&(this->protected));
- }
- else
- {
- this->logger->log(this->logger, CONTROL | LEVEL2, "create first state_t object of type RESPONDER_INIT");
- this->current_state = (state_t *) responder_init_create(&(this->protected));
- }
- return &(this->protected.public);
+ this->transaction_queue = linked_list_create();
+ this->transaction_in = NULL;
+ this->transaction_in_next = NULL;
+ this->transaction_out = NULL;
+ this->state = SA_CREATED;
+ this->message_id_out = 0;
+ this->time_inbound = 0;
+ this->time_outbound = 0;
+
+ return &this->public;
}
diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h
index 06a5930e4..863271950 100644
--- a/src/charon/sa/ike_sa.h
+++ b/src/charon/sa/ike_sa.h
@@ -29,7 +29,6 @@
#include <encoding/payloads/proposal_substructure.h>
#include <sa/ike_sa_id.h>
#include <sa/child_sa.h>
-#include <sa/states/state.h>
#include <config/configuration.h>
#include <utils/logger.h>
#include <utils/randomizer.h>
@@ -40,25 +39,53 @@
#include <config/policies/policy.h>
#include <utils/logger.h>
+
+typedef enum ike_sa_state_t ike_sa_state_t;
+
/**
- * Nonce size in bytes for nonces sending to other peer.
- *
- * @warning Nonce size MUST be between 16 and 256 bytes.
+ * @brief State of an IKE_SA.
*
* @ingroup sa
*/
-#define NONCE_SIZE 16
+enum ike_sa_state_t {
+
+ /**
+ * IKE_SA just got created, but is not initiating nor responding yet.
+ */
+ SA_CREATED,
+
+ /**
+ * IKE_SA gets initiated actively or passively
+ */
+ SA_CONNECTING,
+
+ /**
+ * IKE_SA is fully established
+ */
+ SA_ESTABLISHED,
+
+ /**
+ * IKE_SA is in progress of deletion
+ */
+ SA_DELETING,
+};
+
+/**
+ * String mappings for ike_sa_state_t.
+ */
+extern mapping_t ike_sa_state_m[];
typedef struct ike_sa_t ike_sa_t;
/**
- * @brief Class ike_sa_t representing an IKE_SA.
- *
- * An object of this type is managed by an ike_sa_manager_t object
- * and represents an IKE_SA. Message processing is split up in different states.
- * They will handle all related things for the state they represent.
- *
+ * @brief Class ike_sa_t representing an IKE_SA.
+ *
+ * An IKE_SA contains crypto information related to a connection
+ * with a peer. It contains multiple IPsec CHILD_SA, for which
+ * it is responsible. All traffic is handled by an IKE_SA, using
+ * transactions.
+ *
* @b Constructors:
* - ike_sa_create()
*
@@ -67,20 +94,34 @@ typedef struct ike_sa_t ike_sa_t;
struct ike_sa_t {
/**
- * @brief Processes a incoming IKEv2-Message of type message_t.
+ * @brief Get the id of the SA.
+ *
+ * Returned ike_sa_id_t object is not getting cloned!
*
- * @param this ike_sa_t object object
- * @param[in] message message_t object to process
- * @return
- * - SUCCESS
- * - FAILED
- * - DESTROY_ME if this IKE_SA MUST be deleted
+ * @param this calling object
+ * @return ike_sa's ike_sa_id_t
*/
- status_t (*process_message) (ike_sa_t *this,message_t *message);
+ ike_sa_id_t* (*get_id) (ike_sa_t *this);
+
+ /**
+ * @brief Get the state of the IKE_SA.
+ *
+ * @param this calling object
+ * @return state of the IKE_SA
+ */
+ ike_sa_state_t (*get_state) (ike_sa_t *this);
+
+ /**
+ * @brief Set the state of the IKE_SA.
+ *
+ * @param this calling object
+ * @param state state to set for the IKE_SA
+ */
+ void (*set_state) (ike_sa_t *this, ike_sa_state_t ike_sa);
/**
- * @brief Initiate a new connection with given connection_t object.
- *
+ * @brief Initiate a new connection.
+ *
* The connection_t object is owned by the IKE_SA after the call, so
* do not modify or destroy it.
*
@@ -91,19 +132,24 @@ struct ike_sa_t {
* - FAILED if in wrong state
* - DESTROY_ME if initialization failed and IKE_SA MUST be deleted
*/
- status_t (*initiate_connection) (ike_sa_t *this, connection_t *connection);
+ status_t (*initiate) (ike_sa_t *this, connection_t *connection);
/**
- * @brief Checks whether retransmission is possible.
+ * @brief Initiates the deletion of an IKE_SA.
+ *
+ * Sends a delete message to the remote peer and waits for
+ * its response. If the response comes in, or a timeout occurs,
+ * the IKE SA gets deleted.
*
* @param this calling object
- * @param message_id ID of the request to retransmit
* @return
- * - TRUE if retransmit is possible
- * - FALSE if not
+ * - SUCCESS if deletion is initialized
+ * - INVALID_STATE, if the IKE_SA is not in
+ * an established state and can not be
+ * delete (but destroyed).
*/
- bool (*retransmit_possible) (ike_sa_t *this, u_int32_t message_id);
-
+ status_t (*delete) (ike_sa_t *this);
+
/**
* @brief Retransmits a request.
*
@@ -114,157 +160,71 @@ struct ike_sa_t {
* - NOT_FOUND if request doesn't have to be retransmited
*/
status_t (*retransmit_request) (ike_sa_t *this, u_int32_t message_id);
-
- /**
- * @brief Get the id of the SA.
- *
- * Returned ike_sa_id_t object is not getting cloned!
- *
- * @param this calling object
- * @return ike_sa's ike_sa_id_t
- */
- ike_sa_id_t* (*get_id) (ike_sa_t *this);
-
- /**
- * @brief Get the CHILD_SA with the specified reqid.
- *
- * The reqid is a unique ID for a child SA, which is
- * generated on child SA creation.
- * Returned child_sa_t object is not cloned!
- *
- * @param this calling object
- * @param reqid reqid of the child SA, as used in the kernel
- * @return child_sa, or NULL if not found
- */
- child_sa_t* (*get_child_sa) (ike_sa_t *this, u_int32_t reqid);
-
- /**
- * @brief Close the CHILD SA with the specified reqid.
- *
- * Looks for a CHILD SA owned by this IKE_SA, deletes it and
- * notify's the remote peer about the delete. The associated
- * states and policies in the kernel get deleted, if they exist.
- *
- * @param this calling object
- * @param reqid reqid of the child SA, as used in the kernel
- * @return
- * - NOT_FOUND, if IKE_SA has no such CHILD_SA
- * - SUCCESS, if deleted and delete message sent
- */
- status_t (*delete_child_sa) (ike_sa_t *this, u_int32_t reqid);
-
- /**
- * @brief Rekey the CHILD SA with the specified reqid.
- *
- * Looks for a CHILD SA owned by this IKE_SA, and start the rekeing.
- *
- * @param this calling object
- * @param spi security parameter index identifying the SA to rekey
- * @return
- * - NOT_FOUND, if IKE_SA has no such CHILD_SA
- * - SUCCESS, if rekeying initiated
- */
- status_t (*rekey_child_sa) (ike_sa_t *this, u_int32_t reqid);
-
- /**
- * @brief Get local peer address of the IKE_SA.
- *
- * @param this calling object
- * @return local host_t
- */
- host_t* (*get_my_host) (ike_sa_t *this);
-
- /**
- * @brief Get remote peer address of the IKE_SA.
- *
- * @param this calling object
- * @return remote host_t
- */
- host_t* (*get_other_host) (ike_sa_t *this);
-
- /**
- * @brief Get own ID of the IKE_SA.
- *
- * @param this calling object
- * @return local identification_t
- */
- identification_t* (*get_my_id) (ike_sa_t *this);
-
+
/**
- * @brief Get remote ID the IKE_SA.
+ * @brief Processes a incoming IKEv2-Message.
*
- * @param this calling object
- * @return remote identification_t
- */
- identification_t* (*get_other_id) (ike_sa_t *this);
-
- /**
- * @brief Get the connection of the IKE_SA.
+ * Message processing may fail. If a critical failure occurs,
+ * process_message() return DESTROY_ME. Then the caller must
+ * destroy the IKE_SA immediatly, as it is unusable.
*
- * The internal used connection specification
- * can be queried to get some data of an IKE_SA.
- * The connection is still owned to the IKE_SA
- * and must not be manipulated.
- *
* @param this calling object
- * @return connection_t
+ * @param[in] message message to process
+ * @return
+ * - SUCCESS
+ * - FAILED
+ * - DESTROY_ME if this IKE_SA MUST be deleted
*/
- connection_t* (*get_connection) (ike_sa_t *this);
+ status_t (*process_message) (ike_sa_t *this,message_t *message);
/**
- * @brief Query NAT detection status for local host.
+ * @brief Check if NAT traversal is enabled for this IKE_SA.
*
* @param this calling object
- * @return TRUE if this host is behind NAT
+ * @return TRUE if NAT traversal enabled
*/
- bool (*is_my_host_behind_nat) (ike_sa_t *this);
+ bool (*is_natt_enabled) (ike_sa_t *this);
/**
- * @brief Query NAT detection status for remote host.
+ * @brief Enable NAT detection for this IKE_SA.
*
- * @param this calling object
- * @return TRUE if other host is behind NAT
- */
- bool (*is_other_host_behind_nat) (ike_sa_t *this);
-
- /**
- * @brief Query NAT detection status for any host.
+ * If a Network address translation is detected with
+ * NAT_DETECTION notifys, a SA must switch to ports
+ * 4500. To enable this behavior, call enable_natt().
+ * It is relevant which peer is NATted, this is specified
+ * with the "local" parameter. Call it twice when both
+ * are NATted.
*
* @param this calling object
- * @return TRUE if this or other host is behind NAT
+ * @param local TRUE, if we are NATted, FALSE if other
*/
- bool (*is_any_host_behind_nat) (ike_sa_t *this);
+ void (*enable_natt) (ike_sa_t *this, bool local);
/**
- * @brief Query timeval of last inbound IKE or ESP traffic.
+ * @brief Sends a DPD request to the peer.
*
+ * To check if a peer is still alive, periodic
+ * empty INFORMATIONAL messages are sent if no
+ * other traffic was received.
+ *
* @param this calling object
- * @return time when the last traffic was seen
+ * @return
+ * - SUCCESS
+ * - DESTROY_ME, if peer did not respond
*/
- struct timeval (*get_last_traffic_in_tv) (ike_sa_t *this);
-
+ status_t (*send_dpd) (ike_sa_t *this);
+
/**
- * @brief Query timeval of last outbound IKE or ESP traffic.
+ * @brief Sends a keep alive packet.
*
- * @param this calling object
- * @return time when the last traffic was seen
- */
- struct timeval (*get_last_traffic_out_tv) (ike_sa_t *this);
-
- /**
- * @brief Get the state of type of associated state object.
+ * To refresh NAT tables in a NAT router
+ * between the peers, periodic empty
+ * UDP packets are sent if no other traffic
+ * was sent.
*
- * @param this calling object
- * @return state of IKE_SA
- */
- ike_sa_state_t (*get_state) (ike_sa_t *this);
-
- /**
- * @brief Sends a DPD request to the peer.
- *
* @param this calling object
*/
- status_t (*send_dpd_request) (ike_sa_t *this);
+ void (*send_keepalive) (ike_sa_t *this);
/**
* @brief Log the status of a the ike sa to a logger.
@@ -279,71 +239,14 @@ struct ike_sa_t {
* @param name name of the connection
*/
void (*log_status) (ike_sa_t *this, logger_t *logger, char *name);
-
- /**
- * @brief Initiates the deletion of an IKE_SA.
- *
- * Sends a delete message to the remote peer and waits for
- * its response. If the response comes in, or a timeout occurs,
- * the IKE SA gets deleted.
- *
- * @param this calling object
- * @return
- * - SUCCESS if deletion is initialized
- * - INVALID_STATE, if the IKE_SA is not in
- * an established state and can not be
- * delete (but destroyed).
- */
- status_t (*delete) (ike_sa_t *this);
-
- /**
- * @brief Destroys a ike_sa_t object.
- *
- * @param this calling object
- */
- void (*destroy) (ike_sa_t *this);
-};
-
-
-typedef struct protected_ike_sa_t protected_ike_sa_t;
-
-/**
- * @brief Protected functions of an ike_sa_t object.
- *
- * This members are only accessed out from
- * the various state_t implementations.
- *
- * @ingroup sa
- */
-struct protected_ike_sa_t {
-
- /**
- * Public interface of an ike_sa_t object.
- */
- ike_sa_t public;
-
- /**
- * @brief Build 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 state_t Implementation to build an empty IKEv2-Message.
- *
- * @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
- */
- void (*build_message) (protected_ike_sa_t *this, exchange_type_t type, bool request, message_t **message);
-
+
/**
* @brief Get the internal stored connection_t object.
*
* @param this calling object
* @return pointer to the internal stored connection_t object
*/
- connection_t *(*get_connection) (protected_ike_sa_t *this);
+ connection_t *(*get_connection) (ike_sa_t *this);
/**
* @brief Set the internal connection object.
@@ -351,7 +254,7 @@ struct protected_ike_sa_t {
* @param this calling object
* @param connection object of type connection_t
*/
- void (*set_connection) (protected_ike_sa_t *this, connection_t *connection);
+ void (*set_connection) (ike_sa_t *this, connection_t *connection);
/**
* @brief Get the internal stored policy object.
@@ -359,7 +262,7 @@ struct protected_ike_sa_t {
* @param this calling object
* @return pointer to the internal stored policy_t object
*/
- policy_t *(*get_policy) (protected_ike_sa_t *this);
+ policy_t *(*get_policy) (ike_sa_t *this);
/**
* @brief Set the internal policy_t object.
@@ -367,274 +270,135 @@ struct protected_ike_sa_t {
* @param this calling object
* @param policy object of type policy_t
*/
- void (*set_policy) (protected_ike_sa_t *this,policy_t *policy);
-
+ void (*set_policy) (ike_sa_t *this, policy_t *policy);
+
/**
* @brief Derive all keys and create the transforms for IKE communication.
*
* Keys are derived using the diffie hellman secret, nonces and internal
- * stored SPIs.
+ * stored SPIs.
* Already existing objects get destroyed.
*
- * @param this calling object
- * @param proposal proposal which contains algorithms to use
- * @param dh diffie hellman object with shared secret
- * @param nonce_i initiators nonce
- * @param nonce_r responders nonce
- */
- status_t (*build_transforms) (protected_ike_sa_t *this, proposal_t* proposal,
- diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r);
-
- /**
- * @brief Send the next request message.
- *
- * Also the first retransmit job is created.
- *
- * Last stored requested message gets destroyed. Object gets not cloned!
- *
- * @param this calling object
- * @param message pointer to the message which should be sent
- * @return
- * - SUCCESS
- * - FAILED if message id is not next expected one
- */
- status_t (*send_request) (protected_ike_sa_t *this,message_t * message);
-
- /**
- * @brief Send the next response message.
- *
- * Last stored responded message gets destroyed. Object gets not cloned!
- *
- * @param this calling object
- * @param message pointer to the message which should be sent
- * return
- * - SUCCESS
- * - FAILED if message id is not next expected one
- */
- status_t (*send_response) (protected_ike_sa_t *this,message_t * message);
-
- /**
- * @brief Send a notify reply message.
- *
- * @param this calling object
- * @param exchange_type type of exchange in which the notify should be wrapped
- * @param type type of the notify message to send
- * @param data notification data
- */
- void (*send_notify) (protected_ike_sa_t *this, exchange_type_t exchange_type, notify_message_type_t type, chunk_t data);
-
- /**
- * @brief Get the internal stored randomizer_t object.
- *
- * @param this calling object
- * @return pointer to the internal randomizer_t object
- */
- randomizer_t *(*get_randomizer) (protected_ike_sa_t *this);
-
- /**
- * @brief Set the new state_t object of the IKE_SA object.
- *
- * The old state_t object gets not destroyed. It's the callers duty to
- * make sure old state is destroyed (Normally the old state is the caller).
- *
- * @param this calling object
- * @param state pointer to the new state_t object
- */
- void (*set_new_state) (protected_ike_sa_t *this,state_t *state);
-
- /**
- * @brief Set the last replied message id.
- *
- * @param this calling object
- * @param message_id message id
- */
- void (*set_last_replied_message_id) (protected_ike_sa_t *this,u_int32_t message_id);
-
- /**
- * @brief Get the internal stored initiator crypter_t object.
- *
- * @param this calling object
- * @return pointer to crypter_t object
- */
- crypter_t *(*get_crypter_initiator) (protected_ike_sa_t *this);
-
- /**
- * @brief Get the internal stored initiator signer_t object.
- *
- * @param this calling object
- * @return pointer to signer_t object
- */
- signer_t *(*get_signer_initiator) (protected_ike_sa_t *this);
-
- /**
- * @brief Get the internal stored responder crypter_t object.
- *
- * @param this calling object
- * @return pointer to crypter_t object
- */
- crypter_t *(*get_crypter_responder) (protected_ike_sa_t *this);
-
- /**
- * @brief Get the internal stored responder signer object.
- *
- * @param this calling object
- * @return pointer to signer_t object
- */
- signer_t *(*get_signer_responder) (protected_ike_sa_t *this);
+ * @param this calling object
+ * @param proposal proposal which contains algorithms to use
+ * @param dh diffie hellman object with shared secret
+ * @param nonce_i initiators nonce
+ * @param nonce_r responders nonce
+ * @param initiator role of this IKE SA (TRUE = originial initiator)
+ */
+ status_t (*build_transforms) (ike_sa_t *this, proposal_t* proposal,
+ diffie_hellman_t *dh,
+ chunk_t nonce_i, chunk_t nonce_r,
+ bool initiator);
/**
* @brief Get the multi purpose prf.
*
- * @param this calling object
- * @return pointer to prf_t object
+ * @param this calling object
+ * @return pointer to prf_t object
*/
- prf_t *(*get_prf) (protected_ike_sa_t *this);
+ prf_t *(*get_prf) (ike_sa_t *this);
/**
* @brief Get the prf-object, which is used to derive keys for child SAs.
*
- * @param this calling object
- * @return pointer to prf_t object
+ * @param this calling object
+ * @return pointer to prf_t object
*/
- prf_t *(*get_child_prf) (protected_ike_sa_t *this);
+ prf_t *(*get_child_prf) (ike_sa_t *this);
/**
* @brief Get the prf used for authentication of initiator.
*
- * @param this calling object
- * @return pointer to prf_t object
+ * @param this calling object
+ * @return pointer to prf_t object
*/
- prf_t *(*get_prf_auth_i) (protected_ike_sa_t *this);
+ prf_t *(*get_prf_auth_i) (ike_sa_t *this);
/**
* @brief Get the prf used for authentication of responder.
*
- * @param this calling object
- * @return pointer to prf_t object
- */
- prf_t *(*get_prf_auth_r) (protected_ike_sa_t *this);
-
- /**
- * @brief Associates a child SA to this IKE SA
- *
- * @param this calling object
- * @param child_sa child_sa to add
- */
- void (*add_child_sa) (protected_ike_sa_t *this, child_sa_t *child_sa);
-
- /**
- * @brief Destroys a CHILD_SA upon request from the other peer.
- *
- * @param this calling object
- * @param spi inbound spi of the CHILD_SA to destroy
- * @return outbound spi of the destroyed CHILD_SA
+ * @param this calling object
+ * @return pointer to prf_t object
*/
- u_int32_t (*destroy_child_sa) (protected_ike_sa_t *this, u_int32_t spi);
+ prf_t *(*get_prf_auth_r) (ike_sa_t *this);
/**
* @brief Get a CHILD_SA upon request from the other peer.
*
- * @param this calling object
- * @param spi spi of the CHILD_SA
- * @return child_sa, or NULL if none found
+ * @param this calling object
+ * @param spi spi of the CHILD_SA
+ * @return child_sa, or NULL if none found
*/
- child_sa_t* (*get_child_sa) (protected_ike_sa_t *this, u_int32_t spi);
+ child_sa_t* (*get_child_sa) (ike_sa_t *this, u_int32_t spi);
/**
- * @brief establish the IKE SA
+ * @brief Close the CHILD SA with the specified reqid.
+ *
+ * Looks for a CHILD SA owned by this IKE_SA, deletes it and
+ * notify's the remote peer about the delete. The associated
+ * states and policies in the kernel get deleted, if they exist.
*
* @param this calling object
- */
- void (*establish) (protected_ike_sa_t *this);
-
- /**
- * @brief Get the last responded message.
- *
- * @param this calling object
- * @return
- * - last received as message_t object
- * - NULL if no last request available
- */
- message_t *(*get_last_responded_message) (protected_ike_sa_t *this);
-
- /**
- * @brief Get the last requested message.
- *
- * @param this calling object
- * @return
- * - last sent as message_t object
- * - NULL if no last request available
- */
- message_t *(*get_last_requested_message) (protected_ike_sa_t *this);
-
- /**
- * @brief Resets message counters and does destroy stored received and sent messages.
+ * @param reqid reqid of the child SA, as used in the kernel
+ * @return
+ * - NOT_FOUND, if IKE_SA has no such CHILD_SA
+ * - SUCCESS, if deleted and delete message sent
*
- * @param this calling object
- */
- void (*reset_message_buffers) (protected_ike_sa_t *this);
+ * @TODO use spi, not reqid
+ */
+ status_t (*delete_child_sa) (ike_sa_t *this, u_int32_t reqid);
/**
- * @brief Set NAT detection status for local host.
+ * @brief Rekey the CHILD SA with the specified reqid.
*
- * @param this calling object
- * @param nat if TRUE, local host is behing NAT
- */
- void (*set_my_host_behind_nat) (protected_ike_sa_t *this, bool nat);
-
- /**
- * @brief Set NAT detection status for remote host.
+ * Looks for a CHILD SA owned by this IKE_SA, and start the rekeing.
*
- * @param this calling object
- * @param nat if TRUE, remote host is behing NAT
+ * @param this calling object
+ * @param spi security parameter index identifying the SA to rekey
+ * @return
+ * - NOT_FOUND, if IKE_SA has no such CHILD_SA
+ * - SUCCESS, if rekeying initiated
+ *
+ * @TODO use spi, not reqid
*/
- void (*set_other_host_behind_nat) (protected_ike_sa_t *this, bool nat);
-
+ status_t (*rekey_child_sa) (ike_sa_t *this, u_int32_t reqid);
+
/**
- * @brief Generate NAT-D payload hash.
- *
- * @param this calling object
- * @param spi_i IKE SPI of initiator
- * @param spi_r IKE SPI of responder
- * @param host address and port of the host/interface
- * @return chunk containing calculated NAT-D hash
+ * @brief Associates a child SA to this IKE SA
+ *
+ * @param this calling object
+ * @param child_sa child_sa to add
*/
- chunk_t (*generate_natd_hash) (protected_ike_sa_t *this, u_int64_t spi_i, u_int64_t spi_r, host_t *host);
-
+ void (*add_child_sa) (ike_sa_t *this, child_sa_t *child_sa);
+
/**
- * @brief Dynamically update hosts on the associated connection.
- *
- * Warning: me and other host are cloned.
- *
- * @param this calling object
- * @param me local address and port
- * @param other remote address and port
+ * @brief Destroys a CHILD_SA upon request from the other peer.
+ *
+ * @param this calling object
+ * @param spi inbound spi of the CHILD_SA to destroy
+ * @return outbound spi of the destroyed CHILD_SA
*/
- status_t (*update_connection_hosts) (protected_ike_sa_t *this, host_t *me, host_t *other);
-
+ u_int32_t (*destroy_child_sa) (ike_sa_t *this, u_int32_t spi);
+
/**
- * @brief Return the message id of the last DPD message
+ * @brief Destroys a ike_sa_t object.
*
- * @param this calling object
- * @return the messages id
+ * @param this calling object
*/
- u_int32_t (*get_last_dpd_message_id) (protected_ike_sa_t *this);
+ void (*destroy) (ike_sa_t *this);
};
-
/**
* @brief Creates an ike_sa_t object with a specific ID.
- *
- * @warning the Content of internal ike_sa_id_t object can change over time
- * e.g. when a IKE_SA_INIT has been finished.
*
- * @param[in] ike_sa_id ike_sa_id_t object to associate with new IKE_SA.
- * The object is internal getting cloned
- * and so has to be destroyed by the caller.
+ * The ID gets cloned internally.
+ *
+ * @param[in] ike_sa_id ike_sa_id_t object to associate with new IKE_SA
* @return ike_sa_t object
*
* @ingroup sa
*/
-ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id);
+ike_sa_t *ike_sa_create(ike_sa_id_t *ike_sa_id);
#endif /*IKE_SA_H_*/
diff --git a/src/charon/sa/ike_sa_id.c b/src/charon/sa/ike_sa_id.c
index bf3a05d11..4f1f33bdc 100644
--- a/src/charon/sa/ike_sa_id.c
+++ b/src/charon/sa/ike_sa_id.c
@@ -181,5 +181,5 @@ ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi,
this->responder_spi = responder_spi;
this->is_initiator_flag = is_initiator_flag;
- return (&this->public);
+ return &this->public;
}
diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c
index 82f5d22af..1aad1b393 100644
--- a/src/charon/sa/ike_sa_manager.c
+++ b/src/charon/sa/ike_sa_manager.c
@@ -175,7 +175,7 @@ struct private_ike_sa_manager_t {
status_t (*get_entry_by_sa) (private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry);
/**
- * @brief Felete an entry from the linked list.
+ * @brief Delete an entry from the linked list.
*
* @param this calling object
* @param entry entry to delete
@@ -229,10 +229,13 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike
if (current->ike_sa_id->get_responder_spi(current->ike_sa_id) == 0)
{
/* seems to be a half ready ike_sa */
- if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) == ike_sa_id->get_initiator_spi(ike_sa_id))
- && (ike_sa_id->is_initiator(ike_sa_id) == current->ike_sa_id->is_initiator(current->ike_sa_id)))
+ if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) ==
+ ike_sa_id->get_initiator_spi(ike_sa_id)) &&
+ (ike_sa_id->is_initiator(ike_sa_id) ==
+ current->ike_sa_id->is_initiator(current->ike_sa_id)))
{
- this->logger->log(this->logger, CONTROL|LEVEL2, "found entry by initiator spi %d",
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "found entry by initiator spi %d",
ike_sa_id->get_initiator_spi(ike_sa_id));
*entry = current;
status = SUCCESS;
@@ -241,8 +244,10 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike
}
else if (ike_sa_id->get_responder_spi(ike_sa_id) == 0)
{
- if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) == ike_sa_id->get_initiator_spi(ike_sa_id))
- && (ike_sa_id->is_initiator(ike_sa_id) == current->ike_sa_id->is_initiator(current->ike_sa_id)))
+ if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) ==
+ ike_sa_id->get_initiator_spi(ike_sa_id)) &&
+ (ike_sa_id->is_initiator(ike_sa_id) ==
+ current->ike_sa_id->is_initiator(current->ike_sa_id)))
{
this->logger->log(this->logger, CONTROL|LEVEL2, "found entry by initiator spi %d",
ike_sa_id->get_initiator_spi(ike_sa_id));
@@ -315,7 +320,8 @@ static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *ent
iterator->current(iterator, (void**)&current);
if (current == entry)
{
- this->logger->log(this->logger, CONTROL|LEVEL2, "found entry by pointer. Going to delete it.");
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "found entry by pointer. Going to delete it");
iterator->remove(iterator);
entry->destroy(entry);
status = SUCCESS;
@@ -355,6 +361,11 @@ static void create_and_checkout(private_ike_sa_manager_t *this,ike_sa_t **ike_sa
/* create entry */
new_ike_sa_entry = ike_sa_entry_create(new_ike_sa_id);
new_ike_sa_id->destroy(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");
/* each access is locked */
pthread_mutex_lock(&(this->mutex));
@@ -362,7 +373,8 @@ static void create_and_checkout(private_ike_sa_manager_t *this,ike_sa_t **ike_sa
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");
+ 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;
@@ -379,6 +391,15 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
bool original_initiator;
status_t retval;
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "checkout IKE_SA %llx:%llx, role %s",
+ 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");
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "%d IKE_SAs in manager",
+ this->ike_sa_list->get_count(this->ike_sa_list));
+
/* each access is locked */
pthread_mutex_lock(&(this->mutex));
@@ -399,7 +420,8 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
/* can we give this ike_sa out to new requesters?*/
if (entry->driveout_new_threads)
{
- this->logger->log(this->logger, CONTROL|LEVEL1, "drive out new thread for existing IKE_SA");
+ this->logger->log(this->logger, CONTROL|LEVEL1,
+ "drive out new thread for existing IKE_SA");
/* no we can't */
retval = NOT_FOUND;
}
@@ -422,12 +444,14 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
{
/* 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");
+ 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");
+ 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;
@@ -438,7 +462,8 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
}
else
{
- this->logger->log(this->logger, ERROR|LEVEL1, "IKE SA not stored in known IKE_SA list");
+ this->logger->log(this->logger, ERROR|LEVEL1,
+ "IKE SA not stored in known IKE_SA 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;
@@ -469,11 +494,12 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *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 ,"IKE_SA added to list of known IKE_SA's");
+ this->logger->log(this->logger, CONTROL|LEVEL1,
+ "IKE_SA added to list of known IKE_SA's");
new_ike_sa_entry->checked_out = TRUE;
*ike_sa = new_ike_sa_entry->ike_sa;
- retval = CREATED;
+ retval = SUCCESS;
}
else
{
@@ -482,7 +508,7 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
/* DON'T use return, we must unlock the mutex! */
retval = INVALID_ARG;
}
-
+
pthread_mutex_unlock(&(this->mutex));
/* OK, unlocked... */
return retval;
@@ -491,7 +517,8 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
/**
* Implementation of of ike_sa_manager.checkout_by_reqid.
*/
-static status_t checkout_by_reqid(private_ike_sa_manager_t *this, u_int32_t reqid, ike_sa_t **ike_sa)
+static status_t checkout_by_reqid(private_ike_sa_manager_t *this,
+ u_int32_t reqid, ike_sa_t **ike_sa)
{
iterator_t *iterator;
status_t status = NOT_FOUND;
@@ -600,15 +627,16 @@ linked_list_t *get_ike_sa_list_by_name(private_ike_sa_manager_t* this, const cha
static void log_status(private_ike_sa_manager_t* this, logger_t* logger, char* name)
{
iterator_t *iterator;
+ u_int instances;
pthread_mutex_lock(&(this->mutex));
- iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
-
- if (iterator->get_count(iterator))
+ instances = this->ike_sa_list->get_count(this->ike_sa_list);
+ if (instances)
{
- logger->log(logger, CONTROL, "Instances:");
+ logger->log(logger, CONTROL, "Instances (%d):", instances);
}
+ iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
while (iterator->has_next(iterator))
{
ike_sa_entry_t *entry;
@@ -633,6 +661,15 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
*/
status_t retval;
ike_sa_entry_t *entry;
+ ike_sa_id_t *ike_sa_id;
+
+ ike_sa_id = ike_sa->get_id(ike_sa);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "checkin IKE_SA %llx:%llx, role %s",
+ 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");
pthread_mutex_lock(&(this->mutex));
@@ -649,10 +686,14 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
}
else
{
- this->logger->log(this->logger, ERROR, "tried to check in nonexisting IKE_SA");
+ this->logger->log(this->logger, ERROR,
+ "tried to check in nonexisting IKE_SA");
/* this SA is no more, this REALLY should not happen */
retval = NOT_FOUND;
}
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "%d IKE_SAs in manager now",
+ this->ike_sa_list->get_count(this->ike_sa_list));
pthread_mutex_unlock(&(this->mutex));
return retval;
}
@@ -670,6 +711,14 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik
*/
ike_sa_entry_t *entry;
status_t retval;
+ ike_sa_id_t *ike_sa_id;
+
+ ike_sa_id = ike_sa->get_id(ike_sa);
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "checkin and destroy IKE_SA %llx:%llx, role %s",
+ 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");
pthread_mutex_lock(&(this->mutex));
@@ -690,12 +739,14 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik
}
/* ok, we are alone now, no threads waiting in the entry's condvar */
this->delete_entry(this, entry);
- this->logger->log(this->logger, CONTROL|LEVEL1, "check-in and destroy of IKE_SA successful");
+ this->logger->log(this->logger, CONTROL|LEVEL1,
+ "check-in and destroy of IKE_SA successful");
retval = SUCCESS;
}
else
{
- this->logger->log(this->logger,ERROR, "tried to check-in and delete nonexisting IKE_SA");
+ this->logger->log(this->logger,ERROR,
+ "tried to check-in and delete nonexisting IKE_SA");
retval = NOT_FOUND;
}
@@ -715,9 +766,15 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
*/
ike_sa_entry_t *entry;
status_t retval;
-
+
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "delete IKE_SA %llx:%llx, role %s",
+ 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");
+
pthread_mutex_lock(&(this->mutex));
-
+
if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
{
/* we try a delete. If it succeeds, our job is done here. The
@@ -725,11 +782,13 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
*/
if (entry->ike_sa->delete(entry->ike_sa) == SUCCESS)
{
- this->logger->log(this->logger, CONTROL|LEVEL1, "initiated delete for IKE_SA");
+ this->logger->log(this->logger, CONTROL|LEVEL1,
+ "initiated delete for IKE_SA");
}
- /* but if the IKE SA is not in a state where the deletion is negotiated with
- * the other peer, we can destroy the IKE SA on our own. For this, we must
- * be sure that really NO other threads are waiting for this SA...
+ /* but if the IKE SA is not in a state where the deletion is
+ * negotiated with the other peer, we can destroy the IKE SA on our own.
+ * For this, we must be sure that really NO other threads are
+ * waiting for this SA...
*/
else
{
@@ -740,7 +799,8 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
{
/* wake up all */
pthread_cond_broadcast(&(entry->condvar));
- /* and the nice thing, they will wake us again when their work is done */
+ /* and the nice thing, they will wake us again when their work
+ * is done */
pthread_cond_wait(&(entry->condvar), &(this->mutex));
}
/* ok, we are alone now, no threads waiting in the entry's condvar */
@@ -751,7 +811,8 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
}
else
{
- this->logger->log(this->logger,ERROR, "tried to delete nonexisting IKE_SA");
+ this->logger->log(this->logger,ERROR,
+ "tried to delete nonexisting IKE_SA");
retval = NOT_FOUND;
}
@@ -770,13 +831,12 @@ static void destroy(private_ike_sa_manager_t *this)
ike_sa_entry_t *entry;
pthread_mutex_lock(&(this->mutex));
-
- this->logger->log(this->logger, CONTROL|LEVEL1, "going to destroy IKE_SA manager and all managed IKE_SA's");
-
+ this->logger->log(this->logger, CONTROL|LEVEL1,
+ "going to destroy IKE_SA manager and all managed IKE_SA's");
/* Step 1: drive out all waiting threads */
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "set driveout flags for all stored IKE_SA's");
iterator = list->create_iterator(list, TRUE);
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "set driveout flags for all stored IKE_SA's");
while (iterator->has_next(iterator))
{
iterator->current(iterator, (void**)&entry);
@@ -784,8 +844,8 @@ static void destroy(private_ike_sa_manager_t *this)
entry->driveout_new_threads = TRUE;
entry->driveout_waiting_threads = TRUE;
}
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "wait for all threads to leave IKE_SA's");
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "wait for all threads to leave IKE_SA's");
/* Step 2: wait until all are gone */
iterator->reset(iterator);
while (iterator->has_next(iterator))
diff --git a/src/charon/sa/states/create_child_sa_requested.c b/src/charon/sa/states/create_child_sa_requested.c
deleted file mode 100644
index 3e7abe1b8..000000000
--- a/src/charon/sa/states/create_child_sa_requested.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/**
- * @file create_child_sa_requested.c
- *
- * @brief State after a CREATE_CHILD_SA request was sent.
- *
- */
-
-/*
- * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 <string.h>
-
-#include "create_child_sa_requested.h"
-
-#include <sa/child_sa.h>
-#include <sa/states/delete_ike_sa_requested.h>
-#include <sa/states/ike_sa_established.h>
-#include <encoding/payloads/ts_payload.h>
-#include <encoding/payloads/sa_payload.h>
-#include <encoding/payloads/nonce_payload.h>
-#include <encoding/payloads/notify_payload.h>
-#include <utils/logger_manager.h>
-
-
-typedef struct private_create_child_sa_requested_t private_create_child_sa_requested_t;
-
-/**
- * Private data of a create_child_sa_requested_t object.
- */
-struct private_create_child_sa_requested_t {
- /**
- * Public interface of create_child_sa_requested_t.
- */
- create_child_sa_requested_t public;
-
- /**
- * Assigned IKE_SA.
- */
- protected_ike_sa_t *ike_sa;
-
- /**
- * nonce chosen by initiator
- */
- chunk_t nonce_i;
-
- /**
- * nonce chosen by the responder
- */
- chunk_t nonce_r;
-
- /**
- * Policy to use for new child_sa
- */
- policy_t *policy;
-
- /**
- * Proposal negotiated
- */
- proposal_t *proposal;
-
- /**
- * Negotiated list of traffic selectors for local site
- */
- linked_list_t *my_ts;
-
- /**
- * Negotiated list of traffic selectors for remote site
- */
- linked_list_t *other_ts;
-
- /**
- * Child SA to create
- */
- child_sa_t *child_sa;
-
- /**
- * Reqid of the old CHILD_SA, when rekeying
- */
- u_int32_t reqid;
-
- /**
- * Assigned logger.
- *
- * Is logger of ike_sa!
- */
- logger_t *logger;
-};
-
-/**
- * Implementation of private_create_child_sa_requested_t.process_sa_payload.
- */
-static status_t process_sa_payload(private_create_child_sa_requested_t *this, sa_payload_t *sa_payload)
-{
- proposal_t *proposal, *proposal_tmp;
- linked_list_t *proposal_list;
-
- /* get his selected proposal */
- proposal_list = sa_payload->get_proposals(sa_payload);
- /* check count of proposals */
- if (proposal_list->get_count(proposal_list) == 0)
- {
- /* no proposal? we accept this, but no child sa is built */
- this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA reply contained no proposals. CHILD_SA not created");
- proposal_list->destroy(proposal_list);
- return FAILED;
- }
- if (proposal_list->get_count(proposal_list) > 1)
- {
- this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA reply contained %d proposals. Aborting",
- proposal_list->get_count(proposal_list));
- while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
- {
- proposal->destroy(proposal);
- }
- proposal_list->destroy(proposal_list);
- return FAILED;
- }
-
- /* we have to re-check here if other's selection is valid */
- proposal = this->policy->select_proposal(this->policy, proposal_list);
- /* list not needed anymore */
- while (proposal_list->remove_last(proposal_list, (void**)&proposal_tmp) == SUCCESS)
- {
- proposal_tmp->destroy(proposal_tmp);
- }
- proposal_list->destroy(proposal_list);
- /* got a match? */
- if (proposal == NULL)
- {
- this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA reply contained a not offered proposal. Aborting");
- return FAILED;
- }
-
- /* apply proposal */
- this->proposal = proposal;
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_create_child_sa_requested_t.process_ts_payload.
- */
-static status_t process_ts_payload(private_create_child_sa_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload)
-{
- linked_list_t *ts_received, *ts_selected;
- traffic_selector_t *ts;
-
- /* get ts form payload */
- ts_received = ts_payload->get_traffic_selectors(ts_payload);
- /* select ts depending on payload type */
- if (ts_initiator)
- {
- ts_selected = this->policy->select_my_traffic_selectors(this->policy, ts_received);
- this->my_ts = ts_selected;
- }
- else
- {
- ts_selected = this->policy->select_other_traffic_selectors(this->policy, ts_received);
- this->other_ts = ts_selected;
- }
- /* check if the responder selected valid proposals */
- if (ts_selected->get_count(ts_selected) != ts_received->get_count(ts_received))
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained not offered traffic selectors.");
- }
-
- /* cleanup */
- while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS)
- {
- ts->destroy(ts);
- }
- ts_received->destroy(ts_received);
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_create_child_sa_requested_t.process_nonce_payload.
- */
-static status_t process_nonce_payload(private_create_child_sa_requested_t *this, nonce_payload_t *nonce_request)
-{
- this->nonce_r = nonce_request->get_nonce(nonce_request);
- return SUCCESS;
-}
-
-/**
- * Process a CREATE_CHILD_SA response
- */
-static status_t process_message(private_create_child_sa_requested_t *this, message_t *response)
-{
- ts_payload_t *tsi_request = NULL, *tsr_request = NULL;
- sa_payload_t *sa_request = NULL;
- nonce_payload_t *nonce_request = NULL;
- ike_sa_id_t *ike_sa_id;
- iterator_t *payloads;
- crypter_t *crypter;
- signer_t *signer;
- status_t status;
- chunk_t seed;
- prf_plus_t *prf_plus;
- child_sa_t *old_child_sa;
-
- this->policy = this->ike_sa->get_policy(this->ike_sa);
- if (response->get_exchange_type(response) != CREATE_CHILD_SA)
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state create_child_sa_requested",
- mapping_find(exchange_type_m, response->get_exchange_type(response)));
- return FAILED;
- }
-
- if (response->get_request(response))
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "CREATE_CHILD_SA requests not allowed state create_child_sa_requested");
- /* TODO: our state implementation currently can not handle incoming requests cleanly here.
- * If a request comes in before an outstanding reply, we can not handle it the correct way.
- * Currently, we create a ESTABLISHED state and let it process the message... But we
- * need changes in the whole state mechanism.
- */
- state_t *state = (state_t*)ike_sa_established_create(this->ike_sa);
- state->process_message(state, response);
- state->destroy(state);
- return SUCCESS;
- }
-
- /* get signer for verification and crypter for decryption */
- ike_sa_id = this->ike_sa->public.get_id(&this->ike_sa->public);
- if (!ike_sa_id->is_initiator(ike_sa_id))
- {
- crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
- signer = this->ike_sa->get_signer_initiator(this->ike_sa);
- }
- else
- {
- crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
- signer = this->ike_sa->get_signer_responder(this->ike_sa);
- }
-
- /* parse incoming message */
- status = response->parse_body(response, crypter, signer);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA r decryption failed. Ignoring message");
- return status;
- }
-
- /* iterate over incoming payloads. Message is verified, we can be sure there are the required payloads */
- payloads = response->get_payload_iterator(response);
- while (payloads->has_next(payloads))
- {
- payload_t *payload;
- payloads->current(payloads, (void**)&payload);
-
- switch (payload->get_type(payload))
- {
- case SECURITY_ASSOCIATION:
- {
- sa_request = (sa_payload_t*)payload;
- break;
- }
- case TRAFFIC_SELECTOR_INITIATOR:
- {
- tsi_request = (ts_payload_t*)payload;
- break;
- }
- case TRAFFIC_SELECTOR_RESPONDER:
- {
- tsr_request = (ts_payload_t*)payload;
- break;
- }
- case NONCE:
- {
- nonce_request = (nonce_payload_t*)payload;
- break;
- }
- case NOTIFY:
- {
- /* TODO: handle notifys */
- break;
- }
- default:
- {
- this->logger->log(this->logger, ERROR|LEVEL1, "Ignoring payload %s (%d)",
- mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
- break;
- }
- }
- }
- /* iterator can be destroyed */
- payloads->destroy(payloads);
-
- /* check if we have all payloads */
- if (!(sa_request && nonce_request && tsi_request && tsr_request))
- {
- this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA request did not contain all required payloads. Ignored");
- return FAILED;
- }
-
- /* add payloads to it */
- status = process_nonce_payload(this, nonce_request);
- if (status != SUCCESS)
- {
- response->destroy(response);
- return status;
- }
- status = process_sa_payload(this, sa_request);
- if (status != SUCCESS)
- {
- response->destroy(response);
- return status;
- }
- status = process_ts_payload(this, TRUE, tsi_request);
- if (status != SUCCESS)
- {
- response->destroy(response);
- return status;
- }
- status = process_ts_payload(this, FALSE, tsr_request);
- if (status != SUCCESS)
- {
- response->destroy(response);
- return status;
- }
-
- /* install child SAs for AH and esp */
- if (!this->proposal)
- {
- this->logger->log(this->logger, CONTROL, "Proposal negotiation failed, no CHILD_SA built");
- this->child_sa->destroy(this->child_sa);
- this->child_sa = NULL;
- }
- else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0)
- {
- this->logger->log(this->logger, CONTROL, "Traffic selector negotiation failed, no CHILD_SA built");
- this->child_sa->destroy(this->child_sa);
- this->child_sa = NULL;
- }
- else
- {
- seed = chunk_alloc(this->nonce_i.len + this->nonce_r.len);
- memcpy(seed.ptr, this->nonce_i.ptr, this->nonce_i.len);
- memcpy(seed.ptr + this->nonce_i.len, this->nonce_r.ptr, this->nonce_r.len);
- prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
-
- this->logger->log_chunk(this->logger, RAW|LEVEL2, "Rekey seed", seed);
- chunk_free(&seed);
-
- status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
- prf_plus->destroy(prf_plus);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA");
- return DESTROY_ME;
- }
- status = this->child_sa->add_policies(this->child_sa, this->my_ts, this->other_ts);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA policy! Deleting IKE_SA");
- return DESTROY_ME;
- }
- this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
- }
-
- this->ike_sa->set_last_replied_message_id(this->ike_sa, response->get_message_id(response));
-
- /* create new state */
- this->ike_sa->set_new_state(this->ike_sa, (state_t*)ike_sa_established_create(this->ike_sa));
-
- /* if we are rekeying, inform the old child SA that it has been superseeded and
- * start its delete */
- if (this->reqid)
- {
- old_child_sa = this->ike_sa->public.get_child_sa(&this->ike_sa->public, this->reqid);
- if (old_child_sa)
- {
- old_child_sa->set_rekeyed(old_child_sa);
- }
-
- this->ike_sa->public.delete_child_sa(&this->ike_sa->public, this->reqid);
- }
- this->public.state_interface.destroy(&this->public.state_interface);
- return SUCCESS;
-}
-
-/**
- * Implements state_t.get_state
- */
-static ike_sa_state_t get_state(private_create_child_sa_requested_t *this)
-{
- return CREATE_CHILD_SA_REQUESTED;
-}
-
-/**
- * Implementation of state_t.destroy.
- */
-static void destroy(private_create_child_sa_requested_t *this)
-{
- chunk_free(&this->nonce_i);
- chunk_free(&this->nonce_r);
- free(this);
-}
-
-/*
- * Described in header.
- */
-create_child_sa_requested_t *create_child_sa_requested_create(protected_ike_sa_t *ike_sa, child_sa_t *child_sa, chunk_t nonce_i, u_int32_t reqid)
-{
- private_create_child_sa_requested_t *this = malloc_thing(private_create_child_sa_requested_t);
-
- /* interface functions */
- this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
- this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
- this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
-
- /* private data */
- this->ike_sa = ike_sa;
- this->child_sa = child_sa;
- this->nonce_i = nonce_i;
- this->nonce_r = CHUNK_INITIALIZER;
- this->reqid = reqid;
- this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
-
- return &(this->public);
-}
diff --git a/src/charon/sa/states/create_child_sa_requested.h b/src/charon/sa/states/create_child_sa_requested.h
deleted file mode 100644
index 20c17b6a1..000000000
--- a/src/charon/sa/states/create_child_sa_requested.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * @file create_child_sa_requested.h
- *
- * @brief Interface of create_child_sa_requested_t.
- *
- */
-
-/*
- * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 CREATE_CHILD_SA_REQEUSTED_H_
-#define CREATE_CHILD_SA_REQEUSTED_H_
-
-#include <sa/states/state.h>
-#include <sa/ike_sa.h>
-#include <sa/child_sa.h>
-
-typedef struct create_child_sa_requested_t create_child_sa_requested_t;
-
-/**
- * @brief State after a CREATE_CHILD_SA request was sent.
- *
- * @b Constructors:
- * - create_child_sa_requested_create()
- *
- * @ingroup states
- */
-struct create_child_sa_requested_t {
- /**
- * methods of the state_t interface
- */
- state_t state_interface;
-};
-
-/**
- * @brief Constructor of class create_child_sa_requested_t
- *
- * If this CREATE_CHILD_SA message is to rekey a CHILD_SA,
- * the child_sa with the specified reqid gets deleted after a new
- * one is set up.
- *
- * @param ike_sa assigned ike_sa
- * @param child_sa newly created child sa to complete
- * @param nonce nonce sent at initialization
- * @param reqid reqid, when rekeying a child SA.
- * @return created create_child_sa_requested_t object
- *
- * @ingroup states
- */
-create_child_sa_requested_t *create_child_sa_requested_create(protected_ike_sa_t *ike_sa, child_sa_t *child_sa, chunk_t nonce_i, u_int32_t reqid);
-
-#endif /*CREATE_CHILD_SA_REQEUSTED_H_*/
diff --git a/src/charon/sa/states/delete_child_sa_requested.c b/src/charon/sa/states/delete_child_sa_requested.c
deleted file mode 100644
index 8cad93d8d..000000000
--- a/src/charon/sa/states/delete_child_sa_requested.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/**
- * @file delete_child_sa_requested.c
- *
- * @brief State after a CREATE_CHILD_SA request was sent.
- *
- */
-
-/*
- * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 <string.h>
-
-#include "delete_child_sa_requested.h"
-
-#include <sa/child_sa.h>
-#include <sa/states/delete_ike_sa_requested.h>
-#include <sa/states/ike_sa_established.h>
-#include <encoding/payloads/notify_payload.h>
-#include <encoding/payloads/delete_payload.h>
-#include <utils/logger_manager.h>
-
-
-typedef struct private_delete_child_sa_requested_t private_delete_child_sa_requested_t;
-
-/**
- * Private data of a delete_child_sa_requested_t object.
- */
-struct private_delete_child_sa_requested_t {
- /**
- * Public interface of delete_child_sa_requested_t.
- */
- delete_child_sa_requested_t public;
-
- /**
- * Assigned IKE_SA.
- */
- protected_ike_sa_t *ike_sa;
-
- /**
- * Assigned logger.
- *
- * Is logger of ike_sa!
- */
- logger_t *logger;
-};
-
-
-/**
- * Process the response
- */
-static status_t process_message(private_delete_child_sa_requested_t *this, message_t *response)
-{
- ike_sa_id_t *ike_sa_id;
- crypter_t *crypter;
- signer_t *signer;
- status_t status;
- iterator_t *iterator;
- payload_t *payload;
- delete_payload_t *delete_response;
-
- if (response->get_exchange_type(response) != INFORMATIONAL)
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state delete_child_sa_requested",
- mapping_find(exchange_type_m, response->get_exchange_type(response)));
- return FAILED;
- }
-
- if (response->get_request(response))
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "INFORMATIONAL requests not allowed state delete_child_sa_requested");
- /* TODO: our state implementation currently can not handle incoming requests cleanly here.
- * If a request comes in before an outstanding reply, we can not handle it cleanly.
- * Currently, we create a ESTABLISHED state and let it process the message... But we
- * need changes in the whole state mechanism.
- */
- state_t *state = (state_t*)ike_sa_established_create(this->ike_sa);
- state->process_message(state, response);
- state->destroy(state);
- return SUCCESS;
- }
-
- /* get signer for verification and crypter for decryption */
- ike_sa_id = this->ike_sa->public.get_id(&this->ike_sa->public);
- if (!ike_sa_id->is_initiator(ike_sa_id))
- {
- crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
- signer = this->ike_sa->get_signer_initiator(this->ike_sa);
- }
- else
- {
- crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
- signer = this->ike_sa->get_signer_responder(this->ike_sa);
- }
-
- /* parse incoming message */
- status = response->parse_body(response, crypter, signer);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "INFORMATIONAL response decryption failed. Ignoring message");
- return status;
- }
-
- iterator = response->get_payload_iterator(response);
- while (iterator->has_next(iterator)) {
- iterator->current(iterator, (void**)&payload);
- switch (payload->get_type(payload))
- {
- case DELETE:
- delete_response = (delete_payload_t*)payload;
- break;
- default:
- break;
- }
-
- }
- iterator->destroy(iterator);
-
- if (delete_response)
- {
- iterator = delete_response->create_spi_iterator(delete_response);
- while (iterator->has_next(iterator))
- {
- u_int32_t spi;
- iterator->current(iterator, (void**)&spi);
- this->logger->log(this->logger, CONTROL, "DELETE request for CHILD_SA with SPI 0x%x received", spi);
- this->ike_sa->destroy_child_sa(this->ike_sa, spi);
- }
- iterator->destroy(iterator);
- }
-
- this->ike_sa->set_last_replied_message_id(this->ike_sa, response->get_message_id(response));
-
- /* create new state */
- this->ike_sa->set_new_state(this->ike_sa, (state_t*)ike_sa_established_create(this->ike_sa));
- this->public.state_interface.destroy(&this->public.state_interface);
-
- return SUCCESS;
-}
-
-/**
- * Implements state_t.get_state
- */
-static ike_sa_state_t get_state(private_delete_child_sa_requested_t *this)
-{
- return DELETE_CHILD_SA_REQUESTED;
-}
-
-/**
- * Implementation of state_t.destroy.
- */
-static void destroy(private_delete_child_sa_requested_t *this)
-{
- free(this);
-}
-
-/*
- * Described in header.
- */
-delete_child_sa_requested_t *delete_child_sa_requested_create(protected_ike_sa_t *ike_sa)
-{
- private_delete_child_sa_requested_t *this = malloc_thing(private_delete_child_sa_requested_t);
-
- /* interface functions */
- this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
- this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
- this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
-
- /* private data */
- this->ike_sa = ike_sa;
- this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
-
- return &(this->public);
-}
diff --git a/src/charon/sa/states/delete_child_sa_requested.h b/src/charon/sa/states/delete_child_sa_requested.h
deleted file mode 100644
index e70ff182d..000000000
--- a/src/charon/sa/states/delete_child_sa_requested.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * @file delete_child_sa_requested.h
- *
- * @brief Interface of delete_child_sa_requested_t.
- *
- */
-
-/*
- * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 DELETE_CHILD_SA_REQEUSTED_H_
-#define DELETE_CHILD_SA_REQEUSTED_H_
-
-#include <sa/states/state.h>
-#include <sa/ike_sa.h>
-#include <sa/child_sa.h>
-
-typedef struct delete_child_sa_requested_t delete_child_sa_requested_t;
-
-/**
- * @brief State after a CREATE_CHILD_SA request was sent.
- *
- * @b Constructors:
- * - delete_child_sa_requested_create()
- *
- * @ingroup states
- */
-struct delete_child_sa_requested_t {
- /**
- * methods of the state_t interface
- */
- state_t state_interface;
-};
-
-/**
- * @brief Constructor of class delete_child_sa_requested_t
- *
- * @param ike_sa assigned ike_sa
- * @return created delete_child_sa_requested_t object
- *
- * @ingroup states
- */
-delete_child_sa_requested_t *delete_child_sa_requested_create(protected_ike_sa_t *ike_sa);
-
-#endif /*DELETE_CHILD_SA_REQEUSTED_H_*/
diff --git a/src/charon/sa/states/delete_ike_sa_requested.c b/src/charon/sa/states/delete_ike_sa_requested.c
deleted file mode 100644
index 36e9c2fb2..000000000
--- a/src/charon/sa/states/delete_ike_sa_requested.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/**
- * @file delete_ike_sa_requested.c
- *
- * @brief Implementation of delete_ike_sa_requested_t.
- *
- */
-
-/*
- * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 "delete_ike_sa_requested.h"
-
-#include <daemon.h>
-
-
-typedef struct private_delete_ike_sa_requested_t private_delete_ike_sa_requested_t;
-
-/**
- * Private data of a delete_ike_sa_requested_t object.
- */
-struct private_delete_ike_sa_requested_t {
-
- /**
- * methods of the state_t interface
- */
- delete_ike_sa_requested_t public;
-
- /**
- * Assigned IKE_SA.
- */
- protected_ike_sa_t *ike_sa;
-
- /**
- * Assigned logger. Use logger of IKE_SA.
- */
- logger_t *logger;
-};
-
-/**
- * Implements state_t.get_state
- */
-static status_t process_message(private_delete_ike_sa_requested_t *this, message_t *message)
-{
- ike_sa_id_t *ike_sa_id;
- crypter_t *crypter;
- signer_t *signer;
- status_t status;
-
- /* Notation as follows:
- * Mx{D} means: Message, with message ID "x", containing a Delete payload
- *
- * The clarifcation Document says in 5.8, that a IKE_SA delete should not
- * be acknowledged with the same delete. This only makes sense for CHILD_SAs,
- * as they are paired. IKE_SAs are not, there is only one for both ends.
- *
- * Normal case:
- * ----------------
- * Mx{D} -->
- * <-- Mx{}
- * Delete request is sent, and we wait for the acknowledge.
- *
- * Special case 1:
- * ---------------
- * Mx{D} -->
- * <-- My{D}
- * My{} -->
- * <-- Mx{}
- * Both initate a delete at the same time. We ack the delete, but wait for
- * our delete to be acknowledged.
- */
-
- if (message->get_exchange_type(message) != INFORMATIONAL)
- {
- /* anything other than information is ignored. We can an will not handle
- * messages such as CREATE_CHILD_SA */
- this->logger->log(this->logger, ERROR | LEVEL1,
- "%s messages not supported in state delete_ike_sa_requested. Ignored",
- mapping_find(exchange_type_m, message->get_exchange_type(message)));
- return FAILED;
- }
-
- if (message->get_request(message))
- {
- /* if it is a request, not a reply to our delete request, we
- * just acknowledge this. We stay in our state, as the other peer
- * has to ACK our request.
- */
- message_t *acknowledge;
- this->ike_sa->build_message(this->ike_sa, INFORMATIONAL, FALSE, &acknowledge);
- return this->ike_sa->send_response(this->ike_sa, acknowledge);
- }
-
- /* get signer for verification and crypter for decryption */
- ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public));
- if (!ike_sa_id->is_initiator(ike_sa_id))
- {
- crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
- signer = this->ike_sa->get_signer_initiator(this->ike_sa);
- }
- else
- {
- crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
- signer = this->ike_sa->get_signer_responder(this->ike_sa);
- }
-
- /* parse incoming message, check if it's proper signed */
- status = message->parse_body(message, crypter, signer);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "INFORMATIONAL message decryption failed. Ignoring message");
- return status;
- }
-
- /* ok, he knows about the deletion, destroy this IKE SA */
- return DESTROY_ME;
-}
-
-/**
- * Implementation of state_t.get_state.
- */
-static ike_sa_state_t get_state(private_delete_ike_sa_requested_t *this)
-{
- return DELETE_IKE_SA_REQUESTED;
-}
-
-/**
- * Implementation of state_t.get_state
- */
-static void destroy(private_delete_ike_sa_requested_t *this)
-{
- free(this);
-}
-
-/*
- * Described in header.
- */
-delete_ike_sa_requested_t *delete_ike_sa_requested_create(protected_ike_sa_t *ike_sa)
-{
- private_delete_ike_sa_requested_t *this = malloc_thing(private_delete_ike_sa_requested_t);
-
- /* interface functions */
- this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
- this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
- this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
-
- /* private data */
- this->ike_sa = ike_sa;
- this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
-
- return &(this->public);
-}
diff --git a/src/charon/sa/states/delete_ike_sa_requested.h b/src/charon/sa/states/delete_ike_sa_requested.h
deleted file mode 100644
index a010a0f5b..000000000
--- a/src/charon/sa/states/delete_ike_sa_requested.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * @file delete_ike_sa_requested.h
- *
- * @brief Interface of delete_ike_sa_requested_t.
- *
- */
-
-/*
- * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 DELETE_IKE_SA_REQUESTED_H_
-#define DELETE_IKE_SA_REQUESTED_H_
-
-#include <sa/states/state.h>
-#include <sa/ike_sa.h>
-
-typedef struct delete_ike_sa_requested_t delete_ike_sa_requested_t;
-
-/**
- * @brief This class represents an the state of a half closed IKE_SA.
- *
- * @b Constructors:
- * - delete_ike_sa_requested_create()
- *
- * @ingroup states
- */
-struct delete_ike_sa_requested_t {
- /**
- * methods of the state_t interface
- */
- state_t state_interface;
-
-};
-
-/**
- * @brief Constructor of class delete_ike_sa_requested_t
- *
- * @param ike_sa assigned ike_sa
- * @return created delete_ike_sa_requested_t object
- *
- * @ingroup states
- */
-delete_ike_sa_requested_t *delete_ike_sa_requested_create(protected_ike_sa_t *ike_sa);
-
-#endif /*DELETE_IKE_SA_REQUESTED_H_*/
diff --git a/src/charon/sa/states/ike_auth_requested.c b/src/charon/sa/states/ike_auth_requested.c
deleted file mode 100644
index b2d42fd60..000000000
--- a/src/charon/sa/states/ike_auth_requested.c
+++ /dev/null
@@ -1,719 +0,0 @@
-/**
- * @file ike_auth_requested.c
- *
- * @brief Implementation of ike_auth_requested_t.
- *
- */
-
-/*
- * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 <string.h>
-
-#include "ike_auth_requested.h"
-
-#include <daemon.h>
-#include <encoding/payloads/ts_payload.h>
-#include <encoding/payloads/sa_payload.h>
-#include <encoding/payloads/id_payload.h>
-#include <encoding/payloads/cert_payload.h>
-#include <encoding/payloads/auth_payload.h>
-#include <encoding/payloads/notify_payload.h>
-#include <crypto/signers/signer.h>
-#include <crypto/crypters/crypter.h>
-#include <sa/states/ike_sa_established.h>
-#include <sa/authenticator.h>
-#include <sa/child_sa.h>
-
-typedef struct private_ike_auth_requested_t private_ike_auth_requested_t;
-
-/**
- * Private data of a ike_auth_requested_t object.
- *
- */
-struct private_ike_auth_requested_t {
- /**
- * Public interface of ike_auth_requested_t.
- */
- ike_auth_requested_t public;
-
- /**
- * Assigned IKE_SA.
- */
- protected_ike_sa_t *ike_sa;
-
- /**
- * SA config, just a copy of the one stored in the ike_sa.
- */
- policy_t *policy;
-
- /**
- * Received nonce from responder.
- */
- chunk_t received_nonce;
-
- /**
- * Sent nonce in IKE_SA_INIT request.
- */
- chunk_t sent_nonce;
-
- /**
- * IKE_SA_INIT-Request in binary form.
- */
- chunk_t ike_sa_init_reply_data;
-
- /**
- * Proposal to setup CHILD_SA
- */
- proposal_t *proposal;
-
- /**
- * Traffic selectors applicable at our site
- */
- linked_list_t *my_ts;
-
- /**
- * Traffic selectors applicable at remote site
- */
- linked_list_t *other_ts;
-
- /**
- * Child sa created in ike_sa_init_requested
- */
- child_sa_t *child_sa;
-
- /**
- * Assigned Logger.
- *
- * Is logger of ike_sa!
- */
- logger_t *logger;
-
- /**
- * Process the IDr payload (check if other id is valid)
- *
- * @param this calling object
- * @param idr_payload ID payload of responder
- * @return
- * - SUCCESS
- * - DESTROY_ME
- */
- status_t (*process_idr_payload) (private_ike_auth_requested_t *this, id_payload_t *idr_payload);
-
- /**
- * Process received CERT payload
- *
- * @param this calling object
- * @param cert_payload payload to process
- * @return
- * - DESTROY_ME if IKE_SA should be deleted
- * - SUCCSS if processed successful
- */
- status_t (*process_cert_payload) (private_ike_auth_requested_t *this, cert_payload_t *cert_payload);
-
- /**
- * Process the SA payload (check if selected proposals are valid, setup child sa)
- *
- * @param this calling object
- * @param sa_payload SA payload of responder
- *
- * - SUCCESS
- * - DESTROY_ME
- */
- status_t (*process_sa_payload) (private_ike_auth_requested_t *this, sa_payload_t *sa_payload);
-
- /**
- * Process the AUTH payload (check authenticity of message)
- *
- * @param this calling object
- * @param auth_payload AUTH payload of responder
- * @param other_id_payload ID payload of responder
- *
- * - SUCCESS
- * - DESTROY_ME
- */
- status_t (*process_auth_payload) (private_ike_auth_requested_t *this, auth_payload_t *auth_payload, id_payload_t *other_id_payload);
-
- /**
- * Process the TS payload (check if selected traffic selectors are valid)
- *
- * @param this calling object
- * @param ts_initiator TRUE if TS payload is TSi, FALSE for TSr
- * @param ts_payload TS payload of responder
- *
- * - SUCCESS
- * - DESTROY_ME
- */
- status_t (*process_ts_payload) (private_ike_auth_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload);
-
- /**
- * Process a notify payload
- *
- * @param this calling object
- * @param notify_payload notify payload
- *
- * - SUCCESS
- * - FAILED
- * - DESTROY_ME
- */
- status_t (*process_notify_payload) (private_ike_auth_requested_t *this, notify_payload_t *notify_payload);
-
- /**
- * Destroy function called internally of this class after state change to
- * state IKE_SA_ESTABLISHED succeeded.
- *
- * This destroy function does not destroy objects which were passed to the new state.
- *
- * @param this calling object
- */
- void (*destroy_after_state_change) (private_ike_auth_requested_t *this);
-};
-
-
-/**
- * Implements state_t.process_message
- */
-static status_t process_message(private_ike_auth_requested_t *this, message_t *ike_auth_reply)
-{
- ts_payload_t *tsi_payload = NULL;
- ts_payload_t *tsr_payload = NULL;
- id_payload_t *idr_payload = NULL;
- cert_payload_t *cert_payload = NULL;
- auth_payload_t *auth_payload = NULL;
- sa_payload_t *sa_payload = NULL;
- iterator_t *payloads = NULL;
- crypter_t *crypter = NULL;
- signer_t *signer = NULL;
- status_t status;
- host_t *my_host, *other_host;
- identification_t *my_id, *other_id;
- chunk_t seed;
- prf_plus_t *prf_plus;
- connection_t *connection;
- policy_t *policy;
-
- if (ike_auth_reply->get_exchange_type(ike_auth_reply) != IKE_AUTH)
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "message of type %s not supported in state ike_auth_requested",
- mapping_find(exchange_type_m,ike_auth_reply->get_exchange_type(ike_auth_reply)));
- return FAILED;
- }
-
- if (ike_auth_reply->get_request(ike_auth_reply))
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "IKE_AUTH requests not allowed state ike_sa_init_responded");
- return FAILED;
- }
-
- /* get signer for verification and crypter for decryption */
- signer = this->ike_sa->get_signer_responder(this->ike_sa);
- crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
-
- /* parse incoming message */
- status = ike_auth_reply->parse_body(ike_auth_reply, crypter, signer);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH reply decryption failed. Ignoring message");
- return status;
- }
-
- this->policy = this->ike_sa->get_policy(this->ike_sa);
-
- /* we collect all payloads, which are processed later. Notify's are processed
- * in place, since we don't know how may are there.
- */
- payloads = ike_auth_reply->get_payload_iterator(ike_auth_reply);
- while (payloads->has_next(payloads))
- {
- payload_t *payload;
- payloads->current(payloads, (void**)&payload);
-
- switch (payload->get_type(payload))
- {
- case AUTHENTICATION:
- auth_payload = (auth_payload_t*)payload;
- break;
- case CERTIFICATE:
- cert_payload = (cert_payload_t*)payload;
- status = this->process_cert_payload(this, cert_payload);
- if (status != SUCCESS)
- {
- payloads->destroy(payloads);
- return status;
-
- }
- break;
- case ID_RESPONDER:
- idr_payload = (id_payload_t*)payload;
- break;
- case SECURITY_ASSOCIATION:
- sa_payload = (sa_payload_t*)payload;
- break;
- case TRAFFIC_SELECTOR_INITIATOR:
- tsi_payload = (ts_payload_t*)payload;
- break;
- case TRAFFIC_SELECTOR_RESPONDER:
- tsr_payload = (ts_payload_t*)payload;
- break;
- case NOTIFY:
- {
- notify_payload_t *notify_payload = (notify_payload_t *) payload;
-
- /* handle the notify directly, abort if no further processing required */
- status = this->process_notify_payload(this, notify_payload);
- if (status != SUCCESS)
- {
- payloads->destroy(payloads);
- return status;
- }
- }
- default:
- this->logger->log(this->logger, ERROR|LEVEL1, "ignoring Payload %s (%d)",
- mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
- break;
- }
- }
- /* iterator can be destroyed */
- payloads->destroy(payloads);
-
- /* check if we have all payloads */
- if (!(idr_payload && sa_payload && auth_payload && tsi_payload && tsr_payload))
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH reply did not contain all required payloads. Deleting IKE_SA");
- return DESTROY_ME;
- }
-
- status = this->ike_sa->update_connection_hosts(this->ike_sa,
- ike_auth_reply->get_destination(ike_auth_reply),
- ike_auth_reply->get_source(ike_auth_reply));
- if (status != SUCCESS)
- return status;
-
- /* process all payloads */
- status = this->process_idr_payload(this, idr_payload);
- if (status != SUCCESS)
- return status;
-
- status = this->process_auth_payload(this, auth_payload,idr_payload);
- if (status != SUCCESS)
- return status;
-
- status = this->process_sa_payload(this, sa_payload);
- if (status != SUCCESS)
- return status;
-
- status = this->process_ts_payload(this, TRUE, tsi_payload);
- if (status != SUCCESS)
- return status;
-
- status = this->process_ts_payload(this, FALSE, tsr_payload);
- if (status != SUCCESS)
- return status;
-
- /* install child SAs for AH and esp */
- if (!this->child_sa)
- {
- this->logger->log(this->logger, CONTROL, "no CHILD_SA requested, no CHILD_SA built");
- }
- else if (!this->proposal)
- {
- this->logger->log(this->logger, CONTROL, "proposal negotiation failed, no CHILD_SA built");
- this->child_sa->destroy(this->child_sa);
- this->child_sa = NULL;
- }
- else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0)
- {
- this->logger->log(this->logger, CONTROL, "traffic selector negotiation failed, no CHILD_SA built");
- this->child_sa->destroy(this->child_sa);
- this->child_sa = NULL;
- }
- else
- {
- seed = chunk_alloc(this->sent_nonce.len + this->received_nonce.len);
- memcpy(seed.ptr, this->sent_nonce.ptr, this->sent_nonce.len);
- memcpy(seed.ptr + this->sent_nonce.len, this->received_nonce.ptr, this->received_nonce.len);
- prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
- chunk_free(&seed);
-
- status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
- prf_plus->destroy(prf_plus);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "could not install CHILD_SA! Deleting IKE_SA");
- return DESTROY_ME;
- }
- status = this->child_sa->add_policies(this->child_sa, this->my_ts, this->other_ts);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "could not install CHILD_SA policy! Deleting IKE_SA");
- return DESTROY_ME;
- }
- this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
- }
-
- this->ike_sa->set_last_replied_message_id(this->ike_sa,ike_auth_reply->get_message_id(ike_auth_reply));
-
- /* create new state */
- this->ike_sa->establish(this->ike_sa);
- this->destroy_after_state_change(this);
- return SUCCESS;
-}
-
-/**
- * Implements private_ike_auth_requested_t.process_idr_payload
- */
-static status_t process_idr_payload(private_ike_auth_requested_t *this, id_payload_t *idr_payload)
-{
- identification_t *other_id, *configured_other_id;
-
- other_id = idr_payload->get_identification(idr_payload);
- configured_other_id = this->policy->get_other_id(this->policy);
-
- this->logger->log(this->logger, CONTROL|LEVEL1, "configured ID: %s, ID of responder: %s",
- configured_other_id->get_string(configured_other_id),
- other_id->get_string(other_id));
-
- if (!other_id->belongs_to(other_id, configured_other_id))
- {
- other_id->destroy(other_id);
- this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a not acceptable ID. Deleting IKE_SA");
- return DESTROY_ME;
- }
-
- this->policy->update_other_id(this->policy, other_id);
- return SUCCESS;
-}
-
-/**
- * Implements private_ike_auth_requested_t.process_cert_payload
- */
-static status_t process_cert_payload(private_ike_auth_requested_t *this, cert_payload_t * cert_payload)
-{
- bool found;
- x509_t *cert;
-
- if (cert_payload->get_cert_encoding(cert_payload) != CERT_X509_SIGNATURE)
- {
- this->logger->log(this->logger, CONTROL, "certificate encoding is %s, ignored",
- enum_name(&cert_encoding_names, cert_payload->get_cert_encoding(cert_payload)));
- return SUCCESS;
- }
- cert = x509_create_from_chunk(cert_payload->get_data_clone(cert_payload));
-
- if (charon->credentials->verify(charon->credentials, cert, &found))
- {
- this->logger->log(this->logger, CONTROL, "end entity certificate is trusted");
- if (!found)
- {
- cert = charon->credentials->add_end_certificate(charon->credentials, cert);
- }
- }
- else
- {
- this->logger->log(this->logger, ERROR, "end entity certificate is not trusted");
- }
- return SUCCESS;
-}
-
-
-/**
- * Implements private_ike_auth_requested_t.process_sa_payload
- */
-static status_t process_sa_payload(private_ike_auth_requested_t *this, sa_payload_t *sa_payload)
-{
- proposal_t *proposal, *proposal_tmp;
- linked_list_t *proposal_list;
-
- /* get his selected proposal */
- proposal_list = sa_payload->get_proposals(sa_payload);
- /* check count of proposals */
- if (proposal_list->get_count(proposal_list) == 0)
- {
- /* no proposal? we accept this, but no child sa is built */
- this->logger->log(this->logger, AUDIT, "IKE_AUTH reply's SA_PAYLOAD didn't contain any proposals. No CHILD_SA created",
- proposal_list->get_count(proposal_list));
- proposal_list->destroy(proposal_list);
- return SUCCESS;
- }
- if (proposal_list->get_count(proposal_list) > 1)
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH reply's SA_PAYLOAD contained %d proposal. Deleting IKE_SA",
- proposal_list->get_count(proposal_list));
- while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
- {
- proposal->destroy(proposal);
- }
- proposal_list->destroy(proposal_list);
- return DESTROY_ME;
- }
-
- /* we have to re-check here if other's selection is valid */
- proposal = this->policy->select_proposal(this->policy, proposal_list);
- /* list not needed anymore */
- while (proposal_list->remove_last(proposal_list, (void**)&proposal_tmp) == SUCCESS)
- {
- proposal_tmp->destroy(proposal_tmp);
- }
- proposal_list->destroy(proposal_list);
- /* got a match? */
- if (proposal == NULL)
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a not offered proposal. Deleting IKE_SA");
- return DESTROY_ME;
- }
-
- /* apply proposal */
- this->proposal = proposal;
-
- return SUCCESS;
-}
-
-/**
- * Implements private_ike_auth_requested_t.process_auth_payload
- */
-static status_t process_auth_payload(private_ike_auth_requested_t *this, auth_payload_t *auth_payload, id_payload_t *other_id_payload)
-{
- authenticator_t *authenticator;
- status_t status;
-
- authenticator = authenticator_create(this->ike_sa);
- status = authenticator->verify_auth_data(authenticator,auth_payload,this->ike_sa_init_reply_data,this->sent_nonce,other_id_payload,FALSE);
- authenticator->destroy(authenticator);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "verification of IKE_AUTH reply failed. Deleting IKE_SA");
- return DESTROY_ME;
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL1, "AUTH data verified successfully");
- return SUCCESS;
-}
-
-/**
- * Implements private_ike_auth_requested_t.process_ts_payload
- */
-static status_t process_ts_payload(private_ike_auth_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload)
-{
- linked_list_t *ts_received, *ts_selected;
- traffic_selector_t *ts;
-
- /* get ts form payload */
- ts_received = ts_payload->get_traffic_selectors(ts_payload);
- /* select ts depending on payload type */
- if (ts_initiator)
- {
- ts_selected = this->policy->select_my_traffic_selectors(this->policy, ts_received);
- this->my_ts = ts_selected;
- }
- else
- {
- ts_selected = this->policy->select_other_traffic_selectors(this->policy, ts_received);
- this->other_ts = ts_selected;
- }
- /* check if the responder selected valid proposals */
- if (ts_selected->get_count(ts_selected) != ts_received->get_count(ts_received))
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained not offered traffic selectors.");
- }
-
- /* cleanup */
- while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS)
- {
- ts->destroy(ts);
- }
- ts_received->destroy(ts_received);
-
- return SUCCESS;
-}
-
-/**
- * Implements private_ike_auth_requested_t.process_notify_payload
- */
-static status_t process_notify_payload(private_ike_auth_requested_t *this, notify_payload_t *notify_payload)
-{
- notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
-
- this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s",
- mapping_find(notify_message_type_m, notify_message_type));
-
- switch (notify_message_type)
- {
- case INVALID_SYNTAX:
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an INVALID_SYNTAX notify. Deleting IKE_SA");
- return DESTROY_ME;
-
- }
- case AUTHENTICATION_FAILED:
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an AUTHENTICATION_FAILED notify. Deleting IKE_SA");
- return DESTROY_ME;
-
- }
- case SINGLE_PAIR_REQUIRED:
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a SINGLE_PAIR_REQUIRED notify. Deleting IKE_SA");
- return DESTROY_ME;
- }
- case TS_UNACCEPTABLE:
- {
- /* TODO: We currently check only the replied TS payloads, which should be empty. Should
- * we interpret the notify additionaly? */
- this->logger->log(this->logger, CONTROL, "IKE_AUTH reply contained a TS_UNACCEPTABLE notify. Ignored");
- return SUCCESS;
- }
- case NO_PROPOSAL_CHOSEN:
- {
- /* TODO: We currently check only the replied SA payload, which should be empty. Should
- * we interpret the notify additionaly? */
- this->logger->log(this->logger, CONTROL, "IKE_AUTH reply contained a NO_PROPOSAL_CHOSEN notify. Ignored");
- return SUCCESS;
- }
- default:
- {
- /*
- * - In case of unknown error: IKE_SA gets destroyed.
- * - In case of unknown status: logging
- */
-
- if (notify_message_type < 16383)
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an unknown notify error (%d). Deleting IKE_SA",
- notify_message_type);
- return DESTROY_ME;
-
- }
- else
- {
- this->logger->log(this->logger, CONTROL, "IKE_AUTH reply contained an unknown notify (%d), ignored.",
- notify_message_type);
- return SUCCESS;
- }
- }
- }
-}
-
-/**
- * Implements state_t.get_state
- */
-static ike_sa_state_t get_state(private_ike_auth_requested_t *this)
-{
- return IKE_AUTH_REQUESTED;
-}
-
-/**
- * Implements state_t.get_state
- */
-static void destroy(private_ike_auth_requested_t *this)
-{
- chunk_free(&(this->received_nonce));
- chunk_free(&(this->sent_nonce));
- chunk_free(&(this->ike_sa_init_reply_data));
- if (this->child_sa)
- {
- this->child_sa->destroy(this->child_sa);
- }
- if (this->my_ts)
- {
- traffic_selector_t *ts;
- while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS)
- {
- ts->destroy(ts);
- }
- this->my_ts->destroy(this->my_ts);
- }
- if (this->other_ts)
- {
- traffic_selector_t *ts;
- while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS)
- {
- ts->destroy(ts);
- }
- this->other_ts->destroy(this->other_ts);
- }
- if (this->proposal)
- {
- this->proposal->destroy(this->proposal);
- }
- free(this);
-}
-/**
- * Implements protected_ike_sa_t.destroy_after_state_change
- */
-static void destroy_after_state_change(private_ike_auth_requested_t *this)
-{
- chunk_free(&(this->received_nonce));
- chunk_free(&(this->sent_nonce));
- chunk_free(&(this->ike_sa_init_reply_data));
- if (this->my_ts)
- {
- traffic_selector_t *ts;
- while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS)
- {
- ts->destroy(ts);
- }
- this->my_ts->destroy(this->my_ts);
- }
- if (this->other_ts)
- {
- traffic_selector_t *ts;
- while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS)
- {
- ts->destroy(ts);
- }
- this->other_ts->destroy(this->other_ts);
- }
- if (this->proposal)
- {
- this->proposal->destroy(this->proposal);
- }
- free(this);
-}
-
-/*
- * Described in header.
- */
-ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,chunk_t sent_nonce,chunk_t received_nonce,chunk_t ike_sa_init_reply_data, child_sa_t *child_sa)
-{
- private_ike_auth_requested_t *this = malloc_thing(private_ike_auth_requested_t);
-
- /* interface functions */
- this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
- this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
- this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
-
- /* private functions */
- this->process_idr_payload = process_idr_payload;
- this->process_cert_payload = process_cert_payload;
- this->process_sa_payload = process_sa_payload;
- this->process_auth_payload = process_auth_payload;
- this->process_ts_payload = process_ts_payload;
- this->process_notify_payload = process_notify_payload;
- this->destroy_after_state_change = destroy_after_state_change;
-
- /* private data */
- this->ike_sa = ike_sa;
- this->received_nonce = received_nonce;
- this->sent_nonce = sent_nonce;
- this->ike_sa_init_reply_data = ike_sa_init_reply_data;
- this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
- this->my_ts = NULL;
- this->other_ts = NULL;
- this->proposal = NULL;
- this->child_sa = child_sa;
-
- return &(this->public);
-}
diff --git a/src/charon/sa/states/ike_auth_requested.h b/src/charon/sa/states/ike_auth_requested.h
deleted file mode 100644
index a8eef014c..000000000
--- a/src/charon/sa/states/ike_auth_requested.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * @file ike_auth_requested.h
- *
- * @brief Interface of ike_auth_requested_t.
- *
- */
-
-/*
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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_AUTH_REQUESTED_H_
-#define IKE_AUTH_REQUESTED_H_
-
-#include <sa/states/state.h>
-#include <sa/ike_sa.h>
-
-
-typedef struct ike_auth_requested_t ike_auth_requested_t;
-
-/**
- * @brief This class represents an IKE_SA, which has requested an IKE_AUTH.
- *
- * The state accpets IKE_AUTH responses. It proves the authenticity
- * and sets up the first child sa. After that, it changes IKE_SA state to
- * IKE_SA_ESTABLISHED.
- *
- * @ Constructors:
- * - ike_auth_requested_create()
- *
- * @todo handle certificate payloads
- *
- * @ingroup states
- */
-struct ike_auth_requested_t {
- /**
- * The state_t interface.
- */
- state_t state_interface;
-
-};
-
-/**
- * Constructor of class ike_auth_requested_t
- *
- * @param ike_sa assigned ike_sa object
- * @param sent_nonce Sent nonce value in IKE_SA_INIT request
- * @param received_nonce Received nonce value in IKE_SA_INIT response
- * @param ike_sa_init_reply_data binary representation of IKE_SA_INIT reply
- * @param child_sa opened but not completed child_sa
- * @return created ike_auth_requested_t object
- *
- * @ingroup states
- */
-ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,
- chunk_t sent_nonce,
- chunk_t received_nonce,
- chunk_t ike_sa_init_reply_data,
- child_sa_t *child_sa);
-
-#endif /*IKE_AUTH_REQUESTED_H_*/
diff --git a/src/charon/sa/states/ike_sa_established.c b/src/charon/sa/states/ike_sa_established.c
deleted file mode 100644
index 1a29fbba3..000000000
--- a/src/charon/sa/states/ike_sa_established.c
+++ /dev/null
@@ -1,671 +0,0 @@
-/**
- * @file ike_sa_established.c
- *
- * @brief Implementation of ike_sa_established_t.
- *
- */
-
-/*
- * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 <string.h>
-
-#include "ike_sa_established.h"
-
-#include <daemon.h>
-#include <encoding/payloads/delete_payload.h>
-#include <encoding/payloads/sa_payload.h>
-#include <encoding/payloads/ts_payload.h>
-#include <encoding/payloads/nonce_payload.h>
-#include <sa/child_sa.h>
-#include <sa/states/delete_ike_sa_requested.h>
-#include <queues/jobs/send_dpd_job.h>
-
-typedef struct private_ike_sa_established_t private_ike_sa_established_t;
-
-/**
- * Private data of a ike_sa_established_t object.
- */
-struct private_ike_sa_established_t {
- /**
- * methods of the state_t interface
- */
- ike_sa_established_t public;
-
- /**
- * Assigned IKE_SA.
- */
- protected_ike_sa_t *ike_sa;
-
- /**
- * Nonce for a new child SA, chosen by initiator
- */
- chunk_t nonce_i;
-
- /**
- * Nonce for a new child SA, chosen by responder
- */
- chunk_t nonce_r;
-
- /**
- * Traffic selectors for a new child SA, responder side
- */
- linked_list_t *my_ts;
-
- /**
- * Traffic selectors for a new child SA, initiator side
- */
- linked_list_t *other_ts;
-
- /**
- * Newly set up child sa
- */
- child_sa_t *child_sa;
-
- /**
- * Old child sa, if we are rekeying
- */
- child_sa_t *old_child_sa;
-
- /**
- * Assigned logger. Use logger of IKE_SA.
- */
- logger_t *logger;
-};
-
-/**
- * Schedule send dpd job
- */
-static void schedule_dpd_job(private_ike_sa_established_t *this)
-{
- u_int32_t interval = charon->configuration->get_dpd_interval(charon->configuration);
-
- if (interval)
- {
- charon->event_queue->add_relative(charon->event_queue,
- (job_t*)send_dpd_job_create(this->ike_sa->public.get_id(&this->ike_sa->public)),
- interval);
- }
-}
-
-/**
- * Implementation of private_ike_sa_established_t.build_sa_payload.
- */
-static status_t build_sa_payload(private_ike_sa_established_t *this, sa_payload_t *request, message_t *response)
-{
- proposal_t *proposal, *proposal_tmp;
- linked_list_t *proposal_list;
- sa_payload_t *sa_response;
- chunk_t seed;
- prf_plus_t *prf_plus;
- status_t status;
- connection_t *connection;
- policy_t *policy;
- u_int32_t reqid = 0;
- bool use_natt;
-
- /* prepare reply */
- sa_response = sa_payload_create();
-
- /* get proposals from request, and select one with ours */
- policy = this->ike_sa->get_policy(this->ike_sa);
- proposal_list = request->get_proposals(request);
- this->logger->log(this->logger, CONTROL|LEVEL1, "selecting proposals:");
- proposal = policy->select_proposal(policy, proposal_list);
- /* list is not needed anymore */
- while (proposal_list->remove_last(proposal_list, (void**)&proposal_tmp) == SUCCESS)
- {
- proposal_tmp->destroy(proposal_tmp);
- }
- proposal_list->destroy(proposal_list);
- /* do we have a proposal? */
- if (proposal == NULL)
- {
- notify_payload_t *notify;
- this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA request did not contain any proposals we accept. "
- "Adding NO_PROPOSAL_CHOSEN notify");
- /* add NO_PROPOSAL_CHOSEN and an empty SA payload */
- notify = notify_payload_create_from_protocol_and_type(PROTO_IKE, NO_PROPOSAL_CHOSEN);
- response->add_payload(response, (payload_t*)notify);
- }
- else
- {
- /* set up child sa */
- seed = chunk_alloc(this->nonce_i.len + this->nonce_r.len);
- memcpy(seed.ptr, this->nonce_i.ptr, this->nonce_i.len);
- memcpy(seed.ptr + this->nonce_i.len, this->nonce_r.ptr, this->nonce_r.len);
- prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
- this->logger->log_chunk(this->logger, RAW|LEVEL2, "sekey seed", seed);
- chunk_free(&seed);
- chunk_free(&this->nonce_i);
- chunk_free(&this->nonce_r);
-
- policy = this->ike_sa->get_policy(this->ike_sa);
- connection = this->ike_sa->get_connection(this->ike_sa);
- if (this->old_child_sa)
- { /* reuse old reqid if we are rekeying */
- reqid = this->old_child_sa->get_reqid(this->old_child_sa);
- }
- use_natt = this->ike_sa->public.is_any_host_behind_nat(&this->ike_sa->public);
- this->child_sa = child_sa_create(reqid,
- connection->get_my_host(connection),
- connection->get_other_host(connection),
- policy->get_soft_lifetime(policy),
- policy->get_hard_lifetime(policy),
- use_natt);
-
- status = this->child_sa->add(this->child_sa, proposal, prf_plus);
- prf_plus->destroy(prf_plus);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "sould not install CHILD_SA!");
- sa_response->destroy(sa_response);
- proposal->destroy(proposal);
- return DESTROY_ME;
- }
-
- /* add proposal to sa payload */
- sa_response->add_proposal(sa_response, proposal);
- proposal->destroy(proposal);
- }
- response->add_payload(response, (payload_t*)sa_response);
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_established_t.build_ts_payload.
- */
-static status_t build_ts_payload(private_ike_sa_established_t *this, bool ts_initiator, ts_payload_t *request, message_t* response)
-{
- linked_list_t *ts_received, *ts_selected;
- traffic_selector_t *ts;
- status_t status = SUCCESS;
- ts_payload_t *ts_response;
- policy_t *policy;
-
- policy = this->ike_sa->get_policy(this->ike_sa);
-
- /* build a reply payload with selected traffic selectors */
- ts_received = request->get_traffic_selectors(request);
- /* select ts depending on payload type */
- if (ts_initiator)
- {
- ts_selected = policy->select_other_traffic_selectors(policy, ts_received);
- this->other_ts = ts_selected;
- }
- else
- {
- ts_selected = policy->select_my_traffic_selectors(policy, ts_received);
- this->my_ts = ts_selected;
- }
-
- ts_response = ts_payload_create_from_traffic_selectors(ts_initiator, ts_selected);
- response->add_payload(response, (payload_t*)ts_response);
-
- /* add notify if traffic selectors do not match */
- if (!ts_initiator &&
- (ts_selected->get_count(ts_selected) == 0 || this->other_ts->get_count(this->other_ts) == 0))
- {
- notify_payload_t *notify;
-
- this->logger->log(this->logger, AUDIT, "IKE_AUTH request did not contain any traffic selectors we accept. "
- "Adding TS_UNACCEPTABLE notify");
-
- notify = notify_payload_create_from_protocol_and_type(0, TS_UNACCEPTABLE);
- response->add_payload(response, (payload_t*)notify);
- }
-
- /* cleanup */
- while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS)
- {
- ts->destroy(ts);
- }
- ts_received->destroy(ts_received);
-
- return status;
-}
-
-/**
- * Implementation of private_ike_sa_established_t.build_nonce_payload.
- */
-static status_t build_nonce_payload(private_ike_sa_established_t *this, nonce_payload_t *nonce_request, message_t *response)
-{
- nonce_payload_t *nonce_payload;
- randomizer_t *randomizer;
- status_t status;
-
- randomizer = this->ike_sa->get_randomizer(this->ike_sa);
- status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &this->nonce_r);
- if (status != SUCCESS)
- {
- return status;
- }
- nonce_payload = nonce_payload_create();
- nonce_payload->set_nonce(nonce_payload, this->nonce_r);
-
- response->add_payload(response,(payload_t *) nonce_payload);
-
- this->nonce_i = nonce_request->get_nonce(nonce_request);
-
- return SUCCESS;
-}
-
-/**
- * Process a CREATE_CHILD_SA request
- */
-static status_t process_create_child_sa(private_ike_sa_established_t *this, message_t *request, message_t *response)
-{
- ts_payload_t *tsi_request = NULL, *tsr_request = NULL;
- sa_payload_t *sa_request = NULL;
- nonce_payload_t *nonce_request = NULL;
- notify_payload_t *notify = NULL;
- iterator_t *payloads;
- status_t status;
-
- /* iterate over incoming payloads. Message is verified, we can be sure there are the required payloads */
- payloads = request->get_payload_iterator(request);
- while (payloads->has_next(payloads))
- {
- payload_t *payload;
- payloads->current(payloads, (void**)&payload);
-
- switch (payload->get_type(payload))
- {
- case SECURITY_ASSOCIATION:
- {
- sa_request = (sa_payload_t*)payload;
- break;
- }
- case TRAFFIC_SELECTOR_INITIATOR:
- {
- tsi_request = (ts_payload_t*)payload;
- break;
- }
- case TRAFFIC_SELECTOR_RESPONDER:
- {
- tsr_request = (ts_payload_t*)payload;
- break;
- }
- case NONCE:
- {
- nonce_request = (nonce_payload_t*)payload;
- break;
- }
- case KEY_EXCHANGE:
- {
- /* we currently do not support a diffie hellman exchange
- * for CHILD_SAs. */
- u_int16_t no_group[1];
- no_group[0] = htons(MODP_NONE);
- chunk_t no_group_chunk = chunk_from_buf((u_int8_t*)no_group);
- this->ike_sa->send_notify(this->ike_sa, CREATE_CHILD_SA, INVALID_KE_PAYLOAD, no_group_chunk);
- payloads->destroy(payloads);
- return FAILED;
- }
- case NOTIFY:
- {
- notify = (notify_payload_t*)payload;
- break;
- }
- default:
- {
- this->logger->log(this->logger, ERROR|LEVEL1, "sgnoring payload %s (%d)",
- mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
- break;
- }
- }
- }
- /* iterator can be destroyed */
- payloads->destroy(payloads);
-
- /* check if we have all payloads */
- if (!(sa_request && nonce_request && tsi_request && tsr_request))
- {
- this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA request did not contain all required payloads. Ignored");
- return FAILED;
- }
-
- if (notify && notify->get_notify_message_type(notify) == REKEY_SA)
- {
- u_int32_t spi = notify->get_spi(notify);
- this->old_child_sa = this->ike_sa->get_child_sa(this->ike_sa, spi);
- this->logger->log(this->logger, CONTROL, "sekeying CHILD_SA with SPI 0x%x", spi);
- }
- else
- {
- this->logger->log(this->logger, CONTROL, "create new CHILD_SA");
- }
-
- /* build response */
- this->ike_sa->build_message(this->ike_sa, CREATE_CHILD_SA, FALSE, &response);
-
- /* add payloads to it */
- status = build_nonce_payload(this, nonce_request, response);
- if (status != SUCCESS)
- {
- response->destroy(response);
- return status;
- }
- status = build_sa_payload(this, sa_request, response);
- if (status != SUCCESS)
- {
- response->destroy(response);
- return status;
- }
- status = build_ts_payload(this, TRUE, tsi_request, response);
- if (status != SUCCESS)
- {
- response->destroy(response);
- return status;
- }
- status = build_ts_payload(this, FALSE, tsr_request, response);
- if (status != SUCCESS)
- {
- response->destroy(response);
- return status;
- }
-
- status = this->ike_sa->send_response(this->ike_sa, response);
- /* message can now be sent (must not be destroyed) */
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "unable to send CREATE_CHILD_SA reply. Ignored");
- response->destroy(response);
- return FAILED;
- }
-
- /* install child SA policies */
- if (!this->child_sa)
- {
- this->logger->log(this->logger, ERROR, "proposal negotiation failed, no CHILD_SA built");
- }
- else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0)
- {
- this->logger->log(this->logger, ERROR, "traffic selector negotiation failed, no CHILD_SA built");
- this->child_sa->destroy(this->child_sa);
- this->child_sa = NULL;
- }
- else
- {
- status = this->child_sa->add_policies(this->child_sa, this->my_ts, this->other_ts);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "could not install CHILD_SA policy!");
- }
- if (this->old_child_sa)
- { /* mark old child sa as rekeyed */
- this->old_child_sa->set_rekeyed(this->old_child_sa);
- }
- this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
- }
-
- return SUCCESS;
-}
-
-
-/**
- * Process an informational request
- */
-static status_t process_informational(private_ike_sa_established_t *this, message_t *request, message_t *response)
-{
- delete_payload_t *delete_request = NULL;
- iterator_t *payloads = request->get_payload_iterator(request);
-
- if (!payloads->get_count(payloads))
- {
- this->logger->log(this->logger, CONTROL, "DPD request received.");
- }
-
- while (payloads->has_next(payloads))
- {
- payload_t *payload;
- payloads->current(payloads, (void**)&payload);
-
- switch (payload->get_type(payload))
- {
- case DELETE:
- {
- delete_request = (delete_payload_t *) payload;
- break;
- }
- default:
- {
- this->logger->log(this->logger, ERROR|LEVEL1, "ignoring Payload %s (%d)",
- mapping_find(payload_type_m, payload->get_type(payload)),
- payload->get_type(payload));
- break;
- }
- }
- }
- /* iterator can be destroyed */
- payloads->destroy(payloads);
-
- if (delete_request)
- {
- if (delete_request->get_protocol_id(delete_request) == PROTO_IKE)
- {
- this->logger->log(this->logger, CONTROL, "DELETE request for IKE_SA received");
- /* switch to delete_ike_sa_requested. This is not absolutely correct, but we
- * allow the clean destruction of an SA only in this state. */
- this->ike_sa->set_new_state(this->ike_sa, (state_t*)delete_ike_sa_requested_create(this->ike_sa));
- this->public.state_interface.destroy(&(this->public.state_interface));
- this->ike_sa->send_response(this->ike_sa, response);
- return DESTROY_ME;
- }
- else
- {
- iterator_t *iterator;
- delete_payload_t *delete_response = delete_payload_create(delete_request->get_protocol_id(delete_request));
- iterator = delete_request->create_spi_iterator(delete_request);
- while (iterator->has_next(iterator))
- {
- u_int32_t spi;
- iterator->current(iterator, (void**)&spi);
- this->logger->log(this->logger, CONTROL, "DELETE request for CHILD_SA with SPI 0x%x received", spi);
- spi = this->ike_sa->destroy_child_sa(this->ike_sa, spi);
- if (spi)
- {
- delete_response->add_spi(delete_response, spi);
- }
- }
- iterator->destroy(iterator);
- response->add_payload(response, (payload_t*)delete_response);
- }
- }
-
- if (this->ike_sa->send_response(this->ike_sa, response) != SUCCESS)
- {
- /* something is seriously wrong, kill connection */
- this->logger->log(this->logger, AUDIT, "unable to send reply. Deleting IKE_SA");
- response->destroy(response);
- return DESTROY_ME;
- }
- return SUCCESS;
-}
-
-/**
- * Process an informational response
- */
-static status_t process_informational_response(private_ike_sa_established_t *this, message_t *message)
-{
- iterator_t *payloads = message->get_payload_iterator(message);
-
- if (!payloads->get_count(payloads))
- {
- if (message->get_message_id(message)
- != this->ike_sa->get_last_dpd_message_id(this->ike_sa))
- {
- this->logger->log(this->logger, ERROR|LEVEL1, "DPD response received that does not match our last sent dpd message.");
- payloads->destroy(payloads);
- return FAILED;
- }
-
- this->logger->log(this->logger, CONTROL, "DPD response received. Schedule job.");
- schedule_dpd_job(this);
-
- payloads->destroy(payloads);
- return SUCCESS;
- }
-
- while (payloads->has_next(payloads))
- {
- payload_t *payload;
- payloads->current(payloads, (void**)&payload);
-
- switch (payload->get_type(payload))
- {
- default:
- {
- this->logger->log(this->logger, ERROR|LEVEL1, "ignoring Payload %s (%d)",
- mapping_find(payload_type_m, payload->get_type(payload)),
- payload->get_type(payload));
- break;
- }
- }
- }
- /* iterator can be destroyed */
- payloads->destroy(payloads);
-
- return SUCCESS;
-}
-
-/**
- * Implements state_t.get_state
- * Implements state_t.process_message
- */
-static status_t process_message(private_ike_sa_established_t *this, message_t *message)
-{
- ike_sa_id_t *ike_sa_id;
- message_t *response;
- crypter_t *crypter;
- signer_t *signer;
- status_t status;
-
- /* get signer for verification and crypter for decryption */
- ike_sa_id = this->ike_sa->public.get_id(&this->ike_sa->public);
- if (!ike_sa_id->is_initiator(ike_sa_id))
- {
- crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
- signer = this->ike_sa->get_signer_initiator(this->ike_sa);
- }
- else
- {
- crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
- signer = this->ike_sa->get_signer_responder(this->ike_sa);
- }
-
- /* parse incoming message */
- status = message->parse_body(message, crypter, signer);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "%s request decryption failed. Ignoring message",
- mapping_find(exchange_type_m, message->get_exchange_type(message)));
- return status;
- }
-
- status = this->ike_sa->update_connection_hosts(this->ike_sa,
- message->get_destination(message), message->get_source(message));
- if (status != SUCCESS)
- {
- return status;
- }
-
- /* process responses */
- if (!message->get_request(message))
- {
- switch (message->get_exchange_type(message))
- {
- case INFORMATIONAL:
- status = process_informational_response(this, message);
- break;
- default:
- this->logger->log(this->logger, ERROR | LEVEL1,
- "Only INFORMATIONAL responses are handled in state ike_sa_established");
- status = FAILED;
- break;
- }
-
- /* we don't really reply to this message but the retransmit mechanism relies on this */
- this->ike_sa->set_last_replied_message_id(this->ike_sa, message->get_message_id(message));
-
- /* return here */
- return status;
- }
-
- /* prepare a reply of the same type */
- this->ike_sa->build_message(this->ike_sa, message->get_exchange_type(message), FALSE, &response);
-
- /* handle the different message types in their functions */
- switch (message->get_exchange_type(message))
- {
- case INFORMATIONAL:
- status = process_informational(this, message, response);
- break;
- case CREATE_CHILD_SA:
- status = process_create_child_sa(this, message, response);
- break;
- default:
- this->logger->log(this->logger, ERROR | LEVEL1,
- "message of type %s not supported in state ike_sa_established",
- mapping_find(exchange_type_m, message->get_exchange_type(message)));
- status = NOT_SUPPORTED;
- }
-
- return status;
-}
-
-/**
- * Implementation of state_t.get_state.
- */
-static ike_sa_state_t get_state(private_ike_sa_established_t *this)
-{
- return IKE_SA_ESTABLISHED;
-}
-
-/**
- * Implementation of state_t.get_state
- */
-static void destroy(private_ike_sa_established_t *this)
-{
- chunk_free(&this->nonce_i);
- chunk_free(&this->nonce_r);
- free(this);
-}
-
-/*
- * Described in header.
- */
-ike_sa_established_t *ike_sa_established_create(protected_ike_sa_t *ike_sa)
-{
- private_ike_sa_established_t *this = malloc_thing(private_ike_sa_established_t);
-
- /* interface functions */
- this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
- this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
- this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
-
- /* private data */
- this->ike_sa = ike_sa;
- this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
- this->nonce_i = CHUNK_INITIALIZER;
- this->nonce_r = CHUNK_INITIALIZER;
- this->old_child_sa = NULL;
-
- /* schedule initial dpd job */
- schedule_dpd_job(this);
-
- return &(this->public);
-}
diff --git a/src/charon/sa/states/ike_sa_established.h b/src/charon/sa/states/ike_sa_established.h
deleted file mode 100644
index 8477ad5bc..000000000
--- a/src/charon/sa/states/ike_sa_established.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * @file ike_sa_established.h
- *
- * @brief Interface of ike_sa_established_t.
- *
- */
-
-/*
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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_ESTABLISHED_H_
-#define IKE_SA_ESTABLISHED_H_
-
-#include <sa/states/state.h>
-#include <sa/ike_sa.h>
-
-typedef struct ike_sa_established_t ike_sa_established_t;
-
-/**
- * @brief This class represents an the state of an established
- * IKE_SA.
- *
- * @b Constructors:
- * - ike_sa_established_create()
- *
- * @todo Implement handling of CREATE_CHILD_SA requests
- *
- * @todo Implement initialization of CREATE_CHILD_SA requests
- *
- * @todo Implement handling of any other message
- *
- * @ingroup states
- */
-struct ike_sa_established_t {
- /**
- * methods of the state_t interface
- */
- state_t state_interface;
-
-};
-
-/**
- * @brief Constructor of class ike_sa_established_t
- *
- * @param ike_sa assigned ike_sa
- * @return created ike_sa_established_t object
- *
- * @ingroup states
- */
-ike_sa_established_t *ike_sa_established_create(protected_ike_sa_t *ike_sa);
-
-#endif /*IKE_SA_ESTABLISHED_H_*/
diff --git a/src/charon/sa/states/ike_sa_init_requested.c b/src/charon/sa/states/ike_sa_init_requested.c
deleted file mode 100644
index 6f121ac18..000000000
--- a/src/charon/sa/states/ike_sa_init_requested.c
+++ /dev/null
@@ -1,990 +0,0 @@
-/**
- * @file ike_sa_init_requested.c
- *
- * @brief Implementation of ike_sa_init_requested_t.
- *
- */
-
-/*
- * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 <daemon.h>
-#include <encoding/payloads/sa_payload.h>
-#include <encoding/payloads/ke_payload.h>
-#include <encoding/payloads/nonce_payload.h>
-#include <encoding/payloads/notify_payload.h>
-#include <encoding/payloads/id_payload.h>
-#include <encoding/payloads/cert_payload.h>
-#include <encoding/payloads/certreq_payload.h>
-#include <encoding/payloads/auth_payload.h>
-#include <encoding/payloads/ts_payload.h>
-#include <crypto/diffie_hellman.h>
-#include <sa/states/ike_auth_requested.h>
-#include <sa/states/initiator_init.h>
-#include <sa/authenticator.h>
-
-
-typedef struct private_ike_sa_init_requested_t private_ike_sa_init_requested_t;
-
-/**
- * Private data of a ike_sa_init_requested_t object.
- *
- */
-struct private_ike_sa_init_requested_t {
- /**
- * Public interface of an ike_sa_init_requested_t object.
- */
- 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;
-
- /**
- * Selected proposal
- */
- proposal_t *proposal;
-
- /**
- * Packet data of ike_sa_init request
- */
- chunk_t ike_sa_init_request_data;
-
- /**
- * Created child sa, if any
- */
- child_sa_t *child_sa;
-
- /**
- * Assigned logger
- *
- * Is logger of ike_sa!
- */
- logger_t *logger;
-
- /**
- * Precomputed NAT-D hash for initiator.
- */
- chunk_t natd_hash_i;
-
- /**
- * Flag indicating that an initiator NAT-D hash matched.
- */
- bool natd_hash_i_matched;
-
- /**
- * NAT-D payload count for NAT_DETECTION_SOURCE_IP.
- */
- int natd_seen_i;
-
- /**
- * Precomputed NAT-D hash of responder.
- */
- chunk_t natd_hash_r;
-
- /**
- * Flag indicating that a responder NAT-D hash matched.
- */
- bool natd_hash_r_matched;
-
- /**
- * NAT-D payload count for NAT_DETECTION_DESTINATION_IP.
- */
- int natd_seen_r;
-
-
- /**
- * Process NONCE payload of IKE_SA_INIT response.
- *
- * @param this calling object
- * @param nonce_payload NONCE payload to process
- * @return SUCCESS in any case
- */
- status_t (*process_nonce_payload) (private_ike_sa_init_requested_t *this, nonce_payload_t *nonce_payload);
-
- /**
- * Process SA payload of IKE_SA_INIT response.
- *
- * @param this calling object
- * @param sa_payload SA payload to process
- * @return
- * - SUCCESS
- * - FAILED
- */
- status_t (*process_sa_payload) (private_ike_sa_init_requested_t *this, sa_payload_t *sa_payload);
-
- /**
- * Process KE payload of IKE_SA_INIT response.
- *
- * @param this calling object
- * @param sa_payload KE payload to process
- * @return
- * - SUCCESS
- * - FAILED
- */
- status_t (*process_ke_payload) (private_ike_sa_init_requested_t *this, ke_payload_t *ke_payload);
-
- /**
- * Build ID payload for IKE_AUTH request.
- *
- * @param this calling object
- * @param[out] id_payload buildet ID payload
- * @param msg created payload will be added to this message_t object
- * @return
- * - SUCCESS
- * - FAILED
- */
- status_t (*build_id_payload) (private_ike_sa_init_requested_t *this,id_payload_t **id_payload, message_t *msg);
-
- /**
- * Build CERT payload for IKE_AUTH request.
- *
- * @param this calling object
- * @param msg created payload will be added to this message_t object
- * @return
- * - SUCCESS
- * - FAILED
- */
- status_t (*build_cert_payload) (private_ike_sa_init_requested_t *this, message_t *msg);
-
- /**
- * Build CERTREQ payload for IKE_AUTH request.
- *
- * @param this calling object
- * @param msg created payload will be added to this message_t object
- * @return
- * - SUCCESS
- * - FAILED
- */
- status_t (*build_certreq_payload) (private_ike_sa_init_requested_t *this, message_t *msg);
-
- /**
- * Build IDr payload for IKE_AUTH request.
- *
- * Only built when the ID of the responder contains no wildcards.
- *
- * @param this calling object
- * @param msg created payload will be added to this message_t object
- * @return
- * - SUCCESS
- * - FAILED
- */
- status_t (*build_idr_payload) (private_ike_sa_init_requested_t *this, message_t *msg);
-
- /**
- * Build AUTH payload for IKE_AUTH request.
- *
- * @param this calling object
- * @param my_id_payload buildet ID payload
- * @param msg created payload will be added to this message_t object
- * @return
- * - SUCCESS
- * - FAILED
- */
- status_t (*build_auth_payload) (private_ike_sa_init_requested_t *this,id_payload_t *my_id_payload, message_t *msg);
-
- /**
- * Build SA payload for IKE_AUTH request.
- *
- * @param this calling object
- * @param msg created payload will be added to this message_t object
- * @return
- * - SUCCESS
- * - FAILED
- */
- status_t (*build_sa_payload) (private_ike_sa_init_requested_t *this, message_t *msg);
-
- /**
- * Build TSi payload for IKE_AUTH request.
- *
- * @param this calling object
- * @param msg created payload will be added to this message_t object
- * @return
- * - SUCCESS
- * - FAILED
- */
- status_t (*build_tsi_payload) (private_ike_sa_init_requested_t *this, message_t *msg);
-
- /**
- * Build TSr payload for IKE_AUTH request.
- *
- * @param this calling object
- * @param msg created payload will be added to this message_t object
- * @return
- * - SUCCESS
- * - FAILED
- */
- status_t (*build_tsr_payload) (private_ike_sa_init_requested_t *this, message_t *msg);
-
- /**
- * Process a notify payload and react.
- *
- * @param this calling object
- * @param notify_payload notify_payload to handle
- */
- status_t (*process_notify_payload) (private_ike_sa_init_requested_t *this, notify_payload_t *notify_payload);
-
- /**
- * Destroy function called internally of this class after state change to
- * state IKE_AUTH_REQUESTED succeeded.
- *
- * This destroy function does not destroy objects which were passed to the new state.
- *
- * @param this calling object
- */
- void (*destroy_after_state_change) (private_ike_sa_init_requested_t *this);
-};
-
-/**
- * Implementation of state_t.process_message.
- */
-static status_t process_message(private_ike_sa_init_requested_t *this, message_t *ike_sa_init_reply)
-{
- ike_auth_requested_t *next_state;
- chunk_t ike_sa_init_reply_data;
- sa_payload_t *sa_payload = NULL;
- ke_payload_t *ke_payload = NULL;
- id_payload_t *id_payload = NULL;
- nonce_payload_t *nonce_payload = NULL;
- u_int64_t responder_spi;
- ike_sa_id_t *ike_sa_id;
- iterator_t *payloads;
- host_t *me, *other;
- connection_t *connection;
- policy_t *policy;
-
- message_t *request;
- status_t status;
-
- /*
- * In this state a reply message of type IKE_SA_INIT is expected:
- *
- * <-- HDR, SAr1, KEr, Nr, [CERTREQ]
- * or
- * <-- HDR, N
- */
-
- if (ike_sa_init_reply->get_exchange_type(ike_sa_init_reply) != IKE_SA_INIT)
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "message of type %s not supported in state ike_sa_init_requested",
- mapping_find(exchange_type_m,ike_sa_init_reply->get_exchange_type(ike_sa_init_reply)));
- return FAILED;
- }
-
- if (ike_sa_init_reply->get_request(ike_sa_init_reply))
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT requests not allowed state ike_sa_init_responded");
- return FAILED;
- }
-
- /* parse incoming message */
- status = ike_sa_init_reply->parse_body(ike_sa_init_reply, NULL, NULL);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT reply parsing faild. Ignoring message");
- return status;
- }
-
- /* because we are original initiator we have to update the responder SPI to the new one */
- responder_spi = ike_sa_init_reply->get_responder_spi(ike_sa_init_reply);
- if (responder_spi == 0)
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT reply contained a SPI of zero");
- return FAILED;
- }
- ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public));
- ike_sa_id->set_responder_spi(ike_sa_id,responder_spi);
-
- /*
- * Precompute NAT-D hashes.
- * Even though there SHOULD only be a single payload of each
- * Notify type, we precompute both hashes.
- */
- this->natd_hash_i = this->ike_sa->generate_natd_hash(this->ike_sa,
- ike_sa_init_reply->get_initiator_spi(ike_sa_init_reply),
- ike_sa_init_reply->get_responder_spi(ike_sa_init_reply),
- ike_sa_init_reply->get_source(ike_sa_init_reply));
- this->natd_hash_i_matched = FALSE;
- this->natd_seen_i = 0;
- this->natd_hash_r = this->ike_sa->generate_natd_hash(this->ike_sa,
- ike_sa_init_reply->get_initiator_spi(ike_sa_init_reply),
- ike_sa_init_reply->get_responder_spi(ike_sa_init_reply),
- ike_sa_init_reply->get_destination(ike_sa_init_reply));
- this->natd_hash_r_matched = FALSE;
- this->natd_seen_r = 0;
- this->ike_sa->set_my_host_behind_nat(this->ike_sa, FALSE);
- this->ike_sa->set_other_host_behind_nat(this->ike_sa, FALSE);
-
- /* Iterate over all payloads.
- *
- * The message is already checked for the right payload types.
- */
- payloads = ike_sa_init_reply->get_payload_iterator(ike_sa_init_reply);
- while (payloads->has_next(payloads))
- {
- payload_t *payload;
- payloads->current(payloads, (void**)&payload);
-
- switch (payload->get_type(payload))
- {
- case SECURITY_ASSOCIATION:
- sa_payload = (sa_payload_t*)payload;
- break;
- case KEY_EXCHANGE:
- ke_payload = (ke_payload_t*)payload;
- break;
- case NONCE:
- nonce_payload = (nonce_payload_t*)payload;
- break;
- case NOTIFY:
- {
- notify_payload_t *notify_payload = (notify_payload_t *) payload;
-
- status = this->process_notify_payload(this, notify_payload);
- if (status != SUCCESS)
- {
- payloads->destroy(payloads);
- return status;
- }
- break;
- }
- default:
- this->logger->log(this->logger, ERROR|LEVEL1, "ignoring payload %s (%d)",
- mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
- break;
- }
-
- }
- payloads->destroy(payloads);
-
- if (!(nonce_payload && sa_payload && ke_payload))
- {
- this->logger->log(this->logger, AUDIT, "IKE_SA_INIT reply did not contain all required payloads. Deleting IKE_SA");
- return DESTROY_ME;
- }
-
- status = this->process_nonce_payload (this,nonce_payload);
- if (status != SUCCESS)
- return status;
-
- status = this->process_sa_payload (this,sa_payload);
- if (status != SUCCESS)
- return status;
-
- status = this->process_ke_payload (this,ke_payload);
- if (status != SUCCESS)
- return status;
-
- /* derive all the keys used in the IKE_SA */
- status = this->ike_sa->build_transforms(this->ike_sa, this->proposal, this->diffie_hellman, this->sent_nonce, this->received_nonce);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "transform objects could not be created from selected proposal. Deleting IKE_SA");
- return DESTROY_ME;
- }
-
- /* NAT-D */
- if ((!this->natd_seen_i && this->natd_seen_r > 0)
- || (this->natd_seen_i > 0 && !this->natd_seen_r))
- {
- this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request contained wrong number of NAT-D payloads. Deleting IKE_SA");
- return DESTROY_ME;
- }
- if (this->natd_seen_r > 1)
- {
- this->logger->log(this->logger, AUDIT, "warning: IKE_SA_INIT request contained multiple Notify(NAT_DETECTION_DESTINATION_IP) payloads.");
- }
- if (this->natd_seen_i > 0 && !this->natd_hash_i_matched)
- {
- this->logger->log(this->logger, AUDIT, "remote host is behind NAT, using NAT-Traversal");
- this->ike_sa->set_other_host_behind_nat(this->ike_sa, TRUE);
- }
- if (this->natd_seen_r > 0 && !this->natd_hash_r_matched)
- {
- this->logger->log(this->logger, AUDIT, "local host is behind NAT, using NAT-Traversal");
- this->ike_sa->set_my_host_behind_nat(this->ike_sa, TRUE);
- }
-
- /* apply the address on wich we really received the packet,
- * and switch to port 4500 when using NAT-T and NAT was detected.
- */
- connection = this->ike_sa->get_connection(this->ike_sa);
- me = ike_sa_init_reply->get_destination(ike_sa_init_reply);
- other = ike_sa_init_reply->get_source(ike_sa_init_reply);
-
- if (this->ike_sa->public.is_any_host_behind_nat((ike_sa_t*)this->ike_sa))
- {
- me->set_port(me, IKEV2_NATT_PORT);
- other->set_port(other, IKEV2_NATT_PORT);
- this->logger->log(this->logger, AUDIT, "switching to port %d.", IKEV2_NATT_PORT);
- }
- else
- {
- this->logger->log(this->logger, AUDIT, "no NAT detected, not using NAT-Traversal");
- }
-
- if (this->ike_sa->public.is_my_host_behind_nat(&this->ike_sa->public))
- {
- charon->event_queue->add_relative(charon->event_queue,
- (job_t*)send_keepalive_job_create(this->ike_sa->public.get_id((ike_sa_t*)this->ike_sa)),
- charon->configuration->get_keepalive_interval(charon->configuration));
- }
-
- status = this->ike_sa->update_connection_hosts(this->ike_sa, me, other);
- if (status != SUCCESS)
- return status;
-
- policy = this->ike_sa->get_policy(this->ike_sa);
- policy->update_my_ts(policy, me);
- policy->update_other_ts(policy, other);
-
- /* build empty message */
- this->ike_sa->build_message(this->ike_sa, IKE_AUTH, TRUE, &request);
-
- status = this->build_id_payload(this, &id_payload, request);
- if (status != SUCCESS)
- goto destroy_request;
-
- status = this->build_cert_payload(this, request);
- if (status != SUCCESS)
- goto destroy_request;
-
- status = this->build_certreq_payload(this, request);
- if (status != SUCCESS)
- goto destroy_request;
-
- status = this->build_idr_payload(this, request);
- if (status != SUCCESS)
- goto destroy_request;
-
- status = this->build_auth_payload(this, (id_payload_t*)id_payload, request);
- if (status != SUCCESS)
- goto destroy_request;
-
- status = this->build_sa_payload(this, request);
- if (status != SUCCESS)
- goto destroy_request;
-
- status = this->build_tsi_payload(this, request);
- if (status != SUCCESS)
- goto destroy_request;
-
- status = this->build_tsr_payload(this, request);
- if (status != SUCCESS)
- goto destroy_request;
-
- /* message can now be sent (must not be destroyed) */
- status = this->ike_sa->send_request(this->ike_sa, request);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "unable to send IKE_AUTH request. Deleting IKE_SA");
- request->destroy(request);
- return DESTROY_ME;
- }
-
- this->ike_sa->set_last_replied_message_id(this->ike_sa,ike_sa_init_reply->get_message_id(ike_sa_init_reply));
-
- ike_sa_init_reply_data = ike_sa_init_reply->get_packet_data(ike_sa_init_reply);
-
- /* state can now be changed */
- next_state = ike_auth_requested_create(this->ike_sa, this->sent_nonce, this->received_nonce,
- ike_sa_init_reply_data, this->child_sa);
- this->ike_sa->set_new_state(this->ike_sa,(state_t *) next_state);
-
- this->destroy_after_state_change(this);
- return SUCCESS;
-
-destroy_request:
- request->destroy(request);
- return status;
-
-}
-
-
-/**
- * Implementation of private_ike_sa_init_requested_t.process_nonce_payload.
- */
-status_t process_nonce_payload (private_ike_sa_init_requested_t *this, nonce_payload_t *nonce_payload)
-{
- free(this->received_nonce.ptr);
- this->received_nonce = nonce_payload->get_nonce(nonce_payload);
- return SUCCESS;
-}
-
-
-/**
- * Implementation of private_ike_sa_init_requested_t.process_sa_payload.
- */
-status_t process_sa_payload (private_ike_sa_init_requested_t *this, sa_payload_t *sa_payload)
-{
- proposal_t *proposal;
- linked_list_t *proposal_list;
- connection_t *connection;
-
- connection = this->ike_sa->get_connection(this->ike_sa);
-
- /* get the list of selected proposals, the peer has to select only one proposal */
- proposal_list = sa_payload->get_proposals (sa_payload);
- if (proposal_list->get_count(proposal_list) != 1)
- {
- this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response did not contain a single proposal. Deleting IKE_SA");
- while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
- {
- proposal->destroy(proposal);
- }
- proposal_list->destroy(proposal_list);
- return DESTROY_ME;
- }
-
- /* we have to re-check if the others selection is valid */
- this->proposal = connection->select_proposal(connection, proposal_list);
- while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
- {
- proposal->destroy(proposal);
- }
- proposal_list->destroy(proposal_list);
-
- if (this->proposal == NULL)
- {
- this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained selected proposal we did not offer. Deleting IKE_SA");
- return DESTROY_ME;
- }
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_init_requested_t.process_ke_payload.
- */
-status_t process_ke_payload (private_ike_sa_init_requested_t *this, ke_payload_t *ke_payload)
-{
- this->diffie_hellman->set_other_public_value(this->diffie_hellman, ke_payload->get_key_exchange_data(ke_payload));
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_init_requested_t.build_id_payload.
- */
-static status_t build_id_payload (private_ike_sa_init_requested_t *this,id_payload_t **id_payload, message_t *msg)
-{
- policy_t *policy;
- identification_t *my_id;
- id_payload_t *new_id_payload;
-
- policy = this->ike_sa->get_policy(this->ike_sa);
- my_id = policy->get_my_id(policy);
- new_id_payload = id_payload_create_from_identification(TRUE, my_id);
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add ID payload to message");
- msg->add_payload(msg, (payload_t *) new_id_payload);
-
- *id_payload = new_id_payload;
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_init_requested_t.build_cert_payload.
- */
-static status_t build_cert_payload (private_ike_sa_init_requested_t *this, message_t *msg)
-{
- connection_t *connection = this->ike_sa->get_connection(this->ike_sa);
-
- if (connection->get_cert_policy(connection) != CERT_NEVER_SEND)
- {
- policy_t *policy;
- identification_t *my_id;
- x509_t *cert;
- cert_payload_t *cert_payload;
-
- policy = this->ike_sa->get_policy(this->ike_sa);
- my_id = policy->get_my_id(policy);
-
- cert = charon->credentials->get_certificate(charon->credentials, my_id);
- if (cert == NULL)
- {
- this->logger->log(this->logger, ERROR, "could not find my certificate");
- return NOT_FOUND;
- }
- cert_payload = cert_payload_create_from_x509(cert);
- this->logger->log(this->logger, CONTROL|LEVEL2, "add CERT payload to message");
- msg->add_payload(msg, (payload_t *) cert_payload);
- }
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_init_requested_t.build_certreq_payload.
- */
-static status_t build_certreq_payload (private_ike_sa_init_requested_t *this, message_t *msg)
-{
- if (FALSE)
- {
- certreq_payload_t *certreq_payload;
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add CERTREQ payload to message");
- msg->add_payload(msg, (payload_t *) certreq_payload);
- }
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_init_requested_t.build_idr_payload.
- */
-static status_t build_idr_payload (private_ike_sa_init_requested_t *this, message_t *msg)
-{
- policy_t *policy = this->ike_sa->get_policy(this->ike_sa);
- identification_t *identification = policy->get_other_id(policy);
-
- if (!identification->contains_wildcards(identification))
- {
- id_payload_t *idr_payload = id_payload_create_from_identification(FALSE, identification);
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add IDr payload to message");
- msg->add_payload(msg, (payload_t *) idr_payload);
- }
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_init_requested_t.build_auth_payload.
- */
-static status_t build_auth_payload (private_ike_sa_init_requested_t *this, id_payload_t *my_id_payload, message_t *msg)
-{
- authenticator_t *authenticator;
- auth_payload_t *auth_payload;
- status_t status;
-
- authenticator = authenticator_create(this->ike_sa);
- status = authenticator->compute_auth_data(authenticator,&auth_payload,this->ike_sa_init_request_data,this->received_nonce,my_id_payload,TRUE);
- authenticator->destroy(authenticator);
-
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "could not generate AUTH data for IKE_AUTH request. Deleting IKE_SA");
- return DESTROY_ME;
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add AUTH payload to message");
- msg->add_payload(msg, (payload_t *) auth_payload);
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_init_requested_t.build_sa_payload.
- */
-static status_t build_sa_payload (private_ike_sa_init_requested_t *this, message_t *msg)
-{
- linked_list_t *proposal_list;
- sa_payload_t *sa_payload;
- policy_t *policy;
- connection_t *connection;
-
- /* get proposals form config, add to payload */
- policy = this->ike_sa->get_policy(this->ike_sa);
- proposal_list = policy->get_proposals(policy);
- /* build child sa */
- connection = this->ike_sa->get_connection(this->ike_sa);
- this->child_sa = child_sa_create(0,
- connection->get_my_host(connection),
- connection->get_other_host(connection),
- policy->get_soft_lifetime(policy),
- policy->get_hard_lifetime(policy),
- this->ike_sa->public.is_any_host_behind_nat(&this->ike_sa->public));
- if (this->child_sa->alloc(this->child_sa, proposal_list) != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "could not install CHILD_SA! Deleting IKE_SA");
- return DESTROY_ME;
- }
-
- sa_payload = sa_payload_create_from_proposal_list(proposal_list);
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add SA payload to message");
- msg->add_payload(msg, (payload_t *) sa_payload);
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_init_requested_t.build_tsi_payload.
- */
-static status_t build_tsi_payload (private_ike_sa_init_requested_t *this, message_t *msg)
-{
- policy_t *policy = this->ike_sa->get_policy(this->ike_sa);
- linked_list_t *ts_list = policy->get_my_traffic_selectors(policy);
- ts_payload_t *ts_payload = ts_payload_create_from_traffic_selectors(TRUE, ts_list);
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add TSi payload to message");
- msg->add_payload(msg, (payload_t *) ts_payload);
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_init_requested_t.build_tsr_payload.
- */
-static status_t build_tsr_payload (private_ike_sa_init_requested_t *this, message_t *msg)
-{
- policy_t *policy = this->ike_sa->get_policy(this->ike_sa);
- linked_list_t *ts_list = policy->get_other_traffic_selectors(policy);
- ts_payload_t *ts_payload = ts_payload_create_from_traffic_selectors(FALSE, ts_list);
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add TSr payload to message");
- msg->add_payload(msg, (payload_t *) ts_payload);
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_init_requested_t.process_notify_payload.
- */
-static status_t process_notify_payload(private_ike_sa_init_requested_t *this, notify_payload_t *notify_payload)
-{
- chunk_t notification_data;
- notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
-
- this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s",
- mapping_find(notify_message_type_m, notify_message_type));
-
- switch (notify_message_type)
- {
- case NO_PROPOSAL_CHOSEN:
- {
- this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained a NO_PROPOSAL_CHOSEN notify. Deleting IKE_SA");
- return DESTROY_ME;
- }
- case INVALID_MAJOR_VERSION:
- {
- this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained a INVALID_MAJOR_VERSION notify. Deleting IKE_SA");
- return DESTROY_ME;
- }
- case INVALID_KE_PAYLOAD:
- {
- initiator_init_t *initiator_init_state;
- chunk_t notify_data;
- diffie_hellman_group_t dh_group, old_dh_group;
- connection_t *connection;
-
- connection = this->ike_sa->get_connection(this->ike_sa);
- old_dh_group = connection->get_dh_group(connection);
- notify_data = notify_payload->get_notification_data(notify_payload);
- dh_group = ntohs(*((u_int16_t*)notify_data.ptr));
-
- /* TODO:
- * We are very restrictive here: If the other didn't accept
- * our DH group, and we do not accept his offer, continuation
- * is cancelled...
- */
-
- this->logger->log(this->logger, AUDIT, "peer didn't accept %s, it requested %s!",
- mapping_find(diffie_hellman_group_m, old_dh_group),
- mapping_find(diffie_hellman_group_m, dh_group));
- /* check if we can accept this dh group */
- if (!connection->check_dh_group(connection, dh_group))
- {
- this->logger->log(this->logger, AUDIT,
- "peer does only accept DH group %s, which we do not accept! Aborting",
- mapping_find(diffie_hellman_group_m, dh_group));
- return DESTROY_ME;
- }
-
- /* Going to change state back to initiator_init_t */
- this->logger->log(this->logger, CONTROL|LEVEL2, "create next state object");
- initiator_init_state = initiator_init_create(this->ike_sa);
-
- /* buffer of sent and received messages has to get reseted */
- this->ike_sa->reset_message_buffers(this->ike_sa);
-
- /* state can now be changed */
- this->ike_sa->set_new_state(this->ike_sa,(state_t *) initiator_init_state);
-
- /* state has NOW changed :-) */
- this->logger->log(this->logger, CONTROL|LEVEL2, "destroy old sate object");
- this->logger->log(this->logger, CONTROL|LEVEL2, "going to retry initialization of connection");
-
- this->public.state_interface.destroy(&(this->public.state_interface));
- if (initiator_init_state->retry_initiate_connection (initiator_init_state, dh_group) != SUCCESS)
- {
- return DESTROY_ME;
- }
- return FAILED;
- }
- case NAT_DETECTION_DESTINATION_IP:
- {
- this->natd_seen_r++;
- if (this->natd_hash_r_matched)
- return SUCCESS;
-
- notification_data = notify_payload->get_notification_data(notify_payload);
- if (chunk_equals(notification_data, this->natd_hash_r))
- {
- this->natd_hash_r_matched = TRUE;
- this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash match");
- }
- else
- {
- this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash mismatch");
- }
-
- return SUCCESS;
- }
- case NAT_DETECTION_SOURCE_IP:
- {
- this->natd_seen_i++;
- if (this->natd_hash_i_matched)
- return SUCCESS;
-
- notification_data = notify_payload->get_notification_data(notify_payload);
- if (chunk_equals(notification_data, this->natd_hash_i))
- {
- this->natd_hash_i_matched = TRUE;
- this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash match");
- }
- else
- {
- this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash mismatch");
- }
-
- return SUCCESS;
- }
- default:
- {
- /*
- * - In case of unknown error: IKE_SA gets destroyed.
- * - In case of unknown status: logging
- */
- if (notify_message_type < 16383)
- {
- this->logger->log(this->logger, AUDIT, "IKE_SA_INIT reply contained an unknown notify error (%d). Deleting IKE_SA",
- notify_message_type);
- return DESTROY_ME;
- }
- else
- {
- this->logger->log(this->logger, CONTROL, "IKE_SA_INIT reply contained an unknown notify (%d), ignored.",
- notify_message_type);
- return SUCCESS;
- }
- }
- }
-}
-
-/**
- * Implementation of state_t.get_state.
- */
-static ike_sa_state_t get_state(private_ike_sa_init_requested_t *this)
-{
- return IKE_SA_INIT_REQUESTED;
-}
-
-/**
- * Implementation of private_ike_sa_init_requested_t.destroy_after_state_change.
- */
-static void destroy_after_state_change (private_ike_sa_init_requested_t *this)
-{
- this->diffie_hellman->destroy(this->diffie_hellman);
- free(this->natd_hash_i.ptr);
- free(this->natd_hash_r.ptr);
- free(this->ike_sa_init_request_data.ptr);
- if (this->proposal)
- {
- this->proposal->destroy(this->proposal);
- }
- free(this);
-}
-
-/**
- * Implementation state_t.destroy.
- */
-static void destroy(private_ike_sa_init_requested_t *this)
-{
- this->diffie_hellman->destroy(this->diffie_hellman);
- free(this->sent_nonce.ptr);
- free(this->received_nonce.ptr);
- free(this->natd_hash_i.ptr);
- free(this->natd_hash_r.ptr);
- free(this->ike_sa_init_request_data.ptr);
-
- if (this->child_sa)
- {
- this->child_sa->destroy(this->child_sa);
- }
- if (this->proposal)
- {
- this->proposal->destroy(this->proposal);
- }
- free(this);
-}
-
-/*
- * 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,chunk_t ike_sa_init_request_data)
-{
- private_ike_sa_init_requested_t *this = malloc_thing(private_ike_sa_init_requested_t);
-
- /* interface functions */
- this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
- this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
- this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
-
- /* private functions */
- this->destroy_after_state_change = destroy_after_state_change;
- this->process_nonce_payload = process_nonce_payload;
- this->process_sa_payload = process_sa_payload;
- this->process_ke_payload = process_ke_payload;
- this->build_auth_payload = build_auth_payload;
- this->build_tsi_payload = build_tsi_payload;
- this->build_tsr_payload = build_tsr_payload;
- this->build_id_payload = build_id_payload;
- this->build_idr_payload = build_idr_payload;
- this->build_cert_payload = build_cert_payload;
- this->build_certreq_payload = build_certreq_payload;
- this->build_sa_payload = build_sa_payload;
- this->process_notify_payload = process_notify_payload;
-
- /* private data */
- this->ike_sa = ike_sa;
- this->received_nonce = CHUNK_INITIALIZER;
- this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
- this->diffie_hellman = diffie_hellman;
- this->proposal = NULL;
- this->sent_nonce = sent_nonce;
- this->child_sa = NULL;
- this->ike_sa_init_request_data = ike_sa_init_request_data;
-
- return &(this->public);
-}
diff --git a/src/charon/sa/states/ike_sa_init_requested.h b/src/charon/sa/states/ike_sa_init_requested.h
deleted file mode 100644
index 0a43afad1..000000000
--- a/src/charon/sa/states/ike_sa_init_requested.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * @file ike_sa_init_requested.h
- *
- * @brief Interface of ike_sa_init_requestet_t.
- *
- */
-
-/*
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 <types.h>
-#include <sa/ike_sa.h>
-#include <sa/states/state.h>
-#include <crypto/diffie_hellman.h>
-
-typedef struct ike_sa_init_requested_t ike_sa_init_requested_t;
-
-/**
- * @brief This class represents an IKE_SA state when
- * requested an IKE_SA_INIT as initiator.
- *
- * @b Constructors:
- * - ike_sa_init_requested_create()
- *
- * @todo Include valid child sa SPIs in proposal
- *
- * @ingroup states
- */
-struct ike_sa_init_requested_t {
- /**
- * The state_t interface.
- */
- state_t state_interface;
-};
-
-/**
- * Constructor of class ike_sa_init_requested_t.
- *
- * @param ike_sa assigned ike_sa
- * @param diffie_hellman diffie_hellman object use to retrieve shared secret
- * @param sent_nonce Sent nonce value
- * @param ike_sa_init_request_data the binary representation of the IKE_SA_INIT request message
- * @return created ike_sa_init_request_t object
- *
- * @ingroup states
- */
-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,
- chunk_t ike_sa_init_request_data);
-
-#endif /*IKE_SA_INIT_REQUESTED_H_*/
diff --git a/src/charon/sa/states/ike_sa_init_responded.c b/src/charon/sa/states/ike_sa_init_responded.c
deleted file mode 100644
index 860a53f7b..000000000
--- a/src/charon/sa/states/ike_sa_init_responded.c
+++ /dev/null
@@ -1,796 +0,0 @@
-/**
- * @file ike_sa_init_responded.c
- *
- * @brief State of a IKE_SA after responding to an IKE_SA_INIT request
- *
- */
-
-/*
- * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 <string.h>
-
-#include "ike_sa_init_responded.h"
-
-#include <daemon.h>
-#include <sa/authenticator.h>
-#include <sa/child_sa.h>
-#include <encoding/payloads/ts_payload.h>
-#include <encoding/payloads/sa_payload.h>
-#include <encoding/payloads/id_payload.h>
-#include <encoding/payloads/cert_payload.h>
-#include <encoding/payloads/auth_payload.h>
-#include <encoding/payloads/notify_payload.h>
-#include <crypto/signers/signer.h>
-#include <crypto/crypters/crypter.h>
-#include <sa/states/ike_sa_established.h>
-
-
-typedef struct private_ike_sa_init_responded_t private_ike_sa_init_responded_t;
-
-/**
- * Private data of a ike_sa_init_responded_t object.
- *
- */
-struct private_ike_sa_init_responded_t {
- /**
- * Public interface of ike_sa_init_responded_t.
- */
- ike_sa_init_responded_t public;
-
- /**
- * Assigned IKE_SA.
- */
- protected_ike_sa_t *ike_sa;
-
- /**
- * Received nonce.
- */
- chunk_t received_nonce;
-
- /**
- * Sent nonce.
- */
- chunk_t sent_nonce;
-
- /**
- * Binary representation of the IKE_SA_INIT response.
- */
- chunk_t ike_sa_init_response_data;
-
- /**
- * Binary representation of the IKE_SA_INIT request.
- */
- chunk_t ike_sa_init_request_data;
-
- /**
- * SA config to use.
- */
- policy_t *policy;
-
- /**
- * CHILD_SA, if set up
- */
- child_sa_t *child_sa;
-
- /**
- * Traffic selectors applicable at our site
- */
- linked_list_t *my_ts;
-
- /**
- * Traffic selectors applicable at remote site
- */
- linked_list_t *other_ts;
-
- /**
- * Assigned logger.
- *
- * Is logger of ike_sa!
- */
- logger_t *logger;
-
- /**
- * Process received IDi and IDr payload and build IDr payload for IKE_AUTH response.
- *
- * @param this calling object
- * @param request_idi ID payload representing initiator
- * @param request_idr ID payload representing responder (May be zero)
- * @param msg The created IDr payload is added to this message_t object
- * @param response_idr The created IDr payload is also written to this location
- */
- status_t (*build_idr_payload) (private_ike_sa_init_responded_t *this,
- id_payload_t *request_idi,
- id_payload_t *request_idr,
- message_t *msg,
- id_payload_t **response_idr);
-
- /**
- * Build CERT payload for IKE_AUTH response.
- *
- * @param this calling object
- * @param msg The created CERT payload is added to this message_t object
- */
- status_t (*build_cert_payload) (private_ike_sa_init_responded_t *this, message_t *msg);
-
- /**
- * Process received AUTH payload and build AUTH payload for IKE_AUTH response.
- *
- * @param this calling object
- * @param request AUTH payload received in IKE_AUTH request
- * @param other_id_payload other ID payload needed to verify AUTH data
- * @param my_id_payload my ID payload needed to compute AUTH data
- * @param msg The created AUTH payload is added to this message_t object
- */
- status_t (*build_auth_payload) (private_ike_sa_init_responded_t *this, auth_payload_t *request,id_payload_t *other_id_payload,id_payload_t *my_id_payload, message_t* msg);
-
- /**
- * Process received SA payload and build SA payload for IKE_AUTH response.
- *
- * @param this calling object
- * @param request SA payload received in IKE_AUTH request
- * @param msg The created SA payload is added to this message_t object
- */
- status_t (*build_sa_payload) (private_ike_sa_init_responded_t *this, sa_payload_t *request, message_t *msg);
-
- /**
- * Process received TS payload and build TS payload for IKE_AUTH response.
- *
- * @param this calling object
- * @param is_initiator type of TS payload. TRUE for TSi, FALSE for TSr
- * @param request TS payload received in IKE_AUTH request
- * @param msg the created TS payload is added to this message_t object
- */
- status_t (*build_ts_payload) (private_ike_sa_init_responded_t *this, bool ts_initiator, ts_payload_t *request, message_t *msg);
-
- /**
- * Process received CERT payload
- *
- * @param this calling object
- * @param cert_payload payload to process
- * @return
- * - DESTROY_ME if IKE_SA should be deleted
- * - SUCCSS if processed successful
- */
- status_t (*process_cert_payload) (private_ike_sa_init_responded_t *this, cert_payload_t *cert_payload);
-
- /**
- * Sends a IKE_AUTH reply containing a notify payload.
- *
- * @param this calling object
- * @param notify_payload payload to process
- * @return
- * - DESTROY_ME if IKE_SA should be deleted
- * - SUCCSS if processed successful
- */
- status_t (*process_notify_payload) (private_ike_sa_init_responded_t *this, notify_payload_t* notify_payload);
-
- /**
- * Destroy function called internally of this class after state change to
- * state IKE_SA_ESTABLISHED succeeded.
- *
- * This destroy function does not destroy objects which were passed to the new state.
- *
- * @param this calling object
- */
- void (*destroy_after_state_change) (private_ike_sa_init_responded_t *this);
-};
-
-/**
- * Implements state_t.process_message
- */
-static status_t process_message(private_ike_sa_init_responded_t *this, message_t *request)
-{
- id_payload_t *idi_request = NULL;
- id_payload_t *idr_request = NULL;
- id_payload_t *idr_response;
- ts_payload_t *tsi_request = NULL;
- ts_payload_t *tsr_request = NULL;
- auth_payload_t *auth_request = NULL;
- sa_payload_t *sa_request = NULL;
- cert_payload_t *cert_request = NULL;
- iterator_t *payloads;
- message_t *response;
- crypter_t *crypter;
- signer_t *signer;
- status_t status;
- host_t *my_host, *other_host;
- identification_t *my_id, *other_id;
- connection_t *connection;
- policy_t *policy;
-
- if (request->get_exchange_type(request) != IKE_AUTH)
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "message of type %s not supported in state ike_sa_init_respondd",
- mapping_find(exchange_type_m,request->get_exchange_type(request)));
- return FAILED;
- }
-
- if (!request->get_request(request))
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "IKE_AUTH responses not allowed state ike_sa_init_responded");
- return FAILED;
- }
-
- /* get signer for verification and crypter for decryption */
- signer = this->ike_sa->get_signer_initiator(this->ike_sa);
- crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
-
- status = request->parse_body(request, crypter, signer);
- if (status != SUCCESS)
- {
- if (status == NOT_SUPPORTED)
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "IKE_AUTH request contains unsupported payload with critical flag set. "
- "Deleting IKE_SA");
- this->ike_sa->send_notify(this->ike_sa, IKE_AUTH, UNSUPPORTED_CRITICAL_PAYLOAD, CHUNK_INITIALIZER);
- return DESTROY_ME;
- }
- else
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH request decryption failed. Ignoring message");
- }
- return status;
- }
-
- /* iterate over incoming payloads. Message is verified, we can be sure there are the required payloads */
- payloads = request->get_payload_iterator(request);
- while (payloads->has_next(payloads))
- {
- payload_t *payload;
- payloads->current(payloads, (void**)&payload);
-
- switch (payload->get_type(payload))
- {
- case ID_INITIATOR:
- idi_request = (id_payload_t*)payload;
- break;
- case CERTIFICATE:
- cert_request = (cert_payload_t*)payload;
- status = this->process_cert_payload(this, cert_request);
- if (status != SUCCESS)
- {
- payloads->destroy(payloads);
- return status;
- }
- break;
- case AUTHENTICATION:
- auth_request = (auth_payload_t*)payload;
- break;
- case ID_RESPONDER:
- idr_request = (id_payload_t*)payload;
- break;
- case SECURITY_ASSOCIATION:
- sa_request = (sa_payload_t*)payload;
- break;
- case TRAFFIC_SELECTOR_INITIATOR:
- tsi_request = (ts_payload_t*)payload;
- break;
- case TRAFFIC_SELECTOR_RESPONDER:
- tsr_request = (ts_payload_t*)payload;
- break;
- case NOTIFY:
- {
- notify_payload_t *notify_payload = (notify_payload_t *) payload;
- status = this->process_notify_payload(this, notify_payload);
- if (status != SUCCESS)
- {
- payloads->destroy(payloads);
- return status;
- }
- }
- case CERTIFICATE_REQUEST:
- {
- /* TODO handle certrequest payloads */
- }
- default:
- this->logger->log(this->logger, ERROR|LEVEL1, "ignoring payload %s (%d)",
- mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
- break;
- }
- }
- /* iterator can be destroyed */
- payloads->destroy(payloads);
-
- /* check if we have all payloads */
- if (!(idi_request && sa_request && auth_request && tsi_request && tsr_request))
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH reply did not contain all required payloads. Deleting IKE_SA");
- return DESTROY_ME;
- }
-
- status = this->ike_sa->update_connection_hosts(this->ike_sa,
- request->get_destination(request), request->get_source(request));
- if (status != SUCCESS)
- return status;
-
- /* build response */
- this->ike_sa->build_message(this->ike_sa, IKE_AUTH, FALSE, &response);
-
- /* add payloads to it */
- status = this->build_idr_payload(this, idi_request, idr_request, response, &idr_response);
- if (status != SUCCESS)
- goto destroy_response;
-
- status = this->build_cert_payload(this, response);
- if (status != SUCCESS)
- goto destroy_response;
-
- status = this->build_auth_payload(this, auth_request,idi_request, idr_response,response);
- if (status != SUCCESS)
- goto destroy_response;
-
- status = this->build_sa_payload(this, sa_request, response);
- if (status != SUCCESS)
- goto destroy_response;
-
- status = this->build_ts_payload(this, TRUE, tsi_request, response);
- if (status != SUCCESS)
- goto destroy_response;
-
- status = this->build_ts_payload(this, FALSE, tsr_request, response);
- if (status != SUCCESS)
- goto destroy_response;
-
- status = this->ike_sa->send_response(this->ike_sa, response);
- /* message can now be sent (must not be destroyed) */
-
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "unable to send IKE_AUTH reply. Deleting IKE_SA");
- response->destroy(response);
- return DESTROY_ME;
- }
-
- /* install child SA policies */
- if (!this->child_sa)
- {
- this->logger->log(this->logger, CONTROL, "proposal negotiation failed, no CHILD_SA built");
- }
- else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0)
- {
- this->logger->log(this->logger, CONTROL, "traffic selector negotiation failed, no CHILD_SA built");
- this->child_sa->destroy(this->child_sa);
- this->child_sa = NULL;
- }
- else
- {
- status = this->child_sa->add_policies(this->child_sa, this->my_ts, this->other_ts);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "could not install CHILD_SA policy! Deleting IKE_SA");
- return DESTROY_ME;
- }
- this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
- }
-
- /* create new state */
- this->ike_sa->establish(this->ike_sa);
- this->destroy_after_state_change(this);
- return SUCCESS;
-
-destroy_response:
- response->destroy(response);
- return status;
-
-}
-
-/**
- * Implementation of private_ike_sa_init_responded_t.build_idr_payload.
- */
-static status_t build_idr_payload(private_ike_sa_init_responded_t *this, id_payload_t *request_idi, id_payload_t *request_idr, message_t *msg,id_payload_t **response_idr)
-{
- identification_t *other_id, *my_id;
- id_payload_t *idr_response;
-
- /* use others ID, an ours if peer requested one */
- other_id = request_idi->get_identification(request_idi);
- if (request_idr)
- {
- my_id = request_idr->get_identification(request_idr);
- }
- else
- {
- my_id = identification_create_from_encoding(ID_ANY, CHUNK_INITIALIZER);
- }
-
- /* build new sa config */
- this->policy = charon->policies->get_policy_by_ids(charon->policies, my_id, other_id);
- if (this->policy == NULL)
- {
- this->logger->log(this->logger, AUDIT, "we don't have a policy for IDs %s - %s. Deleting IKE_SA",
- my_id->get_string(my_id), other_id->get_string(other_id));
- my_id->destroy(my_id);
- other_id->destroy(other_id);
- return DESTROY_ME;
- }
- my_id->destroy(my_id);
- other_id->destroy(other_id);
-
- /* get my id from policy, which must contain a fully qualified valid id */
- my_id = this->policy->get_my_id(this->policy);
-
- /* update others traffic selectors with actually used address */
- this->policy->update_my_ts(this->policy, msg->get_source(msg));
- this->policy->update_other_ts(this->policy, msg->get_destination(msg));
-
- /* set policy in ike_sa for other states */
- this->ike_sa->set_policy(this->ike_sa, this->policy);
-
- /* build response */
- idr_response = id_payload_create_from_identification(FALSE, my_id);
- msg->add_payload(msg, (payload_t*)idr_response);
- *response_idr = idr_response;
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_init_responded_t.build_cert_payload.
- */
-static status_t build_cert_payload (private_ike_sa_init_responded_t *this, message_t *msg)
-{
- connection_t *connection = this->ike_sa->get_connection(this->ike_sa);
-
- if (connection->get_cert_policy(connection) != CERT_NEVER_SEND)
- {
- policy_t *policy;
- identification_t *my_id;
- x509_t *cert;
- cert_payload_t *cert_payload;
-
- policy = this->ike_sa->get_policy(this->ike_sa);
- my_id = policy->get_my_id(policy);
-
- cert = charon->credentials->get_certificate(charon->credentials, my_id);
- if (cert == NULL)
- {
- this->logger->log(this->logger, ERROR, "could not find my certificate");
- return NOT_FOUND;
- }
- cert_payload = cert_payload_create_from_x509(cert);
- this->logger->log(this->logger, CONTROL|LEVEL2, "add CERT payload to message");
- msg->add_payload(msg, (payload_t *) cert_payload);
- }
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_init_responded_t.build_auth_payload.
- */
-static status_t build_auth_payload(private_ike_sa_init_responded_t *this, auth_payload_t *auth_request,id_payload_t *other_id_payload,id_payload_t *my_id_payload, message_t* msg)
-{
- authenticator_t *authenticator;
- auth_payload_t *auth_reply;
- status_t status;
-
- authenticator = authenticator_create(this->ike_sa);
- status = authenticator->verify_auth_data(authenticator,auth_request, this->ike_sa_init_request_data,this->sent_nonce,other_id_payload,TRUE);
-
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH request verification failed. Deleting IKE_SA");
- this->ike_sa->send_notify(this->ike_sa, IKE_AUTH, AUTHENTICATION_FAILED, CHUNK_INITIALIZER);
- authenticator->destroy(authenticator);
- return DESTROY_ME;
- }
-
- status = authenticator->compute_auth_data(authenticator,&auth_reply, this->ike_sa_init_response_data,this->received_nonce,my_id_payload,FALSE);
- authenticator->destroy(authenticator);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "unable to build authentication data for IKE_AUTH reply. Deleting IKE_S");
- return DESTROY_ME;
- }
-
- msg->add_payload(msg, (payload_t *)auth_reply);
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_init_responded_t.build_sa_payload.
- */
-static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_payload_t *request, message_t *msg)
-{
- proposal_t *proposal, *proposal_tmp;
- linked_list_t *proposal_list;
- sa_payload_t *sa_response;
- chunk_t seed;
- prf_plus_t *prf_plus;
- status_t status;
- connection_t *connection;
- policy_t *policy;
- bool use_natt;
-
- /* prepare reply */
- sa_response = sa_payload_create();
-
- /* get proposals from request, and select one with ours */
- proposal_list = request->get_proposals(request);
- this->logger->log(this->logger, CONTROL|LEVEL1, "selecting proposals:");
- proposal = this->policy->select_proposal(this->policy, proposal_list);
- /* list is not needed anymore */
- while (proposal_list->remove_last(proposal_list, (void**)&proposal_tmp) == SUCCESS)
- {
- proposal_tmp->destroy(proposal_tmp);
- }
- proposal_list->destroy(proposal_list);
- /* do we have a proposal? */
- if (proposal == NULL)
- {
- notify_payload_t *notify;
- this->logger->log(this->logger, AUDIT, "IKE_AUTH request did not contain any proposals we accept. "
- "Adding NO_PROPOSAL_CHOSEN notify");
- /* add NO_PROPOSAL_CHOSEN and an empty SA payload */
- notify = notify_payload_create_from_protocol_and_type(PROTO_IKE, NO_PROPOSAL_CHOSEN);
- msg->add_payload(msg, (payload_t*) notify);
- }
- else
- {
- /* set up child sa */
- seed = chunk_alloc(this->received_nonce.len + this->sent_nonce.len);
- memcpy(seed.ptr, this->received_nonce.ptr, this->received_nonce.len);
- memcpy(seed.ptr + this->received_nonce.len, this->sent_nonce.ptr, this->sent_nonce.len);
- prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
- chunk_free(&seed);
-
- policy = this->ike_sa->get_policy(this->ike_sa);
- connection = this->ike_sa->get_connection(this->ike_sa);
- use_natt = this->ike_sa->public.is_any_host_behind_nat(&this->ike_sa->public);
- this->child_sa = child_sa_create(0,
- connection->get_my_host(connection),
- connection->get_other_host(connection),
- policy->get_soft_lifetime(policy),
- policy->get_hard_lifetime(policy),
- use_natt);
-
- status = this->child_sa->add(this->child_sa, proposal, prf_plus);
- prf_plus->destroy(prf_plus);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "could not install CHILD_SA! Deleting IKE_SA");
- /* TODO: how do we handle this cleanly? */
- sa_response->destroy(sa_response);
- proposal->destroy(proposal);
- return DESTROY_ME;
- }
-
- /* add proposal to sa payload */
- sa_response->add_proposal(sa_response, proposal);
- proposal->destroy(proposal);
- }
- msg->add_payload(msg, (payload_t*)sa_response);
- return SUCCESS;
-}
-
-/**
- * Implementation of private_ike_sa_init_responded_t.build_ts_payload.
- */
-static status_t build_ts_payload(private_ike_sa_init_responded_t *this, bool ts_initiator, ts_payload_t *request, message_t* msg)
-{
- linked_list_t *ts_received, *ts_selected;
- traffic_selector_t *ts;
- status_t status = SUCCESS;
- ts_payload_t *ts_response;
-
- /* build a reply payload with selected traffic selectors */
- ts_received = request->get_traffic_selectors(request);
- /* select ts depending on payload type */
- if (ts_initiator)
- {
- ts_selected = this->policy->select_other_traffic_selectors(this->policy, ts_received);
- this->other_ts = ts_selected;
- }
- else
- {
- ts_selected = this->policy->select_my_traffic_selectors(this->policy, ts_received);
- this->my_ts = ts_selected;
- }
-
- ts_response = ts_payload_create_from_traffic_selectors(ts_initiator, ts_selected);
- msg->add_payload(msg, (payload_t*) ts_response);
-
- /* add notify if traffic selectors do not match */
- if (!ts_initiator &&
- (ts_selected->get_count(ts_selected) == 0 || this->other_ts->get_count(this->other_ts) == 0))
- {
- notify_payload_t *notify;
-
- this->logger->log(this->logger, AUDIT, "IKE_AUTH request did not contain any traffic selectors we accept. "
- "Adding TS_UNACCEPTABLE notify");
-
- notify = notify_payload_create_from_protocol_and_type(0, TS_UNACCEPTABLE);
- msg->add_payload(msg, (payload_t*)notify);
- }
-
- /* cleanup */
- while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS)
- {
- ts->destroy(ts);
- }
- ts_received->destroy(ts_received);
-
- return status;
-}
-
-/**
- * Implements private_ike_sa_init_responded_t.process_cert_payload
- */
-static status_t process_cert_payload(private_ike_sa_init_responded_t *this, cert_payload_t * cert_payload)
-{
- bool found;
- x509_t *cert;
-
- if (cert_payload->get_cert_encoding(cert_payload) != CERT_X509_SIGNATURE)
- {
- this->logger->log(this->logger, CONTROL, "certificate encoding is %s, ignored",
- enum_name(&cert_encoding_names, cert_payload->get_cert_encoding(cert_payload)));
- return SUCCESS;
- }
- cert = x509_create_from_chunk(cert_payload->get_data_clone(cert_payload));
-
- if (charon->credentials->verify(charon->credentials, cert, &found))
- {
- this->logger->log(this->logger, CONTROL, "end entity certificate is trusted");
- if (!found)
- {
- cert = charon->credentials->add_end_certificate(charon->credentials, cert);
- }
- }
- else
- {
- this->logger->log(this->logger, ERROR, "end entity certificate is not trusted");
- }
- return SUCCESS;
-}
-
-/**
- * Implements private_ike_sa_init_responded_t.process_notify_payload
- */
-static status_t process_notify_payload(private_ike_sa_init_responded_t *this, notify_payload_t *notify_payload)
-{
- notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
-
- this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s",
- mapping_find(notify_message_type_m, notify_message_type));
-
- switch (notify_message_type)
- {
- case SET_WINDOW_SIZE:
- /*
- * TODO Increase window size.
- */
- case INITIAL_CONTACT:
- /*
- * TODO Delete existing IKE_SA's with other Identity.
- */
- default:
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH request contained an unknown notify (%d), ignored.", notify_message_type);
- }
- }
-
- return SUCCESS;
-}
-
-/**
- * Implementation of state_t.get_state.
- */
-static ike_sa_state_t get_state(private_ike_sa_init_responded_t *this)
-{
- return IKE_SA_INIT_RESPONDED;
-}
-
-/**
- * Implementation of state_t.destroy.
- */
-static void destroy(private_ike_sa_init_responded_t *this)
-{
- chunk_free(&(this->received_nonce));
- chunk_free(&(this->sent_nonce));
- chunk_free(&(this->ike_sa_init_response_data));
- chunk_free(&(this->ike_sa_init_request_data));
- if (this->my_ts)
- {
- traffic_selector_t *ts;
- while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS)
- {
- ts->destroy(ts);
- }
- this->my_ts->destroy(this->my_ts);
- }
- if (this->other_ts)
- {
- traffic_selector_t *ts;
- while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS)
- {
- ts->destroy(ts);
- }
- this->other_ts->destroy(this->other_ts);
- }
- if (this->child_sa)
- {
- this->child_sa->destroy(this->child_sa);
- }
-
- free(this);
-}
-/**
- * Implementation of private_ike_sa_init_responded.destroy_after_state_change.
- */
-static void destroy_after_state_change(private_ike_sa_init_responded_t *this)
-{
- chunk_free(&(this->received_nonce));
- chunk_free(&(this->sent_nonce));
- chunk_free(&(this->ike_sa_init_response_data));
- chunk_free(&(this->ike_sa_init_request_data));
- if (this->my_ts)
- {
- traffic_selector_t *ts;
- while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS)
- {
- ts->destroy(ts);
- }
- this->my_ts->destroy(this->my_ts);
- }
- if (this->other_ts)
- {
- traffic_selector_t *ts;
- while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS)
- {
- ts->destroy(ts);
- }
- this->other_ts->destroy(this->other_ts);
- }
-
- free(this);
-}
-
-/*
- * Described in header.
- */
-ike_sa_init_responded_t *ike_sa_init_responded_create(protected_ike_sa_t *ike_sa, chunk_t received_nonce, chunk_t sent_nonce,chunk_t ike_sa_init_request_data, chunk_t ike_sa_init_response_data)
-{
- private_ike_sa_init_responded_t *this = malloc_thing(private_ike_sa_init_responded_t);
-
- /* interface functions */
- this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
- this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
- this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
-
- /* private functions */
- this->build_idr_payload = build_idr_payload;
- this->build_cert_payload = build_cert_payload;
- this->build_auth_payload = build_auth_payload;
- this->build_sa_payload = build_sa_payload;
- this->build_ts_payload = build_ts_payload;
- this->process_cert_payload = process_cert_payload;
- this->process_notify_payload = process_notify_payload;
- this->destroy_after_state_change = destroy_after_state_change;
-
- /* private data */
- this->ike_sa = ike_sa;
- this->received_nonce = received_nonce;
- this->sent_nonce = sent_nonce;
- this->ike_sa_init_response_data = ike_sa_init_response_data;
- this->ike_sa_init_request_data = ike_sa_init_request_data;
- this->my_ts = NULL;
- this->other_ts = NULL;
- this->child_sa = NULL;
- this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
-
- return &(this->public);
-}
diff --git a/src/charon/sa/states/ike_sa_init_responded.h b/src/charon/sa/states/ike_sa_init_responded.h
deleted file mode 100644
index 43aecf26f..000000000
--- a/src/charon/sa/states/ike_sa_init_responded.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * @file ike_sa_init_responded.h
- *
- * @brief Interface of ike_sa_init_responded_t.
- *
- */
-
-/*
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 <sa/ike_sa.h>
-#include <sa/states/state.h>
-
-typedef struct ike_sa_init_responded_t ike_sa_init_responded_t;
-
-/**
- * @brief This class represents an IKE_SA state when
- * responded to an IKE_SA_INIT request.
- *
- * The state accpets IKE_AUTH requests. It proves the authenticity
- * and sets up the first child sa. Then it sends back an IKE_AUTH
- * reply and changes to the IKE_SA_ESTABLISHED state.
- *
- * @b Constructors:
- * - ike_sa_init_response_data()
- *
- * @todo Implement handling of SET_WINDOW_SIZE notify
- *
- * @todo Implement handling of INITIAL_CONTACT notify
- *
- * @ingroup states
- */
-struct ike_sa_init_responded_t {
- /**
- * The state_t interface.
- */
- state_t state_interface;
-
-};
-
-/**
- * @brief Constructor of class ike_sa_init_responded_t
- *
- * @param ike_sa assigned IKE_SA
- * @param received_nonce received nonce data in IKE_SA_INIT request
- * @param sent_nonce sent nonce data in IKE_SA_INIT response
- * @param ike_sa_init_request_data binary representation of received IKE_SA_INIT request
- * @param ike_sa_init_response_data binary representation of sent IKE_SA_INIT response
- *
- * @ingroup states
- */
-ike_sa_init_responded_t *ike_sa_init_responded_create(protected_ike_sa_t *ike_sa,
- chunk_t received_nonce,
- chunk_t sent_nonce,
- chunk_t ike_sa_init_request_data,
- chunk_t ike_sa_init_response_data);
-
-#endif /*IKE_SA_INIT_RESPONDED_H_*/
diff --git a/src/charon/sa/states/initiator_init.c b/src/charon/sa/states/initiator_init.c
deleted file mode 100644
index aa86b514b..000000000
--- a/src/charon/sa/states/initiator_init.c
+++ /dev/null
@@ -1,440 +0,0 @@
-/**
- * @file initiator_init.c
- *
- * @brief Implementation of initiator_init_t.
- *
- */
-
-/*
- * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 "initiator_init.h"
-
-
-#include <daemon.h>
-#include <sa/states/state.h>
-#include <sa/states/ike_sa_init_requested.h>
-#include <queues/jobs/retransmit_request_job.h>
-#include <crypto/diffie_hellman.h>
-#include <crypto/hashers/hasher.h>
-#include <encoding/payloads/sa_payload.h>
-#include <encoding/payloads/ke_payload.h>
-#include <encoding/payloads/nonce_payload.h>
-
-
-typedef struct private_initiator_init_t private_initiator_init_t;
-
-/**
- * Private data of a initiator_init_t object..
- *
- */
-struct private_initiator_init_t {
- /**
- * Methods of the state_t interface.
- */
- initiator_init_t public;
-
- /**
- * Assigned IKE_SA.
- */
- protected_ike_sa_t *ike_sa;
-
- /**
- * Diffie hellman object used to generate public DH value.
- * This objet is passed to the next state of type IKE_SA_INIT_REQUESTED.
- */
- diffie_hellman_t *diffie_hellman;
-
- /**
- * Sent nonce.
- * This nonce is passed to the next state of type IKE_SA_INIT_REQUESTED.
- */
- chunk_t sent_nonce;
-
- /**
- * Assigned logger.
- *
- * Is logger of ike_sa!
- */
- logger_t *logger;
-
- /**
- * Builds the SA payload for this state.
- *
- * @param this calling object
- * @param msg message_t object to add the SA payload
- */
- void (*build_sa_payload) (private_initiator_init_t *this, message_t *msg);
-
- /**
- * Builds the KE payload for this state.
- *
- * @param this calling object
- * @param msg message_t object to add the KE payload
- */
- void (*build_ke_payload) (private_initiator_init_t *this, message_t *msg);
-
- /**
- * Builds the NONCE payload for this state.
- *
- * @param this calling object
- * @param msg message_t object to add the NONCE payload
- */
- status_t (*build_nonce_payload) (private_initiator_init_t *this,message_t *msg);
-
- /**
- * Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
- * Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
- *
- * @param this calling object
- * @param msg message_t object to add the Notify payloads
- */
- void (*build_natd_payload) (private_initiator_init_t *this, message_t *msg, notify_message_type_t type, host_t *host);
-
- /**
- * Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
- * Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
- *
- * @param this calling object
- * @param msg message_t object to add the Notify payloads
- */
- void (*build_natd_payloads) (private_initiator_init_t *this, message_t *msg);
-
- /**
- * Destroy function called internally of this class after state change to state
- * IKE_SA_INIT_REQUESTED succeeded.
- *
- * This destroy function does not destroy objects which were passed to the new state.
- *
- * @param this calling object
- */
- void (*destroy_after_state_change) (private_initiator_init_t *this);
-};
-
-/**
- * Implementation of initiator_init_t.initiate_connection.
- */
-static status_t initiate_connection (private_initiator_init_t *this, connection_t *connection)
-{
- policy_t *policy;
- diffie_hellman_group_t dh_group;
- host_t *my_host, *other_host;
- identification_t *my_id, *other_id;
- char *name;
-
- name = connection->get_name(connection);
- this->ike_sa->set_connection(this->ike_sa, connection);
-
- /* get policy */
- policy = charon->policies->get_policy_by_name(charon->policies, name);
- if (policy == NULL)
- {
- this->logger->log(this->logger, ERROR | LEVEL1,
- "could not get a policy named '%s', aborting", name);
- return DESTROY_ME;
- }
- this->ike_sa->set_policy(this->ike_sa, policy);
-
- my_host = connection->get_my_host(connection);
- other_host = connection->get_other_host(connection);
- my_id = policy->get_my_id(policy);
- other_id = policy->get_other_id(policy);
-
- this->logger->log(this->logger, CONTROL, "initiating connection \"%s\": %s[%s]...%s[%s]",
- name,
- my_host->get_address(my_host),
- my_id->get_string(my_id),
- other_host->get_address(other_host),
- other_id->get_string(other_id));
-
- /* we must guess now a DH group. For that we choose our most preferred group */
- dh_group = connection->get_dh_group(connection);
-
- /* next step is done in retry_initiate_connection */
- return this->public.retry_initiate_connection(&this->public, dh_group);
-}
-
-/**
- * Implementation of initiator_init_t.retry_initiate_connection.
- */
-status_t retry_initiate_connection (private_initiator_init_t *this, diffie_hellman_group_t dh_group)
-{
- ike_sa_init_requested_t *next_state;
- chunk_t ike_sa_init_request_data;
- connection_t *connection;
- ike_sa_id_t *ike_sa_id;
- message_t *message;
- status_t status;
-
- this->diffie_hellman = diffie_hellman_create(dh_group);
- if (this->diffie_hellman == NULL)
- {
- this->logger->log(this->logger, AUDIT, "DH group %s (%d) not supported, aborting",
- mapping_find(diffie_hellman_group_m, dh_group), dh_group);
- return DESTROY_ME;
- }
-
- connection = this->ike_sa->get_connection(this->ike_sa);
- ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public));
- ike_sa_id->set_responder_spi(ike_sa_id,0);
-
- /* going to build message */
- this->logger->log(this->logger, CONTROL|LEVEL2, "going to build message");
- this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, TRUE, &message);
-
- /* build SA payload */
- this->build_sa_payload(this, message);
- /* build KE payload */
- this->build_ke_payload(this, message);
- /* build Nonce payload */
- status = this->build_nonce_payload(this, message);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "building nonce payload failed, aborting");
- message->destroy(message);
- return DESTROY_ME;
- }
-
- /* build Notify(NAT-D) payloads */
- this->build_natd_payloads(this, message);
-
- /* message can now be sent (must not be destroyed) */
- status = this->ike_sa->send_request(this->ike_sa, message);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "unable to initiate connection, could not send message, aborting");
- message->destroy(message);
- return DESTROY_ME;
- }
-
- message = this->ike_sa->get_last_requested_message(this->ike_sa);
-
- ike_sa_init_request_data = message->get_packet_data(message);
-
- /* state can now be changed */
- this->logger->log(this->logger, CONTROL|LEVEL2, "create next state object");
- next_state = ike_sa_init_requested_create(this->ike_sa, this->diffie_hellman, this->sent_nonce,ike_sa_init_request_data);
- this->ike_sa->set_new_state(this->ike_sa,(state_t *) next_state);
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "destroy old state object");
- this->destroy_after_state_change(this);
- return SUCCESS;
-}
-
-/**
- * Implementation of private_initiator_init_t.build_sa_payload.
- */
-static void build_sa_payload(private_initiator_init_t *this, message_t *msg)
-{
- sa_payload_t* sa_payload;
- linked_list_t *proposal_list;
- connection_t *connection;
-
- this->logger->log(this->logger, CONTROL|LEVEL1, "building SA payload");
-
- connection = this->ike_sa->get_connection(this->ike_sa);
-
- proposal_list = connection->get_proposals(connection);
-
- sa_payload = sa_payload_create_from_proposal_list(proposal_list);
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add SA payload to message");
- msg->add_payload(msg, (payload_t *) sa_payload);
-}
-
-/**
- * Implementation of private_initiator_init_t.build_ke_payload.
- */
-static void build_ke_payload(private_initiator_init_t *this, message_t *msg)
-{
- ke_payload_t *ke_payload;
- chunk_t key_data;
- diffie_hellman_group_t dh_group;
-
- this->logger->log(this->logger, CONTROL|LEVEL1, "building KE payload");
-
- this->diffie_hellman->get_my_public_value(this->diffie_hellman, &key_data);
- dh_group = this->diffie_hellman->get_dh_group(this->diffie_hellman);
-
- ke_payload = ke_payload_create();
- ke_payload->set_dh_group_number(ke_payload, dh_group);
- ke_payload->set_key_exchange_data(ke_payload, key_data);
-
- chunk_free(&key_data);
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add KE payload to message");
- msg->add_payload(msg, (payload_t *) ke_payload);
-}
-
-/**
- * Implementation of private_initiator_init_t.build_nonce_payload.
- */
-static status_t build_nonce_payload(private_initiator_init_t *this, message_t *msg)
-{
- nonce_payload_t *nonce_payload;
- randomizer_t *randomizer;
- status_t status;
-
- this->logger->log(this->logger, CONTROL|LEVEL1, "building NONCE payload");
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "get pseudo random bytes for NONCE");
- randomizer = this->ike_sa->get_randomizer(this->ike_sa);
-
- status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce));
- if (status != SUCCESS)
- {
- return status;
- }
-
- this->logger->log(this->logger, RAW|LEVEL2, "initiator NONCE",&(this->sent_nonce));
-
- nonce_payload = nonce_payload_create();
-
- nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add NONCE payload to message");
- msg->add_payload(msg, (payload_t *) nonce_payload);
- return SUCCESS;
-}
-
-/**
- * Implementation of private_initiator_init_t.build_natd_payload.
- */
-static void build_natd_payload(private_initiator_init_t *this, message_t *msg, notify_message_type_t type, host_t *host)
-{
- chunk_t hash;
- this->logger->log(this->logger, CONTROL|LEVEL1, "building Notify(NAT-D) payload");
- notify_payload_t *notify_payload;
- notify_payload = notify_payload_create();
- /*notify_payload->set_protocol_id(notify_payload, NULL);*/
- /*notify_payload->set_spi(notify_payload, NULL);*/
- notify_payload->set_notify_message_type(notify_payload, type);
- hash = this->ike_sa->generate_natd_hash(this->ike_sa,
- msg->get_initiator_spi(msg),
- msg->get_responder_spi(msg),
- host);
- notify_payload->set_notification_data(notify_payload, hash);
- chunk_free(&hash);
- this->logger->log(this->logger, CONTROL|LEVEL2, "add Notify(NAT-D) payload to message");
- msg->add_payload(msg, (payload_t *) notify_payload);
-}
-
-/**
- * Implementation of private_initiator_init_t.build_natd_payloads.
- */
-static void build_natd_payloads(private_initiator_init_t *this, message_t *msg)
-{
- connection_t *connection;
- linked_list_t *hostlist;
- iterator_t *hostiter;
- host_t *host;
-
- /*
- * N(NAT_DETECTION_SOURCE_IP)+
- */
- hostlist = charon->interfaces->get_addresses(charon->interfaces);
- hostiter = hostlist->create_iterator(hostlist, TRUE);
- while(hostiter->iterate(hostiter, (void**)&host)) {
- this->build_natd_payload(this, msg, NAT_DETECTION_SOURCE_IP,
- host);
- }
- hostiter->destroy(hostiter);
-
- /*
- * N(NAT_DETECTION_DESTINATION_IP)
- */
- connection = this->ike_sa->get_connection(this->ike_sa);
- this->build_natd_payload(this, msg, NAT_DETECTION_DESTINATION_IP,
- connection->get_other_host(connection));
-}
-
-/**
- * Implementation of state_t.process_message.
- */
-static status_t process_message(private_initiator_init_t *this, message_t *message)
-{
- this->logger->log(this->logger, ERROR, "in state INITIATOR_INIT, no message is processed");
- return FAILED;
-}
-
-/**
- * Implementation of state_t.get_state.
- */
-static ike_sa_state_t get_state(private_initiator_init_t *this)
-{
- return INITIATOR_INIT;
-}
-
-/**
- * Implementation of state_t.destroy.
- */
-static void destroy(private_initiator_init_t *this)
-{
- this->logger->log(this->logger, CONTROL | LEVEL3, "going to destroy initiator_init_t state object");
-
- /* destroy diffie hellman object */
- if (this->diffie_hellman != NULL)
- {
- this->diffie_hellman->destroy(this->diffie_hellman);
- }
- if (this->sent_nonce.ptr != NULL)
- {
- free(this->sent_nonce.ptr);
- }
- free(this);
-}
-
-/**
- * Implementation of private_initiator_init_t.destroy_after_state_change
- */
-static void destroy_after_state_change (private_initiator_init_t *this)
-{
- this->logger->log(this->logger, CONTROL | LEVEL3, "going to destroy initiator_init_t state object");
- free(this);
-}
-
-/*
- * Described in header.
- */
-initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa)
-{
- private_initiator_init_t *this = malloc_thing(private_initiator_init_t);
-
- /* interface functions */
- this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
- this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
- this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
-
- /* public functions */
- this->public.initiate_connection = (status_t (*)(initiator_init_t *, connection_t*)) initiate_connection;
- this->public.retry_initiate_connection = (status_t (*)(initiator_init_t *, int )) retry_initiate_connection;
-
- /* private functions */
- this->destroy_after_state_change = destroy_after_state_change;
- this->build_nonce_payload = build_nonce_payload;
- this->build_sa_payload = build_sa_payload;
- this->build_ke_payload = build_ke_payload;
- this->build_natd_payload = build_natd_payload;
- this->build_natd_payloads = build_natd_payloads;
-
- /* private data */
- this->ike_sa = ike_sa;
- this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
- this->sent_nonce = CHUNK_INITIALIZER;
- this->diffie_hellman = NULL;
-
- return &(this->public);
-}
diff --git a/src/charon/sa/states/initiator_init.h b/src/charon/sa/states/initiator_init.h
deleted file mode 100644
index 903c58038..000000000
--- a/src/charon/sa/states/initiator_init.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * @file initiator_init.h
- *
- * @brief Interface of initiator_init_t.
- *
- */
-
-/*
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 INITIATOR_INIT_H_
-#define INITIATOR_INIT_H_
-
-#include <sa/ike_sa.h>
-#include <sa/states/state.h>
-
-
-typedef struct initiator_init_t initiator_init_t;
-
-/**
- * @brief This class represents an IKE_SA state when
- * initializing a connection as initiator.
- *
- * @b Constructors:
- * - initiator_init_create()
- *
- * @ingroup states
- */
-struct initiator_init_t {
- /**
- * The state_t interface.
- */
- state_t state_interface;
-
- /**
- * Initiate a new connection with given connection_t object.
- *
- * @param this calling object
- * @param connection connection to initiate
- * @return
- * - SUCCESS
- * - DESTROY_ME if something failed
- */
- status_t (*initiate_connection) (initiator_init_t *this, connection_t *connection);
-
- /**
- * Retry to initiate a new connection with a specific dh_group_priority.
- *
- * The dh_group_priority is starting at 1.
- *
- * @param this calling object
- * @param dh_group_priority dh group priority to try with
- * @return
- * - SUCCESS
- * - DESTROY_ME if something failed (see log for error)
- */
- status_t (*retry_initiate_connection) (initiator_init_t *this, int dh_group_priority);
-};
-
-/**
- * @brief Constructor of class initiator_init_t.
- *
- * @param ike_sa assigned IKE_SA
- * @return created initiator_init_t object
- *
- * @ingroup states
- */
-initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa);
-
-
-#endif /*INITIATOR_INIT_H_*/
diff --git a/src/charon/sa/states/responder_init.c b/src/charon/sa/states/responder_init.c
deleted file mode 100644
index f9d61f90d..000000000
--- a/src/charon/sa/states/responder_init.c
+++ /dev/null
@@ -1,798 +0,0 @@
-/**
- * @file responder_init.c
- *
- * @brief Implementation of responder_init_t.
- *
- */
-
-/*
- * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 "responder_init.h"
-
-#include <daemon.h>
-#include <sa/states/state.h>
-#include <sa/states/ike_sa_init_responded.h>
-#include <encoding/payloads/sa_payload.h>
-#include <encoding/payloads/ke_payload.h>
-#include <encoding/payloads/nonce_payload.h>
-#include <encoding/payloads/certreq_payload.h>
-#include <encoding/payloads/notify_payload.h>
-#include <crypto/diffie_hellman.h>
-#include <queues/jobs/send_keepalive_job.h>
-
-
-typedef struct private_responder_init_t private_responder_init_t;
-
-/**
- * Private data of a responder_init_t object.
- *
- */
-struct private_responder_init_t {
- /**
- * Methods of the state_t interface.
- */
- 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 from selected IKE proposal.
- */
- u_int16_t dh_group_number;
-
- /**
- * Priority used to get matching dh_group number.
- */
- u_int16_t dh_group_priority;
-
- /**
- * Sent nonce value.
- *
- * This value is passed to the next state of type IKE_SA_INIT_RESPONDED.
- */
- chunk_t sent_nonce;
-
- /**
- * Received nonce value
- *
- * This value is passed to the next state of type IKE_SA_INIT_RESPONDED.
- */
- chunk_t received_nonce;
-
- /**
- * Selected proposal
- */
- proposal_t *proposal;
-
- /**
- * Logger used to log data .
- *
- * Is logger of ike_sa!
- */
- logger_t *logger;
-
- /**
- * Precomputed NAT-D hash for initiator.
- */
- chunk_t natd_hash_i;
-
- /**
- * Flag indicating that an initiator NAT-D hash matched.
- */
- bool natd_hash_i_matched;
-
- /**
- * NAT-D payload count for NAT_DETECTION_SOURCE_IP.
- */
- int natd_seen_i;
-
- /**
- * Precomputed NAT-D hash of responder.
- */
- chunk_t natd_hash_r;
-
- /**
- * Flag indicating that a responder NAT-D hash matched.
- */
- bool natd_hash_r_matched;
-
- /**
- * NAT-D payload count for NAT_DETECTION_DESTINATION_IP.
- */
- int natd_seen_r;
-
-
- /**
- * Handles received SA payload and builds the SA payload for the response.
- *
- * @param this calling object
- * @param sa_request The received SA payload
- * @param msg the SA payload is added to this message_t object.
- * @return
- * - DESTROY_ME
- * - SUCCESS
- */
- status_t (*build_sa_payload) (private_responder_init_t *this,sa_payload_t *sa_request, message_t *msg);
-
- /**
- * Handles received KE payload and builds the KE payload for the response.
- *
- * @param this calling object
- * @param ke_request The received KE payload
- * @param msg the KE payload is added to this message_t object.
- * @return
- * - DESTROY_ME
- * - SUCCESS
- */
- status_t (*build_ke_payload) (private_responder_init_t *this,ke_payload_t *ke_request, message_t *msg);
-
- /**
- * Handles received NONCE payload and builds the NONCE payload for the response.
- *
- * @param this calling object
- * @param nonce_request The received NONCE payload
- * @param msg the NONCE payload is added to this message_t object.
- * @return
- * - DESTROY_ME
- * - SUCCESS
- */
- status_t (*build_nonce_payload) (private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *msg);
-
- /**
- * Build CERTREQ payload for the response.
- *
- * @param this calling object
- * @param msg the CERTREQ payload is added to this message_t object
- * @return
- * - SUCCESS
- * - FAILED
- */
- status_t (*build_certreq_payload) (private_responder_init_t *this, message_t *msg);
-
-
- /**
- * Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
- * Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
- *
- * @param this calling object
- * @param msg message_t object to add the Notify payloads
- */
- void (*build_natd_payload) (private_responder_init_t *this, message_t *msg, notify_message_type_t type, host_t *host);
-
- /**
- * Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
- * Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
- *
- * @param this calling object
- * @param msg message_t object to add the Notify payloads
- */
- void (*build_natd_payloads) (private_responder_init_t *this, message_t *msg);
-
- /**
- * Sends a IKE_SA_INIT reply containing a notify payload.
- *
- * @param this calling object
- * @param notify_payload notify_payload to process
- */
- status_t (*process_notify_payload) (private_responder_init_t *this, notify_payload_t *notify_payload);
-
- /**
- * Destroy function called internally of this class after change
- * to state IKE_SA_INIT_RESPONDED succeeded.
- *
- * This destroy function does not destroy objects which were passed to the new state.
- *
- * @param this calling object
- */
- void (*destroy_after_state_change) (private_responder_init_t *this);
-
-};
-
-/**
- * Implementation of state_t.process_message.
- */
-static status_t process_message(private_responder_init_t *this, message_t *message)
-{
- ike_sa_init_responded_t *next_state;
- chunk_t ike_sa_init_response_data;
- chunk_t ike_sa_init_request_data;
- sa_payload_t *sa_request = NULL;
- ke_payload_t *ke_request = NULL;
- nonce_payload_t *nonce_request = NULL;
- host_t *source, *destination;
- connection_t *connection;
- iterator_t *payloads;
- message_t *response;
- status_t status;
-
- if (message->get_exchange_type(message) != IKE_SA_INIT)
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "message of type %s not supported in state responder_init",
- mapping_find(exchange_type_m,message->get_exchange_type(message)));
- return DESTROY_ME;
- }
- if (!message->get_request(message))
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT responses not allowed in state ike_sa_init_responded");
- return DESTROY_ME;
- }
-
- /* this is the first message to process, so get host infos */
- source = message->get_source(message);
- destination = message->get_destination(message);
-
- connection = charon->connections->get_connection_by_hosts(charon->connections, destination, source);
- if (connection == NULL)
- {
- /* no configuration matches given hosts */
- this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request does not match any available connection, deleting IKE_SA");
- /* TODO: inform requestor */
- return DESTROY_ME;
- }
- this->ike_sa->set_connection(this->ike_sa, connection);
- status = this->ike_sa->update_connection_hosts(this->ike_sa,
- destination, source);
- if (status != SUCCESS)
- {
- return status;
- }
-
- /* parse incoming message */
- status = message->parse_body(message, NULL, NULL);
- if (status != SUCCESS)
- {
- if (status == NOT_SUPPORTED)
- {
- this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request contains unsupported payload with critical flag set, "
- "deleting IKE_SA");
- this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, UNSUPPORTED_CRITICAL_PAYLOAD, CHUNK_INITIALIZER);
- }
- else
- {
- this->logger->log(this->logger, AUDIT, "unable to parse IKE_SA_INIT request, deleting IKE_SA");
- }
- return DESTROY_ME;
- }
-
- /*
- * Precompute NAT-D hashes.
- * Even though there SHOULD only be a single payload of Notify type
- * NAT_DETECTION_DESTINATION_IP we precompute both hashes.
- */
- this->natd_hash_i = this->ike_sa->generate_natd_hash(this->ike_sa,
- message->get_initiator_spi(message),
- message->get_responder_spi(message),
- message->get_source(message));
- this->natd_hash_i_matched = FALSE;
- this->natd_seen_i = 0;
- this->natd_hash_r = this->ike_sa->generate_natd_hash(this->ike_sa,
- message->get_initiator_spi(message),
- message->get_responder_spi(message),
- message->get_destination(message));
- this->natd_hash_r_matched = FALSE;
- this->natd_seen_r = 0;
- this->ike_sa->set_my_host_behind_nat(this->ike_sa, FALSE);
- this->ike_sa->set_other_host_behind_nat(this->ike_sa, FALSE);
-
- /* Iterate over all payloads.
- *
- * The message is already checked for the right payload types.
- */
- payloads = message->get_payload_iterator(message);
- while (payloads->has_next(payloads))
- {
- payload_t *payload;
-
- payloads->current(payloads, (void**)&payload);
-
- switch (payload->get_type(payload))
- {
- case SECURITY_ASSOCIATION:
- {
- sa_request = (sa_payload_t*)payload;
- break;
- }
- case KEY_EXCHANGE:
- {
- ke_request = (ke_payload_t*)payload;
- break;
- }
- case NONCE:
- {
- nonce_request = (nonce_payload_t*)payload;
- break;
- }
- case NOTIFY:
- {
- notify_payload_t *notify_payload = (notify_payload_t *) payload;
- status = this->process_notify_payload(this, notify_payload);
- if (status != SUCCESS)
- {
- payloads->destroy(payloads);
- return status;
- }
- break;
- }
- default:
- {
- this->logger->log(this->logger, ERROR|LEVEL1, "ignoring payload %s (%d)",
- mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
- break;
- }
- }
- }
- payloads->destroy(payloads);
-
- /* check if we have all payloads */
- if (!(sa_request && ke_request && nonce_request))
- {
- this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain all required payloads. Deleting IKE_SA");
- return DESTROY_ME;
- }
-
- /* NAT-D */
- if ((!this->natd_seen_i && this->natd_seen_r > 0)
- || (this->natd_seen_i > 0 && !this->natd_seen_r))
- {
- this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request contained wrong number of NAT-D payloads. Deleting IKE_SA");
- return DESTROY_ME;
- }
- if (this->natd_seen_r > 1)
- {
- this->logger->log(this->logger, AUDIT, "warning: IKE_SA_INIT request contained multiple Notify(NAT_DETECTION_DESTINATION_IP) payloads.");
- }
- if (this->natd_seen_i > 0 && !this->natd_hash_i_matched)
- {
- this->logger->log(this->logger, AUDIT, "remote host is behind NAT, using NAT-Traversal");
- this->ike_sa->set_other_host_behind_nat(this->ike_sa, TRUE);
- }
- if (this->natd_seen_r > 0 && !this->natd_hash_r_matched)
- {
- this->logger->log(this->logger, AUDIT, "local host is behind NAT, using NAT-Traversal");
- this->ike_sa->set_my_host_behind_nat(this->ike_sa, TRUE);
- charon->event_queue->add_relative(charon->event_queue,
- (job_t*)send_keepalive_job_create(this->ike_sa->public.get_id((ike_sa_t*)this->ike_sa)),
- charon->configuration->get_keepalive_interval(charon->configuration));
- }
- if (!this->ike_sa->public.is_any_host_behind_nat((ike_sa_t*)this->ike_sa))
- {
- this->logger->log(this->logger, AUDIT, "no NAT detected, not using NAT-Traversal");
- }
-
- this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response);
-
- status = this->build_sa_payload(this, sa_request, response);
- if (status != SUCCESS)
- goto destroy_response;
-
- status = this->build_ke_payload(this, ke_request, response);
- if (status != SUCCESS)
- goto destroy_response;
-
- status = this->build_nonce_payload(this, nonce_request, response);
- if (status != SUCCESS)
- goto destroy_response;
-
- status = this->build_certreq_payload(this, response);
- if (status != SUCCESS)
- goto destroy_response;
-
- /* build Notify(NAT-D) payloads */
- this->build_natd_payloads(this, response);
-
- /* derive all the keys used in the IKE_SA */
- status = this->ike_sa->build_transforms(this->ike_sa, this->proposal, this->diffie_hellman, this->received_nonce, this->sent_nonce);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "transform objects could not be created from selected proposal, deleting IKE_SA");
- return DESTROY_ME;
- }
-
- /* message can now be sent (must not be destroyed) */
- status = this->ike_sa->send_response(this->ike_sa, response);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "unable to send IKE_SA_INIT response, deleting IKE_SA");
- response->destroy(response);
- return DESTROY_ME;
- }
-
- /* state can now be changed */
- this->logger->log(this->logger, CONTROL|LEVEL2, "create next state object of type IKE_SA_INIT_RESPONDED");
-
- response = this->ike_sa->get_last_responded_message(this->ike_sa);
- ike_sa_init_response_data = response->get_packet_data(response);
- ike_sa_init_request_data = message->get_packet_data(message);
-
- next_state = ike_sa_init_responded_create(this->ike_sa, this->received_nonce, this->sent_nonce,ike_sa_init_request_data,
- ike_sa_init_response_data);
-
- /* state can now be changed */
- this->ike_sa->set_new_state(this->ike_sa, (state_t *) next_state);
- this->destroy_after_state_change(this);
- return SUCCESS;
-
-destroy_response:
- response->destroy(response);
- return status;
-
-}
-
-/**
- * Implementation of private_initiator_init_t.build_sa_payload.
- */
-static status_t build_sa_payload(private_responder_init_t *this,sa_payload_t *sa_request, message_t *msg)
-{
- proposal_t *proposal;
- linked_list_t *proposal_list;
- connection_t *connection;
- sa_payload_t* sa_payload;
- algorithm_t *algo;
-
- connection = this->ike_sa->get_connection(this->ike_sa);
-
- this->logger->log(this->logger, CONTROL | LEVEL2, "process received SA payload");
-
- /* get the list of suggested proposals */
- proposal_list = sa_request->get_proposals (sa_request);
-
- /* select proposal */
- this->proposal = connection->select_proposal(connection, proposal_list);
- while(proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
- {
- proposal->destroy(proposal);
- }
- proposal_list->destroy(proposal_list);
- if (this->proposal == NULL)
- {
- this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain any acceptable proposals, deleting IKE_SA");
- this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER);
- return DESTROY_ME;
- }
- /* get selected DH group to force policy, this is very restrictive!? */
- if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, &algo))
- {
- this->dh_group_number = algo->algorithm;
- }
-
- this->logger->log(this->logger, CONTROL | LEVEL2, "SA Payload processed");
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "building SA payload");
- sa_payload = sa_payload_create_from_proposal(this->proposal);
- this->logger->log(this->logger, CONTROL|LEVEL2, "add SA payload to message");
- msg->add_payload(msg, (payload_t *) sa_payload);
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_initiator_init_t.build_ke_payload.
- */
-static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke_request, message_t *msg)
-{
- diffie_hellman_group_t group;
- ke_payload_t *ke_payload;
- diffie_hellman_t *dh;
- chunk_t key_data;
-
- this->logger->log(this->logger, CONTROL | LEVEL2, "process received KE payload");
- group = ke_request->get_dh_group_number(ke_request);
-
- if (group == MODP_NONE)
- {
- this->logger->log(this->logger, AUDIT, "no Diffie-Hellman group to select, deleting IKE_SA");
- return DESTROY_ME;
- }
-
- if (this->dh_group_number != group)
- {
- u_int16_t accepted_group;
- chunk_t accepted_group_chunk;
- /* group not same as selected one
- * Maybe key exchange payload is before SA payload */
- this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain an acceptable Diffie-Hellman group, deleting IKE_SA");
-
- accepted_group = htons(this->dh_group_number);
- accepted_group_chunk.ptr = (u_int8_t*) &(accepted_group);
- accepted_group_chunk.len = 2;
- this->ike_sa->send_notify(this->ike_sa,IKE_SA_INIT,INVALID_KE_PAYLOAD,accepted_group_chunk);
- return DESTROY_ME;
- }
-
- /* create diffie hellman object to handle DH exchange */
- dh = diffie_hellman_create(group);
- if (dh == NULL)
- {
- this->logger->log(this->logger, AUDIT, "could not generate DH object with group %d, deleting IKE_SA",
- mapping_find(diffie_hellman_group_m,group) );
- return DESTROY_ME;
- }
- this->logger->log(this->logger, CONTROL | LEVEL2, "set other DH public value");
-
- dh->set_other_public_value(dh, ke_request->get_key_exchange_data(ke_request));
-
- this->diffie_hellman = dh;
-
- this->logger->log(this->logger, CONTROL | LEVEL2, "KE payload processed.");
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "building KE payload");
- this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data);
-
- ke_payload = ke_payload_create();
- ke_payload->set_key_exchange_data(ke_payload,key_data);
- ke_payload->set_dh_group_number(ke_payload, this->dh_group_number);
- chunk_free(&key_data);
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add KE payload to message");
- msg->add_payload(msg, (payload_t *) ke_payload);
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_responder_init_t.build_nonce_payload.
- */
-static status_t build_nonce_payload(private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *msg)
-{
- nonce_payload_t *nonce_payload;
- randomizer_t *randomizer;
- status_t status;
-
- this->logger->log(this->logger, CONTROL | LEVEL2, "process received NONCE payload");
- free(this->received_nonce.ptr);
- this->received_nonce = CHUNK_INITIALIZER;
-
- this->logger->log(this->logger, CONTROL | LEVEL2, "get NONCE value and store it");
- this->received_nonce = nonce_request->get_nonce(nonce_request);
-
- this->logger->log(this->logger, CONTROL | LEVEL2, "create new NONCE value.");
-
- randomizer = this->ike_sa->get_randomizer(this->ike_sa);
- status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce));
- if (status != SUCCESS)
- {
- return status;
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "building NONCE payload");
- nonce_payload = nonce_payload_create();
- nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add NONCE payload to message");
- msg->add_payload(msg, (payload_t *) nonce_payload);
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_responder_init_t.build_certreq_payload.
- */
-static status_t build_certreq_payload (private_responder_init_t *this, message_t *msg)
-{
- if (FALSE)
- {
- certreq_payload_t *certreq_payload;
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add CERTREQ payload to message");
- msg->add_payload(msg, (payload_t *) certreq_payload);
- }
- return SUCCESS;
-}
-
-/**
- * Implementation of private_initiator_init_t.build_natd_payload.
- */
-static void build_natd_payload(private_responder_init_t *this, message_t *msg, notify_message_type_t type, host_t *host)
-{
- chunk_t hash;
- this->logger->log(this->logger, CONTROL|LEVEL1, "building Notify(NAT-D) payload");
- notify_payload_t *notify_payload;
- notify_payload = notify_payload_create();
- /*notify_payload->set_protocol_id(notify_payload, NULL);*/
- /*notify_payload->set_spi(notify_payload, NULL);*/
- notify_payload->set_notify_message_type(notify_payload, type);
- hash = this->ike_sa->generate_natd_hash(this->ike_sa,
- msg->get_initiator_spi(msg),
- msg->get_responder_spi(msg),
- host);
- notify_payload->set_notification_data(notify_payload, hash);
- chunk_free(&hash);
- this->logger->log(this->logger, CONTROL|LEVEL2, "add Notify(NAT-D) payload to message");
- msg->add_payload(msg, (payload_t *) notify_payload);
-}
-
-/**
- * Implementation of private_initiator_init_t.build_natd_payloads.
- */
-static void build_natd_payloads(private_responder_init_t *this, message_t *msg)
-{
- connection_t *connection;
- connection = this->ike_sa->get_connection(this->ike_sa);
- this->build_natd_payload(this, msg, NAT_DETECTION_SOURCE_IP,
- connection->get_my_host(connection));
- this->build_natd_payload(this, msg, NAT_DETECTION_DESTINATION_IP,
- connection->get_other_host(connection));
-}
-
-/**
- * Implementation of private_responder_init_t.process_notify_payload.
- */
-static status_t process_notify_payload(private_responder_init_t *this, notify_payload_t *notify_payload)
-{
- chunk_t notification_data;
- notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
-
- this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s",
- mapping_find(notify_message_type_m, notify_message_type));
-
- switch (notify_message_type)
- {
- case NAT_DETECTION_DESTINATION_IP:
- {
- this->natd_seen_r++;
- if (this->natd_hash_r_matched)
- return SUCCESS;
-
- notification_data = notify_payload->get_notification_data(notify_payload);
- if (chunk_equals(notification_data, this->natd_hash_r))
- {
- this->natd_hash_r_matched = TRUE;
- this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash match");
- }
- else
- {
- this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash mismatch");
- }
-
- return SUCCESS;
- }
- case NAT_DETECTION_SOURCE_IP:
- {
- this->natd_seen_i++;
- if (this->natd_hash_i_matched)
- return SUCCESS;
-
- notification_data = notify_payload->get_notification_data(notify_payload);
- if (chunk_equals(notification_data, this->natd_hash_i))
- {
- this->natd_hash_i_matched = TRUE;
- this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash match");
- }
- else
- {
- this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash mismatch");
- }
-
- return SUCCESS;
- }
- default:
- {
- this->logger->log(this->logger, CONTROL, "IKE_SA_INIT request contained a notify (%d), ignored.",
- notify_message_type);
- return SUCCESS;
- }
- }
-}
-
-/**
- * Implementation of state_t.get_state.
- */
-static ike_sa_state_t get_state(private_responder_init_t *this)
-{
- return RESPONDER_INIT;
-}
-
-/**
- * Implementation of state_t.destroy.
- */
-static void destroy(private_responder_init_t *this)
-{
- this->logger->log(this->logger, CONTROL | LEVEL1, "going to destroy responder init state object");
-
- this->logger->log(this->logger, CONTROL | LEVEL2, "destroy nonces");
- chunk_free(&(this->sent_nonce));
- this->logger->log(this->logger, CONTROL | LEVEL2, "destroy received nonce");
- chunk_free(&(this->received_nonce));
-
- chunk_free(&(this->natd_hash_i));
- chunk_free(&(this->natd_hash_r));
-
- if (this->diffie_hellman != NULL)
- {
- this->logger->log(this->logger, CONTROL | LEVEL2, "destroy diffie_hellman_t hellman object");
- this->diffie_hellman->destroy(this->diffie_hellman);
- }
- if (this->proposal)
- {
- this->proposal->destroy(this->proposal);
- }
- this->logger->log(this->logger, CONTROL | LEVEL2, "destroy object");
- free(this);
-}
-
-/**
- * Implementation of private_responder_init_t.destroy_after_state_change
- */
-static void destroy_after_state_change (private_responder_init_t *this)
-{
- this->logger->log(this->logger, CONTROL | LEVEL1, "Going to destroy responder_init_t state object");
-
- chunk_free(&(this->natd_hash_i));
- chunk_free(&(this->natd_hash_r));
-
- /* destroy diffie hellman object */
- if (this->diffie_hellman != NULL)
- {
- this->logger->log(this->logger, CONTROL | LEVEL2, "destroy diffie_hellman_t object");
- this->diffie_hellman->destroy(this->diffie_hellman);
- }
- if (this->proposal)
- {
- this->proposal->destroy(this->proposal);
- }
-
- this->logger->log(this->logger, CONTROL | LEVEL2, "destroy object");
- free(this);
-}
-
-/*
- * Described in header.
- */
-responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa)
-{
- private_responder_init_t *this = malloc_thing(private_responder_init_t);
-
- /* interface functions */
- this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
- this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
- this->public.state_interface.destroy = (void (*) (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;
- this->build_certreq_payload = build_certreq_payload;
- this->destroy_after_state_change = destroy_after_state_change;
- this->process_notify_payload = process_notify_payload;
- this->build_natd_payload = build_natd_payload;
- this->build_natd_payloads = build_natd_payloads;
-
- /* private data */
- this->ike_sa = ike_sa;
- this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
- this->sent_nonce = CHUNK_INITIALIZER;
- this->received_nonce = CHUNK_INITIALIZER;
- this->dh_group_number = MODP_NONE;
- this->diffie_hellman = NULL;
- this->proposal = NULL;
- this->natd_hash_i = CHUNK_INITIALIZER;
- this->natd_hash_i_matched = FALSE;
- this->natd_seen_i = 0;
- this->natd_hash_r = CHUNK_INITIALIZER;
- this->natd_hash_r_matched = FALSE;
- this->natd_seen_r = 0;
-
- return &(this->public);
-}
diff --git a/src/charon/sa/states/responder_init.h b/src/charon/sa/states/responder_init.h
deleted file mode 100644
index c8ba73ea3..000000000
--- a/src/charon/sa/states/responder_init.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * @file responder_init.h
- *
- * @brief Interface of responder_init_t.
- *
- */
-
-/*
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 RESPONDER_INIT_H_
-#define RESPONDER_INIT_H_
-
-#include <sa/ike_sa.h>
-#include <sa/states/state.h>
-
-
-typedef struct responder_init_t responder_init_t;
-
-/**
- * @brief This class represents an IKE_SA state when
- * initializing a connection as responder.
- *
- * @b Constructors:
- * - responder_init_create()
- *
- * @ingroup states
- */
-struct responder_init_t {
- /**
- * The state_t interface.
- */
- state_t state_interface;
-};
-
-/**
- * Constructor of class responder_init_t.
- *
- * The following functions of the assigned protected_ike_sa_t object are being called with
- * valid values after successfully processing a received message and before changing
- * to next state IKE_SA_INIT_RESPONDED:
- * - protected_ike_sa_t.set_connection()
- * - protected_ike_sa_t.set_my_host()
- * - protected_ike_sa_t.set_other_host()
- * - protected_ike_sa_t.compute_secrets()
- * - protected_ike_sa_t.create_transforms_from_proposal()
- *
- * @param ike_sa assigned IKE_SA
- *
- * @return responder_init_t object
- *
- * @ingroup states
- */
-responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa);
-
-#endif /*RESPONDER_INIT_H_*/
diff --git a/src/charon/sa/states/state.c b/src/charon/sa/states/state.c
deleted file mode 100644
index 5436e7d44..000000000
--- a/src/charon/sa/states/state.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * @file state.c
- *
- * @brief Interface state_t.
- *
- */
-
-/*
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 "state.h"
-
-
-/**
- * String mappings for ike_sa_state_t.
- */
-mapping_t ike_sa_state_m[] = {
- {INITIATOR_INIT, "INITIATOR_INIT"},
- {RESPONDER_INIT, "RESPONDER_INIT"},
- {IKE_SA_INIT_REQUESTED, "IKE_SA_INIT_REQUESTED"},
- {IKE_SA_INIT_RESPONDED, "IKE_SA_INIT_RESPONDED"},
- {IKE_AUTH_REQUESTED, "IKE_AUTH_REQUESTED"},
- {IKE_SA_ESTABLISHED, "IKE_SA_ESTABLISHED"},
- {DELETE_IKE_SA_REQUESTED, "DELETE_IKE_SA_REQUESTED"},
- {CREATE_CHILD_SA_REQUESTED, "CREATE_CHILD_SA_REQUESTED"},
- {DELETE_CHILD_SA_REQUESTED, "DELETE_CHILD_SA_REQUESTED"},
- {MAPPING_END, NULL}
-};
-
diff --git a/src/charon/sa/states/state.h b/src/charon/sa/states/state.h
deleted file mode 100644
index e1cd490fa..000000000
--- a/src/charon/sa/states/state.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/**
- * @file state.h
- *
- * @brief Interface state_t.
- *
- */
-
-/*
- * 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 <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * 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 STATE_H_
-#define STATE_H_
-
-#include <definitions.h>
-#include <types.h>
-#include <encoding/message.h>
-
-typedef enum ike_sa_state_t ike_sa_state_t;
-
-/**
- * States in which a IKE_SA can be.
- *
- * @todo Support of more states (CHILD_SA_REQUESTED, etc...)
- *
- * @see state_t for state diagram
- *
- * @ingroup states
- */
-enum ike_sa_state_t {
-
- /**
- * @brief IKE_SA is in initial state as initiator and is going to initiate a new connection.
- *
- * Next state following this state is IKE_SA_INIT_REQUESTED.
- *
- * Implemented in class initiator_init_t.
- */
- INITIATOR_INIT = 1,
-
- /**
- * @brief IKE_SA is in initial state as responder and is going to respond to a initiated connection.
- *
- * Next state following this state is IKE_SA_INIT_RESPONDED.
- *
- * Implemented in class responder_init_t.
- */
- RESPONDER_INIT,
-
- /**
- * @brief A IKE_SA_INIT request was sent. In this state a reply of type IKE_SA_INIT is expected.
- *
- * Two states are possible as next states:
- * - IKE_AUTH_REQUESTED if IKE_SA_INIT reply could successfully processed and IKE_AUTH request could be sent.
- * - INITIATOR_INIT if selected DH group was not the one selected by other peer.
- *
- * Implemented in class ike_sa_init_requested_t.
- */
- IKE_SA_INIT_REQUESTED,
-
- /**
- * @brief A IKE_SA_INIT response was sent. In this state a request of type IKE_AUTH is expected.
- *
- * Next state following this state is IKE_SA_ESTABLISHED.
- *
- * Implemented in class ike_sa_init_responded_t.
- */
- IKE_SA_INIT_RESPONDED,
-
- /**
- * @brief An IKE_AUTH request was sent after a successful IKE_SA_INIT-exchange.
- *
- * Next state following this state is IKE_SA_ESTABLISHED.
- *
- * Implemented in class ike_auth_requested_t.
- */
- IKE_AUTH_REQUESTED,
-
- /**
- * @brief An IKE_AUTH exchange was successfuly handled either as initiator or responder.
- *
- * In this state, all the informations for an IKE_SA and one CHILD_SA are known.
- *
- * Implemented in class ike_sa_established_t.
- */
- IKE_SA_ESTABLISHED,
-
- /**
- * @brief A rekeying/create CHILD_SA request was sent.
- *
- * Implemented in class create_child_sa_requested.
- */
- CREATE_CHILD_SA_REQUESTED,
-
- /**
- * @brief A delete CHILD_SA request was sent.
- *
- * Implemented in class delete_child_sa_requested.
- */
- DELETE_CHILD_SA_REQUESTED,
-
- /**
- * @brief An IKE SA has sent a DELETE IKE_SA to the other peer.
- *
- * After a call to ike_sa.close(), the IKE_SA sends a delete message
- * to the remote peer and switches to this state. It waits until the
- * message is aknowledged, or a certain timout occurs.
- *
- * Implemented in class delete_requested.
- */
- DELETE_IKE_SA_REQUESTED,
-};
-
-
-/**
- * String mappings for ike_sa_state_t.
- */
-extern mapping_t ike_sa_state_m[];
-
-
-typedef struct state_t state_t;
-
-/**
- * @brief This interface represents an IKE_SA state.
- *
- * A state_t object is responsible to handle incoming messages. States
- * are exclusive, an IKE_SA is exactly in one state. They are used on IKE_SA
- * setup, as there is a strict scheme message exchange follow. This can be
- * mapped in a state machine. Every state is represented in a single class,
- * and the IKE_SA may switch these states by replacing the owned state.
- @verbatim
- initiator responder
- --------- ---------
-
- ¦ ¦
- V ¦
- +-----------------------+ ¦
- ¦ initiator_init ¦ msg1 V
- +-----------------------+ -----> +-----------------------+
- ¦ msg2 ¦ responder_init ¦
- V <----- +-----------------------+
- +-----------------------+ ¦
- ¦ ike_sa_init_requested ¦ msg3 V
- +-----------------------+ -----> +-----------------------+
- ¦ msg4 ¦ ike_sa_init_requested ¦
- V <----- +-----------------------+
- +-----------------------+ ¦
- ¦ ike_auth_requested ¦ ¦
- +-----------------------+ ¦
- ¦ ¦
- V V
- +---------------------------+
- ¦ ike_sa_established ¦
- +---------------------------+
- ¦
- V
- +---------------------------+
- ¦ delete_requested ¦
- +---------------------------+
-
- msg1 = IKE_SA_INIT request
- msg2 = IKE_SA_INIT response
- msg3 = IKE_AUTH request
- msg4 = IKE_AUTH response
- @endverbatim
- * Every state can be left by deleting the IKE_SA, except the state
- * ike_sa_established: it must switch to the delete_requested state first,
- * as the peer must be informed about the delete.
- *
- * For the handling of message in a established IKE_SA, another concept is used.
- * The state-concept is good if a single state is possible. But in a established
- * IKE_SA, there is no strict message order, and if a window size > 1 is used,
- * multiple "states" would be possible. We call this transactions, better
- * descripted in the transaction_t interface.
- *
- * @b Constructors:
- * - initiator_init_create()
- * - responder_init_create()
- * - ike_sa_init_requested_create()
- * - ike_sa_init_responded_create()
- * - ike_auth_requested_create()
- * - ike_sa_established_create()
- * - delete_requested_create()
- *
- * @ingroup states
- */
-struct state_t {
-
- /**
- * @brief Processes a incoming IKEv2-Message of type message_t.
- *
- * @param this calling object
- * @param[in] message message_t object to process
- * @return
- * - SUCCESSFUL
- * - FAILED
- * - DESTROY_ME if belonging IKE_SA should be deleted
- */
- status_t (*process_message) (state_t *this,message_t *message);
-
- /**
- * @brief Get the current state representing by this state_t object.
- *
- * @param this calling object
- * @return state
- */
- ike_sa_state_t (*get_state) (state_t *this);
-
- /**
- * @brief Destroys a state_t object.
- *
- * @param this calling object
- */
- void (*destroy) (state_t *this);
-};
-
-#endif /* STATE_H_ */
diff --git a/src/charon/sa/transactions/dead_peer_detection.c b/src/charon/sa/transactions/dead_peer_detection.c
new file mode 100644
index 000000000..de15c49ab
--- /dev/null
+++ b/src/charon/sa/transactions/dead_peer_detection.c
@@ -0,0 +1,198 @@
+/**
+ * @file dead_peer_detection.c
+ *
+ * @brief Implementation of the dead_peer_detection transaction.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 "dead_peer_detection.h"
+
+#include <daemon.h>
+
+
+typedef struct private_dead_peer_detection_t private_dead_peer_detection_t;
+
+/**
+ * Private members of a dead_peer_detection_t object..
+ */
+struct private_dead_peer_detection_t {
+
+ /**
+ * Public methods and transaction_t interface.
+ */
+ dead_peer_detection_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Message sent by our peer, if already generated
+ */
+ message_t *message;
+
+ /**
+ * Message ID this transaction uses
+ */
+ u_int32_t message_id;
+
+ /**
+ * Times we did send the request
+ */
+ u_int32_t requested;
+
+ /**
+ * Assigned logger.
+ */
+ logger_t *logger;
+};
+
+/**
+ * Implementation of transaction_t.get_message_id.
+ */
+static u_int32_t get_message_id(private_dead_peer_detection_t *this)
+{
+ return this->message_id;
+}
+
+/**
+ * Implementation of transaction_t.requested.
+ */
+static u_int32_t requested(private_dead_peer_detection_t *this)
+{
+ return this->requested++;
+}
+
+/**
+ * Implementation of transaction_t.get_request.
+ */
+static status_t get_request(private_dead_peer_detection_t *this, message_t **result)
+{
+ message_t *request;
+ connection_t *connection;
+ host_t *me, *other;
+
+ /* check if we already have built a message (retransmission) */
+ if (this->message)
+ {
+ *result = this->message;
+ return SUCCESS;
+ }
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+ me = connection->get_my_host(connection);
+ other = connection->get_other_host(connection);
+
+ /* build the request */
+ request = message_create();
+ request->set_source(request, me->clone(me));
+ request->set_destination(request, other->clone(other));
+ request->set_exchange_type(request, INFORMATIONAL);
+ request->set_request(request, TRUE);
+ request->set_message_id(request, this->message_id);
+ request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
+ /* apply for caller */
+ *result = request;
+ /* store for retransmission */
+ this->message = request;
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of transaction_t.get_response.
+ */
+static status_t get_response(private_dead_peer_detection_t *this, message_t *request,
+ message_t **result, transaction_t **next)
+{
+ host_t *me, *other;
+ message_t *response;
+ connection_t *connection;
+
+ /* check if we already have built a response (retransmission) */
+ if (this->message)
+ {
+ *result = this->message;
+ return SUCCESS;
+ }
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+ me = connection->get_my_host(connection);
+ other = connection->get_other_host(connection);
+
+ /* set up response */
+ response = message_create();
+ response->set_source(response, me->clone(me));
+ response->set_destination(response, other->clone(other));
+ response->set_exchange_type(response, INFORMATIONAL);
+ response->set_request(response, FALSE);
+ response->set_message_id(response, this->message_id);
+ response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
+ this->message = response;
+ *result = response;
+
+ return SUCCESS;
+}
+
+
+/**
+ * Implementation of transaction_t.conclude
+ */
+static status_t conclude(private_dead_peer_detection_t *this, message_t *response,
+ transaction_t **transaction)
+{
+ return SUCCESS;
+}
+
+/**
+ * implements transaction_t.destroy
+ */
+static void destroy(private_dead_peer_detection_t *this)
+{
+ if (this->message)
+ {
+ this->message->destroy(this->message);
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+dead_peer_detection_t *dead_peer_detection_create(ike_sa_t *ike_sa, u_int32_t message_id)
+{
+ private_dead_peer_detection_t *this = malloc_thing(private_dead_peer_detection_t);
+
+ /* transaction interface functions */
+ this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
+ this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
+ this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
+ this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
+ this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
+ this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+ this->message_id = message_id;
+ this->message = NULL;
+ this->requested = 0;
+ this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
+
+ return &this->public;
+}
diff --git a/src/charon/sa/transactions/dead_peer_detection.h b/src/charon/sa/transactions/dead_peer_detection.h
new file mode 100644
index 000000000..7df4410d1
--- /dev/null
+++ b/src/charon/sa/transactions/dead_peer_detection.h
@@ -0,0 +1,60 @@
+/**
+ * @file dead_peer_detection.h
+ *
+ * @brief Interface of transaction dead_peer_detection.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 DEAD_PEER_DETECTION_H_
+#define DEAD_PEER_DETECTION_H_
+
+#include <sa/ike_sa.h>
+#include <sa/transactions/transaction.h>
+
+
+typedef struct dead_peer_detection_t dead_peer_detection_t;
+
+/**
+ * @brief A transaction used to detect dead peers.
+ *
+ * In IKEv2, dead peer detection is done using empty
+ * informational messages. These must be acknowledged.
+ *
+ * @ingroup transactions
+ */
+struct dead_peer_detection_t {
+
+ /**
+ * The transaction_t interface.
+ */
+ transaction_t transaction;
+};
+
+/**
+ * @brief Create a new transaction which detects dead peers.
+ *
+ * @param ike_sa assigned IKE_SA
+ * @param message_id message ids used in this transaction
+ * @return created dead_peer_detection transaction
+ *
+ * @ingroup transactions
+ */
+dead_peer_detection_t *dead_peer_detection_create(ike_sa_t *ike_sa, u_int32_t message_id);
+
+#endif /* DEAD_PEER_DETECTION_H_ */
diff --git a/src/charon/sa/transactions/delete_ike_sa.c b/src/charon/sa/transactions/delete_ike_sa.c
new file mode 100644
index 000000000..a8ec334a7
--- /dev/null
+++ b/src/charon/sa/transactions/delete_ike_sa.c
@@ -0,0 +1,271 @@
+/**
+ * @file delete_ike_sa.c
+ *
+ * @brief Implementation of the delete_ike_sa transaction.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 "delete_ike_sa.h"
+
+#include <daemon.h>
+#include <encoding/payloads/delete_payload.h>
+
+
+typedef struct private_delete_ike_sa_t private_delete_ike_sa_t;
+
+/**
+ * Private members of a delete_ike_sa_t object..
+ */
+struct private_delete_ike_sa_t {
+
+ /**
+ * Public methods and transaction_t interface.
+ */
+ delete_ike_sa_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Message sent by our peer, if already generated
+ */
+ message_t *message;
+
+ /**
+ * Message ID this transaction uses
+ */
+ u_int32_t message_id;
+
+ /**
+ * Times we did send the request
+ */
+ u_int32_t requested;
+
+ /**
+ * Assigned logger.
+ */
+ logger_t *logger;
+};
+
+/**
+ * Implementation of transaction_t.get_message_id.
+ */
+static u_int32_t get_message_id(private_delete_ike_sa_t *this)
+{
+ return this->message_id;
+}
+
+/**
+ * Implementation of transaction_t.requested.
+ */
+static u_int32_t requested(private_delete_ike_sa_t *this)
+{
+ return this->requested++;
+}
+
+/**
+ * Implementation of transaction_t.get_request.
+ */
+static status_t get_request(private_delete_ike_sa_t *this, message_t **result)
+{
+ message_t *request;
+ connection_t *connection;
+ host_t *me, *other;
+ delete_payload_t *delete_payload;
+
+ /* check if we already have built a message (retransmission) */
+ if (this->message)
+ {
+ *result = this->message;
+ return SUCCESS;
+ }
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+ me = connection->get_my_host(connection);
+ other = connection->get_other_host(connection);
+
+ /* build the request */
+ request = message_create();
+ request->set_source(request, me->clone(me));
+ request->set_destination(request, other->clone(other));
+ request->set_exchange_type(request, INFORMATIONAL);
+ request->set_request(request, TRUE);
+ request->set_message_id(request, this->message_id);
+ request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
+ /* apply for caller */
+ *result = request;
+ /* store for retransmission */
+ this->message = request;
+
+ delete_payload = delete_payload_create(PROTO_IKE);
+ request->add_payload(request, (payload_t*)delete_payload);
+
+ /* transit to state SA_DELETING */
+ this->ike_sa->set_state(this->ike_sa, SA_DELETING);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of transaction_t.get_response.
+ */
+static status_t get_response(private_delete_ike_sa_t *this, message_t *request,
+ message_t **result, transaction_t **next)
+{
+ host_t *me, *other;
+ message_t *response;
+ iterator_t *payloads;
+ delete_payload_t *delete_request = NULL;
+ connection_t *connection;
+
+ /* check message type */
+ if (request->get_exchange_type(request) != INFORMATIONAL)
+ {
+ this->logger->log(this->logger, ERROR,
+ "INFORMATIONAL response of invalid type, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+
+ /* check if we already have built a response (retransmission)
+ * this only happens in special simultanous transaction cases,
+ * as we delete the IKE_SA after the response is sent. */
+ if (this->message)
+ {
+ *result = this->message;
+ return SUCCESS;
+ }
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+ me = connection->get_my_host(connection);
+ other = connection->get_other_host(connection);
+
+ /* set up response */
+ response = message_create();
+ response->set_source(response, me->clone(me));
+ response->set_destination(response, other->clone(other));
+ response->set_exchange_type(response, INFORMATIONAL);
+ response->set_request(response, FALSE);
+ response->set_message_id(response, this->message_id);
+ response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
+ this->message = response;
+ *result = response;
+
+ /* iterate over all payloads */
+ payloads = request->get_payload_iterator(request);
+ while (payloads->has_next(payloads))
+ {
+ payload_t *payload;
+ payloads->current(payloads, (void**)&payload);
+
+ switch (payload->get_type(payload))
+ {
+ case DELETE:
+ {
+ delete_request = (delete_payload_t *)payload;
+ break;
+ }
+ default:
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "ignoring payload %s (%d)",
+ mapping_find(payload_type_m, payload->get_type(payload)),
+ payload->get_type(payload));
+ break;
+ }
+ }
+ }
+ payloads->destroy(payloads);
+
+ if (delete_request &&
+ delete_request->get_protocol_id(delete_request) == PROTO_IKE)
+ {
+ this->logger->log(this->logger, CONTROL,
+ "DELETE request for IKE_SA received, deleting IKE_SA");
+ }
+ else
+ {
+ /* should not happen, as we preparsed this at transaction construction */
+ this->logger->log(this->logger, CONTROL,
+ "received a weird DELETE request for IKE_SA, deleting anyway");
+ }
+ if (this->ike_sa->get_state(this->ike_sa) == SA_DELETING)
+ {
+ /* if we are already deleting an IKE_SA, we do not destroy. We wait
+ * until we get the response for our initiated delete. */
+ return SUCCESS;
+ }
+ this->ike_sa->set_state(this->ike_sa, SA_DELETING);
+ return DESTROY_ME;
+}
+
+
+/**
+ * Implementation of transaction_t.conclude
+ */
+static status_t conclude(private_delete_ike_sa_t *this, message_t *response,
+ transaction_t **transaction)
+{
+ /* check message type */
+ if (response->get_exchange_type(response) != INFORMATIONAL)
+ {
+ this->logger->log(this->logger, ERROR,
+ "INFORMATIONAL response of invalid type, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+ /* this is only an acknowledge. We can't do anything here, but delete
+ * the IKE_SA. */
+ return DESTROY_ME;
+}
+
+/**
+ * implements transaction_t.destroy
+ */
+static void destroy(private_delete_ike_sa_t *this)
+{
+ if (this->message)
+ {
+ this->message->destroy(this->message);
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+delete_ike_sa_t *delete_ike_sa_create(ike_sa_t *ike_sa, u_int32_t message_id)
+{
+ private_delete_ike_sa_t *this = malloc_thing(private_delete_ike_sa_t);
+
+ /* transaction interface functions */
+ this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
+ this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
+ this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
+ this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
+ this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
+ this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+ this->message_id = message_id;
+ this->message = NULL;
+ this->requested = 0;
+ this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
+
+ return &this->public;
+}
diff --git a/src/charon/sa/transactions/delete_ike_sa.h b/src/charon/sa/transactions/delete_ike_sa.h
new file mode 100644
index 000000000..bb556acc7
--- /dev/null
+++ b/src/charon/sa/transactions/delete_ike_sa.h
@@ -0,0 +1,83 @@
+/**
+ * @file delete_ike_sa.h
+ *
+ * @brief Interface of transaction delete_ike_sa.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 DELETE_IKE_SA_H_
+#define DELETE_IKE_SA_H_
+
+#include <sa/ike_sa.h>
+#include <sa/transactions/transaction.h>
+
+
+typedef struct delete_ike_sa_t delete_ike_sa_t;
+
+/**
+ * @brief A transaction used to delete the IKE_SA.
+ *
+ * Notation as follows:
+ * Mx{D} means: Message, with message ID "x", containing a Delete payload
+ *
+ * The clarifcation Document says in 5.8, that a IKE_SA delete should not
+ * be acknowledged with the same delete. This only makes sense for CHILD_SAs,
+ * as they are paired. IKE_SAs are not, there is only one for both ends.
+ *
+ * Normal case:
+ * ----------------
+ * Mx{D} -->
+ * <-- Mx{}
+ * Delete request is sent, and we wait for the acknowledge.
+ *
+ * Special case 1:
+ * ---------------
+ * Mx{D} -->
+ * <-- My{D}
+ * My{} -->
+ * <-- Mx{}
+ * Both initate a delete at the same time. We ack the delete, but wait for
+ * our delete to be acknowledged.
+ *
+ * @b Constructors:
+ * - delete_ike_sa_create()
+ * - transaction_create() with the appropriate message
+ *
+ * @ingroup transactions
+ */
+struct delete_ike_sa_t {
+
+ /**
+ * The transaction_t interface.
+ */
+ transaction_t transaction;
+};
+
+/**
+ * @brief Create a new transaction which deletes the IKE_SA.
+ *
+ * @param ike_sa assigned IKE_SA
+ * @param message_id message ids used in this transaction
+ * @return created delete_ike_sa transaction
+ *
+ * @ingroup transactions
+ */
+delete_ike_sa_t *delete_ike_sa_create(ike_sa_t *ike_sa, u_int32_t message_id);
+
+#endif /* DELETE_IKE_SA_H_ */
diff --git a/src/charon/sa/transactions/ike_auth.c b/src/charon/sa/transactions/ike_auth.c
new file mode 100644
index 000000000..faf0ef6e5
--- /dev/null
+++ b/src/charon/sa/transactions/ike_auth.c
@@ -0,0 +1,1007 @@
+/**
+ * @file ike_auth.c
+ *
+ * @brief Implementation of ike_auth_t transaction.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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_auth.h"
+
+#include <string.h>
+
+#include <daemon.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/id_payload.h>
+#include <encoding/payloads/cert_payload.h>
+#include <encoding/payloads/certreq_payload.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/ts_payload.h>
+#include <sa/authenticator.h>
+#include <sa/child_sa.h>
+
+
+typedef struct private_ike_auth_t private_ike_auth_t;
+
+/**
+ * Private members of a ike_auth_t object..
+ */
+struct private_ike_auth_t {
+
+ /**
+ * Public methods and transaction_t interface.
+ */
+ ike_auth_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Message sent by our peer, if already generated
+ */
+ message_t *message;
+
+ /**
+ * Message ID this transaction uses
+ */
+ u_int32_t message_id;
+
+ /**
+ * Times we did send the request
+ */
+ u_int32_t requested;
+
+ /**
+ * initiator chosen nonce
+ */
+ chunk_t nonce_i;
+
+ /**
+ * responder chosen nonce
+ */
+ chunk_t nonce_r;
+
+ /**
+ * encoded request message of ike_sa_init transaction
+ */
+ chunk_t init_request;
+
+ /**
+ * encoded response message of ike_sa_init transaction
+ */
+ chunk_t init_response;
+
+ /**
+ * connection definition used
+ */
+ connection_t *connection;
+
+ /**
+ * policy definition used
+ */
+ policy_t *policy;
+
+ /**
+ * Negotiated proposal used for CHILD_SA
+ */
+ proposal_t *proposal;
+
+ /**
+ * Negotiated traffic selectors for initiator
+ */
+ linked_list_t *tsi;
+
+ /**
+ * Negotiated traffic selectors for responder
+ */
+ linked_list_t *tsr;
+
+ /**
+ * CHILD_SA created along with IKE_AUTH
+ */
+ child_sa_t *child_sa;
+
+ /**
+ * did other peer create a CHILD_SA?
+ */
+ bool build_child;
+
+ /**
+ * Assigned logger.
+ */
+ logger_t *logger;
+};
+
+/**
+ * Implementation of transaction_t.get_message_id.
+ */
+static u_int32_t get_message_id(private_ike_auth_t *this)
+{
+ return this->message_id;
+}
+
+/**
+ * Implementation of transaction_t.requested.
+ */
+static u_int32_t requested(private_ike_auth_t *this)
+{
+ return this->requested++;
+}
+
+/**
+ * Implementation of transaction_t.set_nonces.
+ */
+static void set_nonces(private_ike_auth_t *this, chunk_t nonce_i, chunk_t nonce_r)
+{
+ this->nonce_i = nonce_i;
+ this->nonce_r = nonce_r;
+}
+
+/**
+ * Implementation of transaction_t.set_init_messages.
+ */
+static void set_init_messages(private_ike_auth_t *this, chunk_t init_request, chunk_t init_response)
+{
+ this->init_request = init_request;
+ this->init_response = init_response;
+}
+
+/**
+ * Implementation of transaction_t.get_request.
+ */
+static status_t get_request(private_ike_auth_t *this, message_t **result)
+{
+ message_t *request;
+ host_t *me, *other;
+ identification_t *my_id, *other_id;
+ id_payload_t *my_id_payload;
+
+ /* check if we already have built a message (retransmission) */
+ if (this->message)
+ {
+ *result = this->message;
+ return SUCCESS;
+ }
+
+ this->connection = this->ike_sa->get_connection(this->ike_sa);
+ me = this->connection->get_my_host(this->connection);
+ other = this->connection->get_other_host(this->connection);
+ this->policy = this->ike_sa->get_policy(this->ike_sa);
+ my_id = this->policy->get_my_id(this->policy);
+ other_id = this->policy->get_other_id(this->policy);
+
+ /* build the request */
+ request = message_create();
+ request->set_source(request, me->clone(me));
+ request->set_destination(request, other->clone(other));
+ request->set_exchange_type(request, IKE_AUTH);
+ request->set_request(request, TRUE);
+ request->set_message_id(request, this->message_id);
+ request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
+ /* apply for caller */
+ *result = request;
+ /* store for retransmission */
+ this->message = request;
+
+ { /* build ID payload */
+ my_id_payload = id_payload_create_from_identification(TRUE, my_id);
+ request->add_payload(request, (payload_t*)my_id_payload);
+ }
+
+ { /* TODO: build certreq payload */
+
+ }
+
+ if (this->connection->get_cert_policy(this->connection) != CERT_NEVER_SEND)
+ { /* build certificate payload. TODO: Handle certreq from init_ike_sa. */
+ x509_t *cert;
+ cert_payload_t *cert_payload;
+
+ cert = charon->credentials->get_certificate(charon->credentials, my_id);
+ if (cert)
+ {
+ cert_payload = cert_payload_create_from_x509(cert);
+ request->add_payload(request, (payload_t*)cert_payload);
+ }
+ else
+ {
+ this->logger->log(this->logger, ERROR,
+ "could not find my certificate, certificate payload ommited");
+ }
+ }
+
+ { /* build IDr payload, if other_id defined */
+ id_payload_t *id_payload;
+ if (!other_id->contains_wildcards(other_id))
+ {
+ id_payload = id_payload_create_from_identification(FALSE, other_id);
+ request->add_payload(request, (payload_t*)id_payload);
+ }
+ }
+
+ { /* build auth payload */
+ authenticator_t *authenticator;
+ auth_payload_t *auth_payload;
+ status_t status;
+
+ authenticator = authenticator_create(this->ike_sa);
+ status = authenticator->compute_auth_data(authenticator, &auth_payload,
+ this->init_request, this->nonce_r, my_id_payload, TRUE);
+ authenticator->destroy(authenticator);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT,
+ "could not generate AUTH data, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+ request->add_payload(request, (payload_t*)auth_payload);
+ }
+
+ { /* build SA payload for CHILD_SA */
+ linked_list_t *proposal_list;
+ sa_payload_t *sa_payload;
+ u_int32_t soft_lifetime, hard_lifetime;
+
+ proposal_list = this->policy->get_proposals(this->policy);
+ soft_lifetime = this->policy->get_soft_lifetime(this->policy);
+ hard_lifetime = this->policy->get_hard_lifetime(this->policy);
+ this->child_sa = child_sa_create(0, me, other, soft_lifetime, hard_lifetime,
+ this->ike_sa->is_natt_enabled(this->ike_sa));
+ if (this->child_sa->alloc(this->child_sa, proposal_list) != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR,
+ "could not install CHILD_SA, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+ sa_payload = sa_payload_create_from_proposal_list(proposal_list);
+ request->add_payload(request, (payload_t*)sa_payload);
+ }
+
+ { /* build TSi payload */
+ linked_list_t *ts_list;
+ ts_payload_t *ts_payload;
+
+ ts_list = this->policy->get_my_traffic_selectors(this->policy);
+ ts_payload = ts_payload_create_from_traffic_selectors(TRUE, ts_list);
+
+ request->add_payload(request, (payload_t*)ts_payload);
+ }
+
+ { /* build TSr payload */
+ linked_list_t *ts_list;
+ ts_payload_t *ts_payload;
+
+ ts_list = this->policy->get_other_traffic_selectors(this->policy);
+ ts_payload = ts_payload_create_from_traffic_selectors(FALSE, ts_list);
+
+ request->add_payload(request, (payload_t*)ts_payload);
+ }
+
+ return SUCCESS;
+}
+
+/**
+ * Handle all kind of notifys
+ */
+static status_t process_notifys(private_ike_auth_t *this, notify_payload_t *notify_payload)
+{
+ notify_type_t notify_type = notify_payload->get_notify_type(notify_payload);
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s",
+ mapping_find(notify_type_m, notify_type));
+
+ switch (notify_type)
+ {
+ /* these notifys are not critical. no child_sa is built, but IKE stays alive */
+ case SINGLE_PAIR_REQUIRED:
+ {
+ this->logger->log(this->logger, AUDIT,
+ "received a SINGLE_PAIR_REQUIRED notify");
+ this->build_child = FALSE;
+ return SUCCESS;
+ }
+ case TS_UNACCEPTABLE:
+ {
+ this->logger->log(this->logger, CONTROL,
+ "received TS_UNACCEPTABLE notify");
+ this->build_child = FALSE;
+ return SUCCESS;
+ }
+ case NO_PROPOSAL_CHOSEN:
+ {
+ this->logger->log(this->logger, CONTROL,
+ "received NO_PROPOSAL_CHOSEN notify");
+ this->build_child = FALSE;
+ return SUCCESS;
+ }
+ default:
+ {
+ if (notify_type < 16383)
+ {
+ this->logger->log(this->logger, AUDIT,
+ "received %s notify error (%d), deleting IKE_SA",
+ mapping_find(notify_type_m, notify_type),
+ notify_type);
+ return DESTROY_ME;
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL,
+ "received %s notify (%d), ignored",
+ mapping_find(notify_type_m, notify_type),
+ notify_type);
+ return SUCCESS;
+ }
+ }
+ }
+}
+
+/**
+ * Build a notify message.
+ */
+static void build_notify(notify_type_t type, message_t *message, bool flush_message)
+{
+ notify_payload_t *notify;
+
+ if (flush_message)
+ {
+ payload_t *payload;
+ iterator_t *iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ payload->destroy(payload);
+ iterator->remove(iterator);
+ }
+ iterator->destroy(iterator);
+ }
+
+ notify = notify_payload_create();
+ notify->set_notify_type(notify, type);
+ message->add_payload(message, (payload_t*)notify);
+}
+
+/**
+ * Import a certificate from a cert payload
+ */
+static void import_certificate(private_ike_auth_t *this, cert_payload_t *cert_payload)
+{
+ bool found;
+ x509_t *cert;
+ cert_encoding_t encoding;
+
+ encoding = cert_payload->get_cert_encoding(cert_payload);
+ if (encoding != CERT_X509_SIGNATURE)
+ {
+ this->logger->log(this->logger, CONTROL,
+ "certificate payload %s not supported, ignored",
+ enum_name(&cert_encoding_names, encoding));
+ return;
+ }
+ cert = x509_create_from_chunk(cert_payload->get_data_clone(cert_payload));
+
+ if (charon->credentials->verify(charon->credentials, cert, &found))
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL1,
+ "end entity certificate is trusted");
+ if (found)
+ {
+ cert->destroy(cert);
+ }
+ else
+ {
+ cert = charon->credentials->add_end_certificate(charon->credentials, cert);
+ }
+ }
+ else
+ {
+ this->logger->log(this->logger, ERROR,
+ "end entity certificate is not trusted");
+ }
+}
+
+/**
+ * Install a CHILD_SA for usage
+ */
+static status_t install_child_sa(private_ike_auth_t *this, bool initiator)
+{
+ prf_plus_t *prf_plus;
+ chunk_t seed;
+ status_t status;
+
+ seed = chunk_alloc(this->nonce_i.len + this->nonce_r.len);
+ memcpy(seed.ptr, this->nonce_i.ptr, this->nonce_i.len);
+ memcpy(seed.ptr + this->nonce_i.len, this->nonce_r.ptr, this->nonce_r.len);
+ prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
+ chunk_free(&seed);
+
+ if (initiator)
+ {
+ status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
+ }
+ else
+ {
+ status = this->child_sa->add(this->child_sa, this->proposal, prf_plus);
+ }
+ prf_plus->destroy(prf_plus);
+ if (status != SUCCESS)
+ {
+ return DESTROY_ME;
+ }
+ if (initiator)
+ {
+ status = this->child_sa->add_policies(this->child_sa, this->tsi, this->tsr);
+ }
+ else
+ {
+ status = this->child_sa->add_policies(this->child_sa, this->tsr, this->tsi);
+ }
+ if (status != SUCCESS)
+ {
+ return DESTROY_ME;
+ }
+ /* add to IKE_SA, and remove from transaction */
+ this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
+ this->child_sa = NULL;
+ return SUCCESS;
+}
+
+/**
+ * destroy a list of traffic selectors
+ */
+static void destroy_ts_list(linked_list_t *list)
+{
+ if (list)
+ {
+ traffic_selector_t *ts;
+ while (list->remove_last(list, (void**)&ts) == SUCCESS)
+ {
+ ts->destroy(ts);
+ }
+ list->destroy(list);
+ }
+}
+
+/**
+ * Implementation of transaction_t.get_response.
+ */
+static status_t get_response(private_ike_auth_t *this, message_t *request,
+ message_t **result, transaction_t **next)
+{
+ host_t *me, *other;
+ identification_t *my_id, *other_id;
+ message_t *response;
+ status_t status;
+ iterator_t *payloads;
+ id_payload_t *idi_request = NULL;
+ id_payload_t *idr_request = NULL;
+ auth_payload_t *auth_request = NULL;
+ cert_payload_t *cert_request = NULL;
+ sa_payload_t *sa_request = NULL;
+ ts_payload_t *tsi_request = NULL;
+ ts_payload_t *tsr_request = NULL;
+ id_payload_t *idr_response;
+
+ /* check message type */
+ if (request->get_exchange_type(request) != IKE_AUTH)
+ {
+ this->logger->log(this->logger, ERROR,
+ "IKE_AUTH response of invalid type, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+
+ /* check if we already have built a response (retransmission) */
+ if (this->message)
+ {
+ *result = this->message;
+ return SUCCESS;
+ }
+
+ this->connection = this->ike_sa->get_connection(this->ike_sa);
+ me = this->connection->get_my_host(this->connection);
+ other = this->connection->get_other_host(this->connection);
+
+ /* set up response */
+ response = message_create();
+ response->set_source(response, me->clone(me));
+ response->set_destination(response, other->clone(other));
+ response->set_exchange_type(response, IKE_AUTH);
+ response->set_request(response, FALSE);
+ response->set_message_id(response, this->message_id);
+ response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
+ this->message = response;
+ *result = response;
+
+ /* Iterate over all payloads. */
+ payloads = request->get_payload_iterator(request);
+ while (payloads->has_next(payloads))
+ {
+ payload_t *payload;
+ payloads->current(payloads, (void**)&payload);
+ switch (payload->get_type(payload))
+ {
+ case ID_INITIATOR:
+ idi_request = (id_payload_t*)payload;
+ break;
+ case ID_RESPONDER:
+ idr_request = (id_payload_t*)payload;
+ break;
+ case AUTHENTICATION:
+ auth_request = (auth_payload_t*)payload;
+ break;
+ case CERTIFICATE:
+ cert_request = (cert_payload_t*)payload;
+ break;
+ case SECURITY_ASSOCIATION:
+ sa_request = (sa_payload_t*)payload;
+ break;
+ case TRAFFIC_SELECTOR_INITIATOR:
+ tsi_request = (ts_payload_t*)payload;
+ break;
+ case TRAFFIC_SELECTOR_RESPONDER:
+ tsr_request = (ts_payload_t*)payload;
+ break;
+ case NOTIFY:
+ {
+ status = process_notifys(this, (notify_payload_t*)payload);
+ if (status == FAILED)
+ {
+ payloads->destroy(payloads);
+ /* we return SUCCESS, returned FAILED means do next transaction */
+ return SUCCESS;
+ }
+ if (status == DESTROY_ME)
+ {
+ payloads->destroy(payloads);
+ return DESTROY_ME;
+ }
+ break;
+ }
+ default:
+ {
+ this->logger->log(this->logger, ERROR, "ignoring %s payload (%d)",
+ mapping_find(payload_type_m, payload->get_type(payload)),
+ payload->get_type(payload));
+ break;
+ }
+ }
+ }
+ payloads->destroy(payloads);
+
+ /* check if we have all payloads */
+ if (!(idi_request && auth_request && sa_request && tsi_request && tsr_request))
+ {
+ build_notify(INVALID_SYNTAX, response, TRUE);
+ this->logger->log(this->logger, AUDIT,
+ "request message incomplete, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+
+ { /* process ID payload */
+ other_id = idi_request->get_identification(idi_request);
+ if (idr_request)
+ {
+ my_id = idr_request->get_identification(idr_request);
+ }
+ else
+ {
+ my_id = identification_create_from_encoding(ID_ANY, CHUNK_INITIALIZER);
+ }
+
+ /* get policy from store */
+ this->policy = charon->policies->get_policy_by_ids(charon->policies, my_id, other_id);
+ if (this->policy == NULL)
+ {
+ this->logger->log(this->logger, AUDIT,
+ "we don't have a policy for IDs %s - %s, deleting IKE_SA",
+ my_id->get_string(my_id), other_id->get_string(other_id));
+ my_id->destroy(my_id);
+ other_id->destroy(other_id);
+ build_notify(AUTHENTICATION_FAILED, response, TRUE);
+ return DESTROY_ME;
+ }
+ my_id->destroy(my_id);
+ other_id->destroy(other_id);
+
+ /* get my id from policy, which must contain a fully qualified valid id */
+ my_id = this->policy->get_my_id(this->policy);
+
+ /* update others traffic selectors with actually used address */
+ this->policy->update_my_ts(this->policy, me);
+ this->policy->update_other_ts(this->policy, other);
+
+ this->ike_sa->set_policy(this->ike_sa, this->policy);
+ idr_response = id_payload_create_from_identification(FALSE, my_id);
+ response->add_payload(response, (payload_t*)idr_response);
+ }
+
+ if (this->connection->get_cert_policy(this->connection) != CERT_NEVER_SEND)
+ { /* build certificate payload */
+ x509_t *cert;
+ cert_payload_t *cert_payload;
+
+ cert = charon->credentials->get_certificate(charon->credentials, my_id);
+ if (cert == NULL)
+ {
+ this->logger->log(this->logger, ERROR,
+ "could not find my certificate, cert payload ommited");
+ }
+ cert_payload = cert_payload_create_from_x509(cert);
+ response->add_payload(response, (payload_t *)cert_payload);
+ }
+
+ if (cert_request)
+ { /* process certificate payload */
+ import_certificate(this, cert_request);
+ }
+
+ { /* process auth payload */
+ authenticator_t *authenticator;
+ auth_payload_t *auth_response;
+ status_t status;
+
+ authenticator = authenticator_create(this->ike_sa);
+ status = authenticator->verify_auth_data(authenticator, auth_request,
+ this->init_request,
+ this->nonce_r, idi_request,
+ TRUE);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT,
+ "authentication failed, deleting IKE_SA");
+ build_notify(AUTHENTICATION_FAILED, response, TRUE);
+ authenticator->destroy(authenticator);
+ return DESTROY_ME;
+ }
+ status = authenticator->compute_auth_data(authenticator, &auth_response,
+ this->init_response,
+ this->nonce_i, idr_response,
+ FALSE);
+ authenticator->destroy(authenticator);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT,
+ "authentication data generation failed, deleting IKE_SA");
+ build_notify(AUTHENTICATION_FAILED, response, TRUE);
+ return DESTROY_ME;
+ }
+ response->add_payload(response, (payload_t*)auth_response);
+ }
+
+ { /* process traffic selectors for other */
+ linked_list_t *ts_received = tsi_request->get_traffic_selectors(tsi_request);
+ this->tsi = this->policy->select_other_traffic_selectors(this->policy, ts_received);
+ destroy_ts_list(ts_received);
+ }
+
+ { /* process traffic selectors for us */
+ linked_list_t *ts_received = ts_received = tsr_request->get_traffic_selectors(tsr_request);
+ this->tsr = this->policy->select_my_traffic_selectors(this->policy, ts_received);
+ destroy_ts_list(ts_received);
+ }
+
+ { /* process SA payload */
+ proposal_t *proposal;
+ linked_list_t *proposal_list;
+ sa_payload_t *sa_response;
+ ts_payload_t *ts_response;
+ bool use_natt;
+ u_int32_t soft_lifetime, hard_lifetime;
+
+ /* prepare reply */
+ sa_response = sa_payload_create();
+
+ /* get proposals from request, and select one with ours */
+ proposal_list = sa_request->get_proposals(sa_request);
+ this->logger->log(this->logger, CONTROL|LEVEL1, "selecting proposals:");
+ this->proposal = this->policy->select_proposal(this->policy, proposal_list);
+ /* list is not needed anymore */
+ while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
+ {
+ proposal->destroy(proposal);
+ }
+ proposal_list->destroy(proposal_list);
+
+ /* do we have a proposal? */
+ if (this->proposal == NULL)
+ {
+ this->logger->log(this->logger, AUDIT,
+ "CHILD_SA proposals unacceptable, adding NO_PROPOSAL_CHOSEN notify");
+ build_notify(NO_PROPOSAL_CHOSEN, response, FALSE);
+ }
+ /* do we have traffic selectors? */
+ else if (this->tsi->get_count(this->tsi) == 0 || this->tsr->get_count(this->tsr) == 0)
+ {
+ this->logger->log(this->logger, AUDIT,
+ "CHILD_SA traffic selectors unacceptable, adding TS_UNACCEPTABLE notify");
+ build_notify(TS_UNACCEPTABLE, response, FALSE);
+ }
+ else
+ {
+ /* create child sa */
+ soft_lifetime = this->policy->get_soft_lifetime(this->policy);
+ hard_lifetime = this->policy->get_hard_lifetime(this->policy);
+ use_natt = this->ike_sa->is_natt_enabled(this->ike_sa);
+ this->child_sa = child_sa_create(0, me, other,
+ soft_lifetime, hard_lifetime,
+ use_natt);
+ if (install_child_sa(this, FALSE) != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR,
+ "installing CHILD_SA failed, adding NO_PROPOSAL_CHOSEN notify");
+ build_notify(NO_PROPOSAL_CHOSEN, response, FALSE);
+ }
+ /* add proposal to sa payload */
+ sa_response->add_proposal(sa_response, this->proposal);
+ }
+ response->add_payload(response, (payload_t*)sa_response);
+
+ /* add ts payload after sa payload */
+ ts_response = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
+ response->add_payload(response, (payload_t*)ts_response);
+ ts_response = ts_payload_create_from_traffic_selectors(FALSE, this->tsr);
+ response->add_payload(response, (payload_t*)ts_response);
+ }
+ /* set established state */
+ this->ike_sa->set_state(this->ike_sa, SA_ESTABLISHED);
+ return SUCCESS;
+}
+
+
+/**
+ * Implementation of transaction_t.conclude
+ */
+static status_t conclude(private_ike_auth_t *this, message_t *response,
+ transaction_t **transaction)
+{
+ iterator_t *payloads;
+ host_t *me, *other;
+ identification_t *other_id;
+ ts_payload_t *tsi_payload = NULL;
+ ts_payload_t *tsr_payload = NULL;
+ id_payload_t *idr_payload = NULL;
+ cert_payload_t *cert_payload = NULL;
+ auth_payload_t *auth_payload = NULL;
+ sa_payload_t *sa_payload = NULL;
+ status_t status;
+
+ /* check message type */
+ if (response->get_exchange_type(response) != IKE_AUTH)
+ {
+ this->logger->log(this->logger, ERROR,
+ "IKE_AUTH response of invalid type, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+
+ me = this->connection->get_my_host(this->connection);
+ other = this->connection->get_other_host(this->connection);
+
+ /* Iterate over all payloads to collect them */
+ payloads = response->get_payload_iterator(response);
+ while (payloads->has_next(payloads))
+ {
+ payload_t *payload;
+ payloads->current(payloads, (void**)&payload);
+
+ switch (payload->get_type(payload))
+ {
+ case ID_RESPONDER:
+ idr_payload = (id_payload_t*)payload;
+ break;
+ case AUTHENTICATION:
+ auth_payload = (auth_payload_t*)payload;
+ break;
+ case CERTIFICATE:
+ cert_payload = (cert_payload_t*)payload;
+ break;
+ case SECURITY_ASSOCIATION:
+ sa_payload = (sa_payload_t*)payload;
+ break;
+ case TRAFFIC_SELECTOR_INITIATOR:
+ tsi_payload = (ts_payload_t*)payload;
+ break;
+ case TRAFFIC_SELECTOR_RESPONDER:
+ tsr_payload = (ts_payload_t*)payload;
+ break;
+ case NOTIFY:
+ {
+ status = process_notifys(this, (notify_payload_t*)payload);
+ if (status == FAILED)
+ {
+ payloads->destroy(payloads);
+ /* we return SUCCESS, returned FAILED means do next transaction */
+ return SUCCESS;
+ }
+ if (status == DESTROY_ME)
+ {
+ payloads->destroy(payloads);
+ return status;
+ }
+ break;
+ }
+ default:
+ {
+ this->logger->log(this->logger, CONTROL, "ignoring payload %s (%d)",
+ mapping_find(payload_type_m, payload->get_type(payload)),
+ payload->get_type(payload));
+ break;
+ }
+ }
+ }
+ payloads->destroy(payloads);
+
+ if (!(idr_payload && auth_payload && sa_payload && tsi_payload && tsr_payload))
+ {
+ this->logger->log(this->logger, AUDIT, "response message incomplete, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+
+ { /* process idr payload */
+ identification_t *configured_other_id;
+
+ other_id = idr_payload->get_identification(idr_payload);
+ configured_other_id = this->policy->get_other_id(this->policy);
+
+ if (!other_id->belongs_to(other_id, configured_other_id))
+ {
+ other_id->destroy(other_id);
+ this->logger->log(this->logger, AUDIT,
+ "other peer uses unacceptable ID (%s, excepted %s), deleting IKE_SA",
+ other_id->get_string(other_id),
+ configured_other_id->get_string(configured_other_id));
+ return DESTROY_ME;
+ }
+
+ this->policy->update_other_id(this->policy, other_id);
+ }
+
+ if (cert_payload)
+ { /* process cert payload */
+ import_certificate(this, cert_payload);
+ }
+
+ { /* authenticate peer */
+ authenticator_t *authenticator;
+ status_t status;
+
+ authenticator = authenticator_create(this->ike_sa);
+ status = authenticator->verify_auth_data(authenticator, auth_payload,
+ this->init_response,
+ this->nonce_i, idr_payload,
+ FALSE);
+ authenticator->destroy(authenticator);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "authentication failed, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+ }
+
+ { /* process traffic selectors for us */
+ linked_list_t *ts_received = tsi_payload->get_traffic_selectors(tsi_payload);
+ this->tsi = this->policy->select_my_traffic_selectors(this->policy, ts_received);
+ destroy_ts_list(ts_received);
+ }
+
+ { /* process traffic selectors for other */
+ linked_list_t *ts_received = tsr_payload->get_traffic_selectors(tsr_payload);
+ this->tsr = this->policy->select_other_traffic_selectors(this->policy, ts_received);
+ destroy_ts_list(ts_received);
+ }
+
+ { /* process sa payload */
+ proposal_t *proposal;
+ linked_list_t *proposal_list;
+
+ proposal_list = sa_payload->get_proposals(sa_payload);
+ /* we have to re-check here if other's selection is valid */
+ this->proposal = this->policy->select_proposal(this->policy, proposal_list);
+ /* list not needed anymore */
+ while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
+ {
+ proposal->destroy(proposal);
+ }
+ proposal_list->destroy(proposal_list);
+
+ /* everything fine to create CHILD? */
+ if (this->proposal == NULL ||
+ this->tsi->get_count(this->tsi) == 0 ||
+ this->tsr->get_count(this->tsr) == 0 ||
+ !this->build_child)
+ {
+ this->logger->log(this->logger, AUDIT,
+ "CHILD_SA creation failed");
+ }
+ else
+ {
+ if (install_child_sa(this, TRUE) != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR,
+ "installing CHILD_SA failed, no CHILD_SA built");
+ }
+ }
+ }
+ /* set new state */
+ this->ike_sa->set_state(this->ike_sa, SA_ESTABLISHED);
+ return SUCCESS;
+}
+
+/**
+ * implements transaction_t.destroy
+ */
+static void destroy(private_ike_auth_t *this)
+{
+ if (this->message)
+ {
+ this->message->destroy(this->message);
+ }
+ if (this->proposal)
+ {
+ this->proposal->destroy(this->proposal);
+ }
+ if (this->child_sa)
+ {
+ this->child_sa->destroy(this->child_sa);
+ }
+ destroy_ts_list(this->tsi);
+ destroy_ts_list(this->tsr);
+ chunk_free(&this->nonce_i);
+ chunk_free(&this->nonce_r);
+ chunk_free(&this->init_request);
+ chunk_free(&this->init_response);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, u_int32_t message_id)
+{
+ private_ike_auth_t *this = malloc_thing(private_ike_auth_t);
+
+ /* transaction interface functions */
+ this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
+ this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
+ this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
+ this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
+ this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
+ this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
+
+ /* public functions */
+ this->public.set_nonces = (void(*)(ike_auth_t*,chunk_t,chunk_t))set_nonces;
+ this->public.set_init_messages = (void(*)(ike_auth_t*,chunk_t,chunk_t))set_init_messages;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+ this->message_id = message_id;
+ this->message = NULL;
+ this->requested = 0;
+ this->nonce_i = CHUNK_INITIALIZER;
+ this->nonce_r = CHUNK_INITIALIZER;
+ this->init_request = CHUNK_INITIALIZER;
+ this->init_response = CHUNK_INITIALIZER;
+ this->child_sa = NULL;
+ this->proposal = NULL;
+ this->tsi = NULL;
+ this->tsr = NULL;
+ this->build_child = TRUE;
+ this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
+
+ return &this->public;
+}
diff --git a/src/charon/sa/transactions/ike_auth.h b/src/charon/sa/transactions/ike_auth.h
new file mode 100644
index 000000000..1404b785e
--- /dev/null
+++ b/src/charon/sa/transactions/ike_auth.h
@@ -0,0 +1,86 @@
+/**
+ * @file ike_auth.h
+ *
+ * @brief Interface of transaction ike_auth.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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_AUTH_H_
+#define IKE_AUTH_H_
+
+#include <sa/ike_sa.h>
+#include <sa/transactions/transaction.h>
+
+
+typedef struct ike_auth_t ike_auth_t;
+
+/**
+ * @brief A transaction for the second message exchange to authenticate an IKE_SA.
+ *
+ * The second transaction is encrypted and authenticates the peers. It also
+ * sets up a first CHILD_SA.
+ *
+ * @b Constructors:
+ * - ike_auth_create()
+ * - transaction_create() with the appropriate message
+ *
+ * @ingroup transactions
+ */
+struct ike_auth_t {
+
+ /**
+ * The transaction_t interface.
+ */
+ transaction_t transaction;
+
+ /**
+ * @brief Set the nonces used in the previous ike_sa_init transaction.
+ *
+ * The nonces are used to create the authentication data.
+ *
+ * @param this calling object
+ * @param nonce_i initiator chosen nonce
+ * @param nonce_r responder chosen nonce
+ */
+ void (*set_nonces) (ike_auth_t* this, chunk_t nonce_i, chunk_t nonce_r);
+
+ /**
+ * @brief Set the messages used in the previous ike_sa_init transaction.
+ *
+ * The messages are used to create the authentication data.
+ *
+ * @param this calling object
+ * @param request encoded request message as a chunk
+ * @param response encoded response message as a chunk
+ */
+ void (*set_init_messages) (ike_auth_t* this, chunk_t request, chunk_t response);
+};
+
+/**
+ * @brief Create a new transaction which processes IKE_AUTH exchanges.
+ *
+ * @param ike_sa assigned IKE_SA
+ * @param message_id message ids used in this transaction
+ * @return created ike_auth transaction
+ *
+ * @ingroup transactions
+ */
+ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, u_int32_t message_id);
+
+#endif /* IKE_AUTH_H_ */
diff --git a/src/charon/sa/transactions/ike_sa_init.c b/src/charon/sa/transactions/ike_sa_init.c
new file mode 100644
index 000000000..ce6d045ac
--- /dev/null
+++ b/src/charon/sa/transactions/ike_sa_init.c
@@ -0,0 +1,1079 @@
+/**
+ * @file ike_sa_init.c
+ *
+ * @brief Implementation of ike_sa_init_t transaction.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.h"
+
+#include <string.h>
+
+#include <daemon.h>
+#include <crypto/diffie_hellman.h>
+#include <crypto/hashers/hasher.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/ke_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <sa/transactions/ike_auth.h>
+#include <queues/jobs/delete_half_open_ike_sa_job.h>
+
+
+typedef struct private_ike_sa_init_t private_ike_sa_init_t;
+
+/**
+ * Private members of a ike_sa_init_t object..
+ */
+struct private_ike_sa_init_t {
+
+ /**
+ * Public methods and transaction_t interface.
+ */
+ ike_sa_init_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Message sent by our peer, if already generated
+ */
+ message_t *message;
+
+ /**
+ * Message ID this transaction uses
+ */
+ u_int32_t message_id;
+
+ /**
+ * Times we did send the request
+ */
+ u_int32_t requested;
+
+ /**
+ * Next transaction followed to this one. May be IKE_AUTH,
+ * or a IKE_SA_INIT retry
+ */
+ transaction_t **next;
+
+ /**
+ * Diffie hellman object used to generate public DH value.
+ */
+ diffie_hellman_t *diffie_hellman;
+
+ /**
+ * initiator chosen nonce
+ */
+ chunk_t nonce_i;
+
+ /**
+ * responder chosen nonce
+ */
+ chunk_t nonce_r;
+
+ /**
+ * connection definition used
+ */
+ connection_t *connection;
+
+ /**
+ * Negotiated proposal used for IKE_SA
+ */
+ proposal_t *proposal;
+
+ /**
+ * Randomizer to generate nonces
+ */
+ randomizer_t *randomizer;
+
+ /**
+ * Hasher used to build NAT detection hashes
+ */
+ hasher_t *nat_hasher;
+
+ /**
+ * Precomputed NAT hash for source address
+ */
+ chunk_t natd_src_hash;
+
+ /**
+ * Precomputed NAT hash for destination address
+ */
+ chunk_t natd_dst_hash;
+
+ /**
+ * Did we process any NAT detection notifys for a source address?
+ */
+ bool natd_src_seen;
+
+ /**
+ * Did we process any NAT detection notifys for a destination address?
+ */
+ bool natd_dst_seen;
+
+ /**
+ * Have we found a matching source address NAT hash?
+ */
+ bool natd_src_matched;
+
+ /**
+ * Have we found a matching destination address NAT hash?
+ */
+ bool natd_dst_matched;
+
+ /**
+ * Assigned logger.
+ */
+ logger_t *logger;
+};
+
+/**
+ * Implementation of ike_sa_init_t.use_dh_group.
+ */
+static bool use_dh_group(private_ike_sa_init_t *this, diffie_hellman_group_t dh_group)
+{
+ this->connection = this->ike_sa->get_connection(this->ike_sa);
+
+ if (this->connection->check_dh_group(this->connection, dh_group))
+ {
+ this->diffie_hellman = diffie_hellman_create(dh_group);
+ if (this->diffie_hellman)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Implementation of transaction_t.get_message_id.
+ */
+static u_int32_t get_message_id(private_ike_sa_init_t *this)
+{
+ return this->message_id;
+}
+
+/**
+ * Implementation of transaction_t.requested.
+ */
+static u_int32_t requested(private_ike_sa_init_t *this)
+{
+ return this->requested++;
+}
+
+/**
+ * Build NAT detection hash for a host
+ */
+static chunk_t generate_natd_hash(private_ike_sa_init_t *this,
+ ike_sa_id_t * ike_sa_id, host_t *host)
+{
+ chunk_t natd_string;
+ chunk_t natd_hash;
+ u_int8_t *p;
+ u_int64_t spi_i, spi_r;
+ char buf[512];
+
+ spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
+ spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
+
+ switch (host->get_family(host))
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in* sai;
+ natd_string = chunk_alloc(sizeof(spi_i) + sizeof(spi_r) +
+ sizeof(sai->sin_addr.s_addr) +
+ sizeof(sai->sin_port));
+ sai = (struct sockaddr_in*)host->get_sockaddr(host);
+ p = natd_string.ptr;
+ *(u_int64_t*)p = spi_i; p += sizeof(spi_i);
+ *(u_int64_t*)p = spi_r; p += sizeof(spi_r);
+ *(u_int32_t*)p = sai->sin_addr.s_addr; p += sizeof(sai->sin_addr.s_addr);
+ *(u_int16_t*)p = sai->sin_port; p += sizeof(sai->sin_port);
+ break;
+ }
+ case AF_INET6:
+ default:
+ /* TODO: Add IPv6 support */
+ natd_string = CHUNK_INITIALIZER;
+ }
+
+ this->nat_hasher->allocate_hash(this->nat_hasher, natd_string, &natd_hash);
+
+ sprintf(buf, "natd_hash(%016llx %016llx %s:%d) == SHA1(", spi_i, spi_r,
+ host->get_address(host), host->get_port(host));
+ chunk_to_hex(buf + strlen(buf), sizeof(buf) - strlen(buf), natd_string);
+ strcat(buf, ") == ");
+ chunk_to_hex(buf + strlen(buf), sizeof(buf) - strlen(buf), natd_hash);
+ this->logger->log(this->logger, CONTROL|LEVEL3, buf);
+
+ chunk_free(&natd_string);
+ return natd_hash;
+}
+
+/**
+ * Build a NAT detection notify payload.
+ */
+static notify_payload_t *build_natd_payload(private_ike_sa_init_t *this,
+ notify_type_t type, host_t *host)
+{
+ chunk_t hash;
+ notify_payload_t *notify;
+ ike_sa_id_t *ike_sa_id;
+
+ ike_sa_id = this->ike_sa->get_id(this->ike_sa);
+ notify = notify_payload_create();
+ notify->set_notify_type(notify, type);
+ hash = generate_natd_hash(this, ike_sa_id, host);
+ notify->set_notification_data(notify, hash);
+ chunk_free(&hash);
+
+ return notify;
+}
+
+/**
+ * Implementation of transaction_t.get_request.
+ */
+static status_t get_request(private_ike_sa_init_t *this, message_t **result)
+{
+ message_t *request;
+ host_t *me, *other;
+
+ /* check if we already have built a message (retransmission) */
+ if (this->message)
+ {
+ *result = this->message;
+ return SUCCESS;
+ }
+
+ this->connection = this->ike_sa->get_connection(this->ike_sa);
+ me = this->connection->get_my_host(this->connection);
+ other = this->connection->get_other_host(this->connection);
+
+ /* build the request */
+ request = message_create();
+ request->set_source(request, me->clone(me));
+ request->set_destination(request, other->clone(other));
+ request->set_exchange_type(request, IKE_SA_INIT);
+ request->set_request(request, TRUE);
+ request->set_message_id(request, this->message_id);
+ request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
+ /* apply for caller */
+ *result = request;
+ /* store for retransmission */
+ this->message = request;
+
+ /* if the DH group is set via use_dh_group(), we already have a DH object */
+ if (!this->diffie_hellman)
+ {
+ diffie_hellman_group_t dh_group;
+
+ dh_group = this->connection->get_dh_group(this->connection);
+ this->diffie_hellman = diffie_hellman_create(dh_group);
+ if (this->diffie_hellman == NULL)
+ {
+ this->logger->log(this->logger, AUDIT,
+ "DH group %s (%d) not supported, aborting",
+ mapping_find(diffie_hellman_group_m, dh_group), dh_group);
+ return DESTROY_ME;
+ }
+ }
+
+ { /* build the SA payload from proposals */
+ sa_payload_t *sa_payload;
+ linked_list_t *proposal_list;
+
+ proposal_list = this->connection->get_proposals(this->connection);
+ sa_payload = sa_payload_create_from_proposal_list(proposal_list);
+
+ request->add_payload(request, (payload_t*)sa_payload);
+ }
+
+ { /* build the KE payload from the DH object */
+ ke_payload_t *ke_payload;
+
+ ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
+
+ request->add_payload(request, (payload_t*)ke_payload);
+ }
+
+ { /* build the NONCE payload for us (initiator) */
+ nonce_payload_t *nonce_payload;
+ randomizer_t *randomizer;
+
+ randomizer = randomizer_create();
+ if (randomizer->allocate_pseudo_random_bytes(randomizer,
+ NONCE_SIZE, &this->nonce_i) != SUCCESS)
+ {
+ randomizer->destroy(randomizer);
+ request->destroy(request);
+ return DESTROY_ME;
+ }
+ randomizer->destroy(randomizer);
+ nonce_payload = nonce_payload_create();
+ nonce_payload->set_nonce(nonce_payload, this->nonce_i);
+
+ request->add_payload(request, (payload_t*)nonce_payload);
+ }
+
+ { /* build NAT_DETECTION notifys */
+ notify_payload_t *notify;
+ iterator_t *iterator;
+ host_t *host;
+
+ /* N(NAT_DETECTION_SOURCE_IP)+ */
+ iterator = charon->interfaces->create_address_iterator(charon->interfaces);
+ while (iterator->iterate(iterator, (void**)&host))
+ {
+ notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
+ request->add_payload(request, (payload_t*)notify);
+ }
+ iterator->destroy(iterator);
+
+ /* N(NAT_DETECTION_DESTINATION_IP) */
+ notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other);
+ request->add_payload(request, (payload_t*)notify);
+ }
+
+ /* set new state */
+ this->ike_sa->set_state(this->ike_sa, SA_CONNECTING);
+ return SUCCESS;
+}
+
+/**
+ * Handle all kind of notifys
+ */
+static status_t process_notifys(private_ike_sa_init_t *this, notify_payload_t *notify_payload)
+{
+ chunk_t notification_data;
+ notify_type_t notify_type = notify_payload->get_notify_type(notify_payload);
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s",
+ mapping_find(notify_type_m, notify_type));
+
+ switch (notify_type)
+ {
+ case NO_PROPOSAL_CHOSEN:
+ {
+ this->logger->log(this->logger, AUDIT,
+ "received a NO_PROPOSAL_CHOSEN notify, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+ case INVALID_MAJOR_VERSION:
+ {
+ this->logger->log(this->logger, AUDIT,
+ "received a INVALID_MAJOR_VERSION notify, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+ case INVALID_KE_PAYLOAD:
+ {
+ chunk_t notify_data;
+ diffie_hellman_group_t dh_group, old_dh_group;
+ ike_sa_init_t *retry;
+
+ old_dh_group = this->connection->get_dh_group(this->connection);
+ notify_data = notify_payload->get_notification_data(notify_payload);
+ dh_group = ntohs(*((u_int16_t*)notify_data.ptr));
+
+ this->logger->log(this->logger, AUDIT,
+ "peer didn't accept DH group %s, it requested %s",
+ mapping_find(diffie_hellman_group_m, old_dh_group),
+ mapping_find(diffie_hellman_group_m, dh_group));
+ if (!this->connection->check_dh_group(this->connection, dh_group))
+ {
+ this->logger->log(this->logger, AUDIT,
+ "requested DH group not acceptable, aborting");
+ return DESTROY_ME;
+ }
+ retry = ike_sa_init_create(this->ike_sa, 0);
+ retry->use_dh_group(retry, dh_group);
+ *this->next = (transaction_t*)retry;
+ return FAILED;
+ }
+ case NAT_DETECTION_DESTINATION_IP:
+ {
+ this->natd_dst_seen = TRUE;
+ if (this->natd_dst_matched)
+ {
+ return SUCCESS;
+ }
+ notification_data = notify_payload->get_notification_data(notify_payload);
+ if (chunk_equals(notification_data, this->natd_dst_hash))
+ {
+ this->natd_dst_matched = TRUE;
+ this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D dst hash match");
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D dst hash mismatch");
+ }
+ return SUCCESS;
+ }
+ case NAT_DETECTION_SOURCE_IP:
+ {
+ this->natd_src_seen = TRUE;;
+ if (this->natd_src_matched)
+ {
+ return SUCCESS;
+ }
+ notification_data = notify_payload->get_notification_data(notify_payload);
+ if (chunk_equals(notification_data, this->natd_src_hash))
+ {
+ this->natd_src_matched = TRUE;
+ this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D src hash match");
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D src hash mismatch");
+ }
+ return SUCCESS;
+ }
+ default:
+ {
+ if (notify_type < 16383)
+ {
+ this->logger->log(this->logger, AUDIT,
+ "received %s notify error (%d), deleting IKE_SA",
+ mapping_find(notify_type_m, notify_type),
+ notify_type);
+ return DESTROY_ME;
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL,
+ "received %s notify (%d), ignored",
+ mapping_find(notify_type_m, notify_type),
+ notify_type);
+ return SUCCESS;
+ }
+ }
+ }
+}
+
+/**
+ * Implementation of transaction_t.get_response.
+ */
+static status_t get_response(private_ike_sa_init_t *this,
+ message_t *request, message_t **result,
+ transaction_t **next)
+{
+ host_t *me, *other;
+ message_t *response;
+ status_t status;
+ iterator_t *payloads;
+ sa_payload_t *sa_request = NULL;
+ ke_payload_t *ke_request = NULL;
+ nonce_payload_t *nonce_request = NULL;
+ ike_sa_id_t *ike_sa_id;
+ u_int32_t timeout;
+
+ /* check message type */
+ if (request->get_exchange_type(request) != IKE_SA_INIT)
+ {
+ this->logger->log(this->logger, ERROR,
+ "IKE_SA_INIT request of invalid type, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+
+ /* check if we already have built a response (retransmission) */
+ if (this->message)
+ {
+ *result = this->message;
+ return SUCCESS;
+ }
+
+ me = request->get_destination(request);
+ other = request->get_source(request);
+
+ /* set up response */
+ response = message_create();
+ response->set_source(response, me->clone(me));
+ response->set_destination(response, other->clone(other));
+ response->set_exchange_type(response, IKE_SA_INIT);
+ response->set_request(response, FALSE);
+ response->set_message_id(response, this->message_id);
+ response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
+ this->message = response;
+ *result = response;
+
+ /* this is the first message to process, find a connection for IKE_SA */
+ this->connection = charon->connections->get_connection_by_hosts(
+ charon->connections, me, other);
+ if (this->connection == NULL)
+ {
+ notify_payload_t *notify = notify_payload_create();
+ notify->set_notify_type(notify, NO_PROPOSAL_CHOSEN);
+ response->add_payload(response, (payload_t*)notify);
+
+ this->logger->log(this->logger, AUDIT,
+ "no connection for hosts %s...%s found, deleting IKE_SA",
+ me->get_address(me), other->get_address(other));
+ return DESTROY_ME;
+ }
+ this->ike_sa->set_connection(this->ike_sa, this->connection);
+
+ /* Precompute NAT-D hashes for incoming NAT notify comparison */
+ ike_sa_id = request->get_ike_sa_id(request);
+ this->natd_dst_hash = generate_natd_hash(this, ike_sa_id, me);
+ this->natd_src_hash = generate_natd_hash(this, ike_sa_id, other);
+
+ /* Iterate over all payloads. */
+ payloads = request->get_payload_iterator(request);
+ while (payloads->has_next(payloads))
+ {
+ payload_t *payload;
+ payloads->current(payloads, (void**)&payload);
+ switch (payload->get_type(payload))
+ {
+ case SECURITY_ASSOCIATION:
+ sa_request = (sa_payload_t*)payload;
+ break;
+ case KEY_EXCHANGE:
+ ke_request = (ke_payload_t*)payload;
+ break;
+ case NONCE:
+ nonce_request = (nonce_payload_t*)payload;
+ break;
+ case NOTIFY:
+ {
+ status = process_notifys(this, (notify_payload_t*)payload);
+ if (status == FAILED)
+ {
+ payloads->destroy(payloads);
+ /* we return SUCCESS, returned FAILED means do next transaction */
+ return SUCCESS;
+ }
+ if (status == DESTROY_ME)
+ {
+ payloads->destroy(payloads);
+ return DESTROY_ME;
+ }
+ break;
+ }
+ default:
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1,
+ "ignoring %s payload (%d)",
+ mapping_find(payload_type_m, payload->get_type(payload)),
+ payload->get_type(payload));
+ break;
+ }
+ }
+ }
+ payloads->destroy(payloads);
+
+ /* check if we have all payloads */
+ if (!(sa_request && ke_request && nonce_request))
+ {
+ notify_payload_t *notify = notify_payload_create();
+ notify->set_notify_type(notify, INVALID_SYNTAX);
+ response->add_payload(response, (payload_t*)notify);
+ this->logger->log(this->logger, AUDIT,
+ "request message incomplete, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+
+ { /* process SA payload:
+ * -------------------
+ * - extract proposals
+ * - select our most preferred proposal found in extracted
+ * - if no matches, return NO_PROPOSAL_CHOSEN
+ * - add sa payload with selected proposal
+ */
+ sa_payload_t* sa_response;
+ linked_list_t *proposal_list;
+ proposal_t *proposal;
+
+ proposal_list = sa_request->get_proposals(sa_request);
+ this->proposal = this->connection->select_proposal(this->connection, proposal_list);
+ while(proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
+ {
+ proposal->destroy(proposal);
+ }
+ proposal_list->destroy(proposal_list);
+ if (this->proposal == NULL)
+ {
+ notify_payload_t *notify = notify_payload_create();
+ notify->set_notify_type(notify, NO_PROPOSAL_CHOSEN);
+ response->add_payload(response, (payload_t*)notify);
+ this->logger->log(this->logger, AUDIT,
+ "request did not contain any acceptable proposals, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+ sa_response = sa_payload_create_from_proposal(this->proposal);
+ response->add_payload(response, (payload_t *)sa_response);
+ }
+
+ { /* process KE payload:
+ * --------------------
+ * - check if used group match the selected proposal
+ * - if not, stop with INVALID_KE_PAYLOAD
+ * - apply others public value to complete diffie hellman exchange
+ * - add our public value to response
+ */
+ diffie_hellman_group_t used_group;
+ ke_payload_t *ke_response;
+
+ used_group = ke_request->get_dh_group_number(ke_request);
+
+ if (!this->connection->check_dh_group(this->connection, used_group) ||
+ (this->diffie_hellman = diffie_hellman_create(used_group)) == NULL)
+ {
+ u_int16_t notify_group;
+ chunk_t notify_chunk;
+ notify_payload_t *notify;
+ iterator_t *iterator;
+ payload_t *payload;
+
+ notify_group = this->connection->get_dh_group(this->connection);
+ this->logger->log(this->logger, AUDIT,
+ "request used inacceptable DH group %s, sending INVALID_KE_PAYLOAD with %s, deleting IKE_SA",
+ mapping_find(diffie_hellman_group_m, used_group),
+ mapping_find(diffie_hellman_group_m, notify_group));
+
+ /* remove already added payloads */
+ iterator = response->get_payload_iterator(response);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&payload);
+ iterator->remove(iterator);
+ payload->destroy(payload);
+ }
+ iterator->destroy(iterator);
+
+ notify_group = htons(notify_group);
+ notify_chunk.ptr = (u_int8_t*)&notify_group;
+ notify_chunk.len = sizeof(notify_group);
+ notify = notify_payload_create();
+ notify->set_notify_type(notify, INVALID_KE_PAYLOAD);
+ notify->set_notification_data(notify, notify_chunk);
+ response->add_payload(response, (payload_t*)notify);
+ return DESTROY_ME;
+ }
+ this->diffie_hellman->set_other_public_value(this->diffie_hellman,
+ ke_request->get_key_exchange_data(ke_request));
+
+ /* build response */
+ ke_response = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
+ response->add_payload(response, (payload_t*)ke_response);
+ }
+
+ { /* process nonce payload:
+ * ----------------------
+ * - get nonce from payload
+ * - generate own nonce and add to reply
+ */
+ nonce_payload_t *nonce_response;
+
+ this->nonce_i = nonce_request->get_nonce(nonce_request);
+
+ /* build response nonce */
+ if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer,
+ NONCE_SIZE, &this->nonce_r) != SUCCESS)
+ {
+ notify_payload_t *notify = notify_payload_create();
+ notify->set_notify_type(notify, NO_PROPOSAL_CHOSEN);
+ response->add_payload(response, (payload_t*)notify);
+ this->logger->log(this->logger, AUDIT,
+ "could not get random bytes for nonce, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+ nonce_response = nonce_payload_create();
+ nonce_response->set_nonce(nonce_response, this->nonce_r);
+ response->add_payload(response, (payload_t *)nonce_response);
+ }
+
+ { /* processs NATT stuff:
+ * --------------------
+ * - check if we or other is behind NAT
+ * - enable NATT if so
+ * - build NAT detection notifys for reply
+ */
+ notify_payload_t *notify;
+
+ if ((!this->natd_src_seen && this->natd_dst_seen) ||
+ (this->natd_src_seen && !this->natd_dst_seen))
+ {
+ notify = notify_payload_create();
+ notify->set_notify_type(notify, INVALID_SYNTAX);
+ response->add_payload(response, (payload_t*)notify);
+ this->logger->log(this->logger, AUDIT,
+ "request contained wrong number of NAT-D payloads, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+ if (this->natd_dst_seen && !this->natd_dst_matched)
+ {
+ this->ike_sa->enable_natt(this->ike_sa, TRUE);
+ }
+ if (this->natd_src_seen && !this->natd_src_matched)
+ {
+ this->ike_sa->enable_natt(this->ike_sa, FALSE);
+ }
+ /* build response NAT DETECTION notifys, if remote supports it */
+ if (this->natd_src_seen || this->natd_dst_seen)
+ {
+ /* N(NAT_DETECTION_SOURCE_IP) */
+ notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, me);
+ response->add_payload(response, (payload_t*)notify);
+
+ /* N(NAT_DETECTION_DESTINATION_IP) */
+ notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other);
+ response->add_payload(response, (payload_t*)notify);
+ }
+ }
+
+ /* derive all the keys used in the IKE_SA */
+ if (this->ike_sa->build_transforms(this->ike_sa, this->proposal,
+ this->diffie_hellman,
+ this->nonce_i, this->nonce_r,
+ FALSE) != SUCCESS)
+ {
+ notify_payload_t *notify = notify_payload_create();
+ notify->set_notify_type(notify, NO_PROPOSAL_CHOSEN);
+ response->add_payload(response, (payload_t*)notify);
+ this->logger->log(this->logger, AUDIT,
+ "transform objects could not be created from selected proposal, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+
+ { /* create ike_auth transaction, which will store informations for us */
+ packet_t *response_packet;
+ chunk_t request_chunk, response_chunk;
+ ike_auth_t *ike_auth;
+
+ /* we normally do not generate the message. But we need the generated message
+ * for authentication in the next state, so we do it here. This is not problematic,
+ * as we don't use a crypter/signer in ike_sa_init... */
+ if (response->generate(response, NULL, NULL, &response_packet) != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT,
+ "error in response generation, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+ response_packet->destroy(response_packet);
+ request_chunk = request->get_packet_data(request);
+ response_chunk = response->get_packet_data(response);
+
+ /* create next transaction, for which we except a message */
+ ike_auth = ike_auth_create(this->ike_sa, 1);
+ ike_auth->set_nonces(ike_auth,
+ chunk_clone(this->nonce_i),
+ chunk_clone(this->nonce_r));
+ ike_auth->set_init_messages(ike_auth, request_chunk, response_chunk);
+ *next = (transaction_t*)ike_auth;
+ }
+
+ /* everything went fine. Now we set a timeout to destroy half initiated IKE_SAs */
+ timeout = charon->configuration->get_half_open_ike_sa_timeout(charon->configuration);
+ if (timeout)
+ {
+ job_t *job = (job_t*)delete_half_open_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa));
+ charon->event_queue->add_relative(charon->event_queue, job, timeout);
+ }
+ /* set new state */
+ this->ike_sa->set_state(this->ike_sa, SA_CONNECTING);
+ return SUCCESS;
+}
+
+
+/**
+ * Implementation of transaction_t.conclude
+ */
+static status_t conclude(private_ike_sa_init_t *this, message_t *response,
+ transaction_t **next)
+{
+ u_int64_t responder_spi;
+ ike_sa_id_t *ike_sa_id;
+ iterator_t *payloads;
+ host_t *me, *other;
+ sa_payload_t *sa_payload = NULL;
+ ke_payload_t *ke_payload = NULL;
+ nonce_payload_t *nonce_payload = NULL;
+ policy_t *policy;
+ status_t status;
+
+ /* check message type */
+ if (response->get_exchange_type(response) != IKE_SA_INIT)
+ {
+ this->logger->log(this->logger, ERROR,
+ "IKE_SA_INIT response of invalid type, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+
+ /* allow setting of next transaction in other functions */
+ this->next = next;
+
+ this->connection = this->ike_sa->get_connection(this->ike_sa);
+ me = this->connection->get_my_host(this->connection);
+ other = this->connection->get_other_host(this->connection);
+
+ /* check if SPI has been updated, but apply only if all goes ok later */
+ responder_spi = response->get_responder_spi(response);
+ if (responder_spi == 0)
+ {
+ this->logger->log(this->logger, ERROR,
+ "response contained a SPI of zero, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+
+ /* Precompute NAT-D hashes for later comparison */
+ ike_sa_id = response->get_ike_sa_id(response);
+ this->natd_src_hash = generate_natd_hash(this, ike_sa_id, other);
+ this->natd_dst_hash = generate_natd_hash(this, ike_sa_id, me);
+
+ /* Iterate over all payloads to collect them */
+ payloads = response->get_payload_iterator(response);
+ while (payloads->has_next(payloads))
+ {
+ payload_t *payload;
+ payloads->current(payloads, (void**)&payload);
+
+ switch (payload->get_type(payload))
+ {
+ case SECURITY_ASSOCIATION:
+ {
+ sa_payload = (sa_payload_t*)payload;
+ break;
+ }
+ case KEY_EXCHANGE:
+ {
+ ke_payload = (ke_payload_t*)payload;
+ break;
+ }
+ case NONCE:
+ {
+ nonce_payload = (nonce_payload_t*)payload;
+ break;
+ }
+ case NOTIFY:
+ {
+ status = process_notifys(this, (notify_payload_t*)payload);
+ if (status == FAILED)
+ {
+ payloads->destroy(payloads);
+ /* we return SUCCESS, returned FAILED means do next transaction */
+ return SUCCESS;
+ }
+ if (status == DESTROY_ME)
+ {
+ payloads->destroy(payloads);
+ return status;
+ }
+ break;
+ }
+ default:
+ {
+ this->logger->log(this->logger, ERROR, "ignoring payload %s (%d)",
+ mapping_find(payload_type_m, payload->get_type(payload)),
+ payload->get_type(payload));
+ break;
+ }
+ }
+ }
+ payloads->destroy(payloads);
+
+ if (!(nonce_payload && sa_payload && ke_payload))
+ {
+ this->logger->log(this->logger, AUDIT, "response message incomplete, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+
+ { /* process SA payload:
+ * -------------------
+ * - get proposals from it
+ * - check if peer selected a proposal
+ * - verify it's selection againts our set
+ */
+ proposal_t *proposal;
+ linked_list_t *proposal_list;
+
+ /* get the list of selected proposals, the peer has to select only one proposal */
+ proposal_list = sa_payload->get_proposals (sa_payload);
+ if (proposal_list->get_count(proposal_list) != 1)
+ {
+ this->logger->log(this->logger, AUDIT,
+ "response did not contain a single proposal, deleting IKE_SA");
+ while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
+ {
+ proposal->destroy(proposal);
+ }
+ proposal_list->destroy(proposal_list);
+ return DESTROY_ME;
+ }
+
+ /* we have to re-check if the others selection is valid */
+ this->proposal = this->connection->select_proposal(this->connection, proposal_list);
+ while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
+ {
+ proposal->destroy(proposal);
+ }
+ proposal_list->destroy(proposal_list);
+
+ if (this->proposal == NULL)
+ {
+ this->logger->log(this->logger, AUDIT,
+ "peer selected a proposal we did not offer, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+ }
+
+ { /* process KE payload:
+ * -------------------
+ * - extract others public value
+ * - complete diffie-hellman exchange
+ */
+ this->diffie_hellman->set_other_public_value(this->diffie_hellman,
+ ke_payload->get_key_exchange_data(ke_payload));
+ }
+
+ { /* process NONCE payload:
+ * ----------------------
+ * - extract nonce used for key derivation */
+ this->nonce_r = nonce_payload->get_nonce(nonce_payload);
+ }
+
+ { /* process NATT stuff:
+ * -------------------
+ * - check if we or other is NATted
+ * - switch to port 4500 if so
+ */
+ if ((!this->natd_dst_seen && this->natd_src_seen) ||
+ (this->natd_dst_seen && !this->natd_src_seen))
+ {
+ this->logger->log(this->logger, AUDIT,
+ "request contained wrong number of NAT-D payloads, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+ if (this->natd_src_seen && !this->natd_src_matched)
+ {
+ this->ike_sa->enable_natt(this->ike_sa, FALSE);
+ }
+ if (this->natd_dst_seen && !this->natd_dst_matched)
+ {
+ this->ike_sa->enable_natt(this->ike_sa, TRUE);
+ }
+ if (this->ike_sa->is_natt_enabled(this->ike_sa))
+ {
+ me->set_port(me, IKEV2_NATT_PORT);
+ other->set_port(other, IKEV2_NATT_PORT);
+ this->logger->log(this->logger, CONTROL|LEVEL1, "switching to port %d", IKEV2_NATT_PORT);
+ }
+ policy = this->ike_sa->get_policy(this->ike_sa);
+ policy->update_my_ts(policy, me);
+ policy->update_other_ts(policy, other);
+ }
+
+ /* because we are original initiator we have to update the responder SPI to the new one */
+ ike_sa_id = this->ike_sa->get_id(this->ike_sa);
+ ike_sa_id->set_responder_spi(ike_sa_id, responder_spi);
+
+ /* derive all the keys used in the IKE_SA */
+ if (this->ike_sa->build_transforms(this->ike_sa, this->proposal,
+ this->diffie_hellman,
+ this->nonce_i, this->nonce_r,
+ TRUE) != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT,
+ "transform objects could not be created from selected proposal, deleting IKE_SA");
+ return DESTROY_ME;
+ }
+
+ { /* create ike_auth transaction, which will continue IKE_SA setup */
+ chunk_t request_chunk, response_chunk;
+ ike_auth_t *ike_auth;
+
+ request_chunk = this->message->get_packet_data(this->message);
+ response_chunk = response->get_packet_data(response);
+
+ /* create next transaction, for which we except a message */
+ ike_auth = ike_auth_create(this->ike_sa, 1);
+ ike_auth->set_nonces(ike_auth,
+ chunk_clone(this->nonce_i),
+ chunk_clone(this->nonce_r));
+ ike_auth->set_init_messages(ike_auth, request_chunk, response_chunk);
+ *next = (transaction_t*)ike_auth;
+ }
+
+ return SUCCESS;
+}
+
+static void destroy(private_ike_sa_init_t *this)
+{
+ if (this->message)
+ {
+ this->message->destroy(this->message);
+ }
+ if (this->diffie_hellman)
+ {
+ this->diffie_hellman->destroy(this->diffie_hellman);
+ }
+ if (this->proposal)
+ {
+ this->proposal->destroy(this->proposal);
+ }
+ chunk_free(&this->nonce_i);
+ chunk_free(&this->nonce_r);
+ this->randomizer->destroy(this->randomizer);
+ this->nat_hasher->destroy(this->nat_hasher);
+ chunk_free(&this->natd_src_hash);
+ chunk_free(&this->natd_dst_hash);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_sa_init_t *ike_sa_init_create(ike_sa_t *ike_sa, u_int32_t message_id)
+{
+ private_ike_sa_init_t *this = malloc_thing(private_ike_sa_init_t);
+
+ /* transaction interface functions */
+ this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
+ this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
+ this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
+ this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
+ this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
+ this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
+
+ /* public functions */
+ this->public.use_dh_group = (bool(*)(ike_sa_init_t*,diffie_hellman_group_t))use_dh_group;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+ this->message_id = message_id;
+ this->message = NULL;
+ this->requested = 0;
+ this->diffie_hellman = NULL;
+ this->nonce_i = CHUNK_INITIALIZER;
+ this->nonce_r = CHUNK_INITIALIZER;
+ this->connection = NULL;
+ this->proposal = NULL;
+ this->randomizer = randomizer_create();
+ this->nat_hasher = hasher_create(HASH_SHA1);
+ this->natd_src_hash = CHUNK_INITIALIZER;
+ this->natd_dst_hash = CHUNK_INITIALIZER;
+ this->natd_src_seen = FALSE;
+ this->natd_dst_seen = FALSE;
+ this->natd_src_matched = FALSE;
+ this->natd_dst_matched = FALSE;
+ this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
+
+ return &this->public;
+}
diff --git a/src/charon/sa/transactions/ike_sa_init.h b/src/charon/sa/transactions/ike_sa_init.h
new file mode 100644
index 000000000..a7701d625
--- /dev/null
+++ b/src/charon/sa/transactions/ike_sa_init.h
@@ -0,0 +1,73 @@
+/**
+ * @file ike_sa_init.h
+ *
+ * @brief Interface of transaction ike_sa_init.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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_H_
+#define IKE_SA_INIT_H_
+
+#include <sa/ike_sa.h>
+#include <sa/transactions/transaction.h>
+
+
+typedef struct ike_sa_init_t ike_sa_init_t;
+
+/**
+ * @brief A transaction for the first message exchange to set up an IKE_SA.
+ *
+ * @b Constructors:
+ * - ike_sa_init_create()
+ * - transaction_create() with the appropriate message
+ *
+ * @ingroup transactions
+ */
+struct ike_sa_init_t {
+
+ /**
+ * The transaction_t interface.
+ */
+ transaction_t transaction;
+
+ /**
+ * @brief Set the Diffie Hellman group to use for initiating.
+ *
+ * If a first exchange fails with a INVALID_KE_PAYLOAD, the second
+ * try uses the DH group proposed by the responder.
+ *
+ * @param this calling object
+ * @param dh_group diffie hellman group to use
+ * @return FALSE, if DH group not allowed/supported
+ */
+ bool (*use_dh_group) (ike_sa_init_t* this, diffie_hellman_group_t dh_group);
+};
+
+/**
+ * @brief Create a new transaction which processes IKE_SA_INIT exchanges.
+ *
+ * @param ike_sa assigned IKE_SA
+ * @param message_id message ids used in this transaction
+ * @return created ike_sa_init transaction
+ *
+ * @ingroup transactions
+ */
+ike_sa_init_t *ike_sa_init_create(ike_sa_t *ike_sa, u_int32_t message_id);
+
+#endif /* IKE_SA_INIT_H_ */
diff --git a/src/charon/sa/transactions/transaction.c b/src/charon/sa/transactions/transaction.c
new file mode 100644
index 000000000..ecbfd0abc
--- /dev/null
+++ b/src/charon/sa/transactions/transaction.c
@@ -0,0 +1,147 @@
+/**
+ * @file transaction.c
+ *
+ * @brief Generic contstructor for the different transaction types.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 "transaction.h"
+
+#include <sa/child_sa.h>
+#include <sa/transactions/ike_sa_init.h>
+#include <sa/transactions/ike_auth.h>
+#include <sa/transactions/delete_ike_sa.h>
+#include <sa/transactions/dead_peer_detection.h>
+#include <encoding/payloads/ts_payload.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <encoding/payloads/notify_payload.h>
+#include <encoding/payloads/delete_payload.h>
+#include <utils/logger_manager.h>
+
+
+/*
+ * see header file
+ */
+transaction_t *transaction_create(ike_sa_t *ike_sa, message_t *request)
+{
+ iterator_t *iterator;
+ payload_t *current;
+ notify_payload_t *notify;
+ transaction_t *transaction = NULL;
+ u_int32_t message_id;
+
+ if (!request->get_request(request))
+ {
+ return NULL;
+ }
+ message_id = request->get_message_id(request);
+
+ switch (request->get_exchange_type(request))
+ {
+ case IKE_SA_INIT:
+ {
+ transaction = (transaction_t*)ike_sa_init_create(ike_sa, message_id);
+ break;
+ }
+ case IKE_AUTH:
+ {
+ /* IKE_AUTH is always created in IKE_SA_INIT, it never should
+ * appear alone */
+ break;
+ }
+ case CREATE_CHILD_SA:
+ {
+ /* look for a REKEY_SA notify */
+ iterator = request->get_payload_iterator(request);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&current);
+ if (current->get_type(current) != NOTIFY)
+ {
+ continue;
+ }
+ notify = (notify_payload_t*)current;
+ if (notify->get_notify_type(notify) != REKEY_SA)
+ {
+ continue;
+ }
+ switch (notify->get_protocol_id(notify))
+ {
+ case PROTO_IKE:
+ /* TODO: transaction = rekey_ike_sa_create(ike_sa, message_id); */
+ break;
+ case PROTO_AH:
+ case PROTO_ESP:
+ {
+ /* TODO: transaction = rekey_child_sa_create(ike_sa, message_id); */
+ break;
+ }
+ default:
+ break;
+ }
+ if (transaction)
+ {
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ break;
+ }
+ case INFORMATIONAL:
+ {
+ u_int payload_count = 0;
+ iterator = request->get_payload_iterator(request);
+ while (iterator->has_next(iterator))
+ {
+ payload_count++;
+ iterator->current(iterator, (void**)&current);
+ switch (current->get_type(current))
+ {
+ case DELETE:
+ {
+ delete_payload_t *delete_payload;
+ delete_payload = (delete_payload_t*)current;
+ if (delete_payload->get_protocol_id(delete_payload) == PROTO_IKE)
+ {
+ transaction = (transaction_t*)
+ delete_ike_sa_create(ike_sa, message_id);
+ break;
+ }
+ }
+ default:
+ break;
+ }
+ if (transaction)
+ {
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ if (payload_count == 0)
+ {
+ transaction = (transaction_t*)
+ dead_peer_detection_create(ike_sa, message_id);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return transaction;
+}
diff --git a/src/charon/sa/transactions/transaction.h b/src/charon/sa/transactions/transaction.h
new file mode 100644
index 000000000..ea84b0394
--- /dev/null
+++ b/src/charon/sa/transactions/transaction.h
@@ -0,0 +1,181 @@
+/**
+ * @file transaction.h
+ *
+ * @brief Interface transaction_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 TRANSACTION_H_
+#define TRANSACTION_H_
+
+#include <types.h>
+#include <encoding/message.h>
+#include <sa/ike_sa.h>
+
+
+typedef struct transaction_t transaction_t;
+
+/**
+ * @brief This interface represents a transaction an established IKE_SA can do.
+ *
+ * To every transaction, a message ID is associated. IKEv2 uses strict message
+ * IDs, which are equal for a request/response pair in a transaction.
+ * An initiator of a transaction does the following:
+ * - create the transaction using a specific constructor
+ * - call request() to get the message for initiaton
+ * - call conclude() to process received reply
+ * The other peer does the following:
+ * - create a transanction using the generic transaction constructor
+ * - call respond() to get a reply to send
+ *
+ * The responder must not destroy the transaction, until the
+ * initiator initiates another transaction (or a number of transactions
+ * > window size). This allows us to redo a transaction in case of a
+ * message loss. The initiator can destroy the the transaction once
+ * the conclude() function is called.
+ *
+ * @b Constructors:
+ * - transaction_create()
+ * - ike_sa_init_create()
+ * - ike_auth_create()
+ *
+ * @ingroup transactions
+ */
+struct transaction_t {
+
+ /**
+ * @brief Get the request to use for initiating the transaction.
+ *
+ * A transaction creates a request only once. The request is stored
+ * internally and may be queried multiple times for retransmission.
+ * The transaction is not responsible for generating/encrypting the
+ * message, this is the job of the caller. But it MAY be already
+ * generated when calling get_request() the second time.
+ *
+ * @param this calling object
+ * @param[out] request resultin request
+ * @return
+ * - FAILED if transaction failed
+ * - DESTROY_ME if transaction failed and IKE SA
+ * must be deleted
+ * - SUCCESS
+ */
+ status_t (*get_request) (transaction_t *this, message_t **request);
+
+ /**
+ * @brief Build the response for a received request.
+ *
+ * A transaction creates a response only once for a unique request.
+ * This allows the use of get_response multiple times for retransmission
+ * purposes.
+ * The transaction is not responsible for generating/encrypting the
+ * response, nor is it responsible for decrypting/parsing the request.
+ * This is the job of the caller. But the response MAY be already
+ * generated when calling get_request() the second time.
+ * The initiator waits for a response, so we send one in every case. This
+ * means response points always to a valid message. This message
+ * may not be modified or destroyed, it gets destroyed along with the
+ * transaction.
+ * The get_response() function may return a next transaction. This allows
+ * passing of informations from one transaction to a next one.
+ *
+ * @param this calling object
+ * @param request received request
+ * @param[out] response resulting response
+ * @param[out] next transaction expected as next, or NULL
+ * @return
+ * - FAILED if transaction failed
+ * - DESTROY_ME if transaction failed and IKE SA
+ * must be deleted
+ * - SUCCESS
+ */
+ status_t (*get_response) (transaction_t *this, message_t *request,
+ message_t **response, transaction_t **next);
+
+ /**
+ * @brief Conclude an initiated transaction with a received response.
+ *
+ * The response must be decrypted and parsed. The conclude function
+ * may return a new transaction. This transaction has to be executed
+ * next to complete a multi-exchange scenario. It allows a clean
+ * transaction mechanism, as the transaction knows best whats to do
+ * after it completes. It must only be executed if conclude returns
+ * SUCCESS.
+ *
+ * @param this calling object
+ * @param response received response
+ * @param[out] next transaction to execute as next, or NULL
+ * @return
+ * - FAILED if transaction failed
+ * - DESTROY_ME if transaction failed and IKE SA
+ * must be deleted
+ * - SUCCESS
+ */
+ status_t (*conclude) (transaction_t *this, message_t *response,
+ transaction_t **next);
+
+ /**
+ * @brief Get the message ID associated with this transaction.
+ *
+ * Every transaction consists of a message pair with the same
+ * message ID. This ID can be queried with get_message_id().
+ *
+ * @param this calling object
+ * @return message id
+ */
+ u_int32_t (*get_message_id) (transaction_t *this);
+
+ /**
+ * @brief Times we already sent the request (retransmitted).
+ *
+ * The transaction stores an internal counter to see how
+ * many times we sent the request. This counter is incremented
+ * each time after a call to requested().
+ *
+ * @param this calling object
+ * @return message id
+ */
+ u_int32_t (*requested) (transaction_t *this);
+
+ /**
+ * @brief Destroys a transaction_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (transaction_t *this);
+};
+
+/**
+ * @brief Create a transaction instance based on a received request.
+ *
+ * Incoming requests are handled by a transaction. But as we don't
+ * know what kind of transaction we use for a specific request, we use
+ * a generic constructor. This constructor decides which instance will
+ * handle the transaction, and creates it.
+ *
+ * @param ike_sa ike_sa associated with this transaction
+ * @param request received request
+ * @return
+ * - created transaction, or
+ * - NULL no transaction needed
+ *
+ * @ingroup transactions
+ */
+transaction_t *transaction_create(ike_sa_t *ike_sa, message_t* request);
+
+#endif /* TRANSACTION_H_ */
diff --git a/src/charon/testing/generator_test.c b/src/charon/testing/generator_test.c
index b557b5880..d68cdb593 100644
--- a/src/charon/testing/generator_test.c
+++ b/src/charon/testing/generator_test.c
@@ -709,7 +709,7 @@ void test_generator_with_notify_payload(protected_tester_t *tester)
notification_data.len = strlen(notification_data.ptr);
notify_payload->set_protocol_id(notify_payload,255);
- notify_payload->set_notify_message_type(notify_payload,63333); /* Hex F765 */
+ notify_payload->set_notify_type(notify_payload,63333); /* Hex F765 */
notify_payload->set_spi(notify_payload, 0x31323334);
notify_payload->set_notification_data(notify_payload,notification_data);
diff --git a/src/charon/testing/parser_test.c b/src/charon/testing/parser_test.c
index 66e65479b..ed9f7272f 100644
--- a/src/charon/testing/parser_test.c
+++ b/src/charon/testing/parser_test.c
@@ -558,7 +558,7 @@ void test_parser_with_notify_payload(protected_tester_t *tester)
return;
}
tester->assert_true(tester,(notify_payload->get_protocol_id(notify_payload) == 3), "Protocol id");
- tester->assert_true(tester,(notify_payload->get_notify_message_type(notify_payload) == 1), "notify message type");
+ tester->assert_true(tester,(notify_payload->get_notify_type(notify_payload) == 1), "notify message type");
spi = notify_payload->get_spi(notify_payload);
tester->assert_false(tester, spi == 0x01020303, "parsed spi");
diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c
index f6736a86f..4c0f80836 100755
--- a/src/charon/threads/stroke_interface.c
+++ b/src/charon/threads/stroke_interface.c
@@ -42,7 +42,6 @@
#define IKE_PORT 500
#define PATH_BUF 256
-static bool strict = FALSE;
struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET};
@@ -134,7 +133,6 @@ static x509_t* load_end_certificate(const char *filename, identification_t **idp
if (cert)
{
- bool found;
identification_t *id = *idp;
identification_t *subject = cert->get_subject(cert);