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
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+1
-1
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -520,6 +516,20 @@ static exchange_type_t get_request (private_message_t *this)
|
||||
return this->is_request;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -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];
|
||||
|
||||
this->logger->log(this->logger, CONTROL, "generating %s %s, contains %d payloads",
|
||||
if (is_encoded(this))
|
||||
{
|
||||
/* already generated, return a new packet clone */
|
||||
*packet = this->packet->clone(this->packet);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -710,20 +771,6 @@ static chunk_t get_packet_data (private_message_t *this)
|
||||
return chunk_clone(this->packet->get_data(this->packet));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
@@ -321,19 +319,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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -26,6 +26,15 @@
|
||||
#include <types.h>
|
||||
#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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
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);
|
||||
/* 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;
|
||||
}
|
||||
case NAT_DETECTION_SOURCE_IP:
|
||||
case NAT_DETECTION_DESTINATION_IP:
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -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_*/
|
||||
|
||||
@@ -73,6 +73,37 @@ mapping_t payload_type_m[] = {
|
||||
{MAPPING_END, NULL}
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -56,6 +56,47 @@ static job_type_t get_type(private_incoming_packet_job_t *this)
|
||||
return INCOMING_PACKET;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,11 +45,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
|
||||
*/
|
||||
@@ -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;
|
||||
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!");
|
||||
}
|
||||
|
||||
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->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);
|
||||
|
||||
|
||||
@@ -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(¤t_tv, NULL) )
|
||||
status = ike_sa->send_dpd(ike_sa);
|
||||
if (status == DESTROY_ME)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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(¤t_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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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;
|
||||
|
||||
+875
-1050
File diff suppressed because it is too large
Load Diff
+293
-529
@@ -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()
|
||||
*
|
||||
@@ -66,55 +93,6 @@ typedef struct ike_sa_t ike_sa_t;
|
||||
*/
|
||||
struct ike_sa_t {
|
||||
|
||||
/**
|
||||
* @brief Processes a incoming IKEv2-Message of type message_t.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
status_t (*process_message) (ike_sa_t *this,message_t *message);
|
||||
|
||||
/**
|
||||
* @brief Initiate a new connection with given connection_t object.
|
||||
*
|
||||
* The connection_t object is owned by the IKE_SA after the call, so
|
||||
* do not modify or destroy it.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param connection connection to initiate
|
||||
* @return
|
||||
* - SUCCESS if initialization started
|
||||
* - 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);
|
||||
|
||||
/**
|
||||
* @brief Checks whether retransmission is possible.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param message_id ID of the request to retransmit
|
||||
* @return
|
||||
* - TRUE if retransmit is possible
|
||||
* - FALSE if not
|
||||
*/
|
||||
bool (*retransmit_possible) (ike_sa_t *this, u_int32_t message_id);
|
||||
|
||||
/**
|
||||
* @brief Retransmits a request.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param message_id ID of the request to retransmit
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - 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.
|
||||
*
|
||||
@@ -124,161 +102,37 @@ struct ike_sa_t {
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
connection_t* (*get_connection) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Query NAT detection status for local host.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return TRUE if this host is behind NAT
|
||||
*/
|
||||
bool (*is_my_host_behind_nat) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Query NAT detection status for remote host.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return TRUE if this or other host is behind NAT
|
||||
*/
|
||||
bool (*is_any_host_behind_nat) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Query timeval of last inbound IKE or ESP traffic.
|
||||
* @brief Get the state of the IKE_SA.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return time when the last traffic was seen
|
||||
*/
|
||||
struct timeval (*get_last_traffic_in_tv) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Query timeval of last outbound IKE or ESP traffic.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return state of IKE_SA
|
||||
* @return state of the IKE_SA
|
||||
*/
|
||||
ike_sa_state_t (*get_state) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Sends a DPD request to the peer.
|
||||
*
|
||||
* @param this calling object
|
||||
* @brief Set the state of the IKE_SA.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param state state to set for the IKE_SA
|
||||
*/
|
||||
status_t (*send_dpd_request) (ike_sa_t *this);
|
||||
|
||||
void (*set_state) (ike_sa_t *this, ike_sa_state_t ike_sa);
|
||||
|
||||
/**
|
||||
* @brief Log the status of a the ike sa to a logger.
|
||||
* @brief Initiate a new connection.
|
||||
*
|
||||
* The status of the IKE SA and all child SAs is logged.
|
||||
* Supplying NULL as logger uses the internal child_sa logger
|
||||
* to do the logging. The log is only done if the supplied
|
||||
* connection name is NULL or matches the connections name.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param logger logger to use for logging
|
||||
* @param name name of the connection
|
||||
*/
|
||||
void (*log_status) (ike_sa_t *this, logger_t *logger, char *name);
|
||||
* The connection_t object is owned by the IKE_SA after the call, so
|
||||
* do not modify or destroy it.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param connection connection to initiate
|
||||
* @return
|
||||
* - SUCCESS if initialization started
|
||||
* - FAILED if in wrong state
|
||||
* - DESTROY_ME if initialization failed and IKE_SA MUST be deleted
|
||||
*/
|
||||
status_t (*initiate) (ike_sa_t *this, connection_t *connection);
|
||||
|
||||
/**
|
||||
* @brief Initiates the deletion of an IKE_SA.
|
||||
@@ -295,7 +149,238 @@ struct ike_sa_t {
|
||||
* delete (but destroyed).
|
||||
*/
|
||||
status_t (*delete) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Retransmits a request.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param message_id ID of the request to retransmit
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - NOT_FOUND if request doesn't have to be retransmited
|
||||
*/
|
||||
status_t (*retransmit_request) (ike_sa_t *this, u_int32_t message_id);
|
||||
|
||||
/**
|
||||
* @brief Processes a incoming IKEv2-Message.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param[in] message message to process
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
* - DESTROY_ME if this IKE_SA MUST be deleted
|
||||
*/
|
||||
status_t (*process_message) (ike_sa_t *this,message_t *message);
|
||||
|
||||
/**
|
||||
* @brief Check if NAT traversal is enabled for this IKE_SA.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return TRUE if NAT traversal enabled
|
||||
*/
|
||||
bool (*is_natt_enabled) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Enable NAT detection for this IKE_SA.
|
||||
*
|
||||
* 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
|
||||
* @param local TRUE, if we are NATted, FALSE if other
|
||||
*/
|
||||
void (*enable_natt) (ike_sa_t *this, bool local);
|
||||
|
||||
/**
|
||||
* @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
|
||||
* - SUCCESS
|
||||
* - DESTROY_ME, if peer did not respond
|
||||
*/
|
||||
status_t (*send_dpd) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Sends a keep alive packet.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
void (*send_keepalive) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Log the status of a the ike sa to a logger.
|
||||
*
|
||||
* The status of the IKE SA and all child SAs is logged.
|
||||
* Supplying NULL as logger uses the internal child_sa logger
|
||||
* to do the logging. The log is only done if the supplied
|
||||
* connection name is NULL or matches the connections name.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param logger logger to use for logging
|
||||
* @param name name of the connection
|
||||
*/
|
||||
void (*log_status) (ike_sa_t *this, logger_t *logger, char *name);
|
||||
|
||||
/**
|
||||
* @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) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Set the internal connection object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param connection object of type connection_t
|
||||
*/
|
||||
void (*set_connection) (ike_sa_t *this, connection_t *connection);
|
||||
|
||||
/**
|
||||
* @brief Get the internal stored policy object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to the internal stored policy_t object
|
||||
*/
|
||||
policy_t *(*get_policy) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Set the internal policy_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param policy object of type policy_t
|
||||
*/
|
||||
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.
|
||||
* 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
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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) (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
|
||||
*/
|
||||
child_sa_t* (*get_child_sa) (ike_sa_t *this, u_int32_t spi);
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
* @TODO use spi, not reqid
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @TODO use spi, not reqid
|
||||
*/
|
||||
status_t (*rekey_child_sa) (ike_sa_t *this, u_int32_t reqid);
|
||||
|
||||
/**
|
||||
* @brief Associates a child SA to this IKE SA
|
||||
*
|
||||
* @param this calling object
|
||||
* @param child_sa child_sa to add
|
||||
*/
|
||||
void (*add_child_sa) (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
|
||||
*/
|
||||
u_int32_t (*destroy_child_sa) (ike_sa_t *this, u_int32_t spi);
|
||||
|
||||
/**
|
||||
* @brief Destroys a ike_sa_t object.
|
||||
*
|
||||
@@ -304,337 +389,16 @@ struct ike_sa_t {
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Set the internal connection object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param connection object of type connection_t
|
||||
*/
|
||||
void (*set_connection) (protected_ike_sa_t *this, connection_t *connection);
|
||||
|
||||
/**
|
||||
* @brief Get the internal stored policy object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to the internal stored policy_t object
|
||||
*/
|
||||
policy_t *(*get_policy) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Set the internal policy_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param policy object of type policy_t
|
||||
*/
|
||||
void (*set_policy) (protected_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.
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* @brief Get the multi purpose prf.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to prf_t object
|
||||
*/
|
||||
prf_t *(*get_prf) (protected_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
|
||||
*/
|
||||
prf_t *(*get_child_prf) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the prf used for authentication of initiator.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to prf_t object
|
||||
*/
|
||||
prf_t *(*get_prf_auth_i) (protected_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
|
||||
*/
|
||||
u_int32_t (*destroy_child_sa) (protected_ike_sa_t *this, u_int32_t spi);
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
child_sa_t* (*get_child_sa) (protected_ike_sa_t *this, u_int32_t spi);
|
||||
|
||||
/**
|
||||
* @brief establish the IKE SA
|
||||
*
|
||||
* @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 this calling object
|
||||
*/
|
||||
void (*reset_message_buffers) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Set NAT detection status for local host.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param nat if TRUE, remote host is behing NAT
|
||||
*/
|
||||
void (*set_other_host_behind_nat) (protected_ike_sa_t *this, bool nat);
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
chunk_t (*generate_natd_hash) (protected_ike_sa_t *this, u_int64_t spi_i, u_int64_t spi_r, host_t *host);
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
status_t (*update_connection_hosts) (protected_ike_sa_t *this, host_t *me, host_t *other);
|
||||
|
||||
/**
|
||||
* @brief Return the message id of the last DPD message
|
||||
*
|
||||
* @param this calling object
|
||||
* @return the messages id
|
||||
*/
|
||||
u_int32_t (*get_last_dpd_message_id) (protected_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_*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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**)¤t);
|
||||
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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_*/
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_*/
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_*/
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_*/
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_*/
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_*/
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_*/
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_*/
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_*/
|
||||
@@ -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}
|
||||
};
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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_ */
|
||||
@@ -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**)¤t);
|
||||
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**)¤t);
|
||||
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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user