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:
Martin Willi
2006-07-05 10:53:20 +00:00
parent b12af2ead6
commit 3dd3c5f39e
71 changed files with 4873 additions and 8187 deletions
+5 -8
View File
@@ -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 \
+9 -11
View File
@@ -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;
+5 -8
View File
@@ -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);
+1 -1
View File
@@ -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;
}
+1 -1
View File
@@ -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;
+2
View File
@@ -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
View File
@@ -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>
+5 -4
View File
@@ -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
+86 -42
View File
@@ -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 */
+13 -28
View File
@@ -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.
*
+1 -1
View File
@@ -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;
}
}
+18 -7
View File
@@ -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;
}
+12 -1
View File
@@ -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.
*
+72 -58
View File
@@ -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_*/
+31
View File
@@ -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
*/
+5
View File
@@ -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;
+1 -1
View File
@@ -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;
}
+4 -4
View File
@@ -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;
+5 -5
View File
@@ -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_ */
+2 -2
View File
@@ -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_ */
+61 -73
View File
@@ -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;
}
+10 -23
View File
@@ -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);
+6 -41
View File
@@ -66,58 +66,23 @@ static status_t execute(private_send_dpd_job_t *this)
{
ike_sa_t *ike_sa;
status_t status;
u_int32_t dt;
u_int32_t interval = charon->configuration->get_dpd_interval(charon->configuration);
struct timeval last_msg_tv, current_tv;
this->logger->log(this->logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s",
this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
this->ike_sa_id->get_responder_spi(this->ike_sa_id),
this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
this->ike_sa_id, &ike_sa);
this->ike_sa_id, &ike_sa);
if (status != SUCCESS)
{
this->logger->log(this->logger, ERROR|LEVEL1,
"IKE SA could not be checked out. Already deleted?");
return DESTROY_ME;
}
last_msg_tv = ike_sa->get_last_traffic_in_tv(ike_sa);
if (0 > gettimeofday(&current_tv, NULL) )
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;
}
/**
+5 -57
View File
@@ -60,74 +60,22 @@ static job_type_t get_type(private_send_keepalive_job_t *this)
}
/**
* Implementation of job_t.execute.
* Implementation of job_t.execute.
*/
static status_t execute(private_send_keepalive_job_t *this)
{
ike_sa_t *ike_sa;
status_t status;
u_int32_t dt;
u_int32_t interval = charon->configuration->get_keepalive_interval(charon->configuration);
struct timeval last_msg_tv, current_tv;
packet_t *packet;
host_t *host;
connection_t *connection;
chunk_t data;
this->logger->log(this->logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s",
this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
this->ike_sa_id->get_responder_spi(this->ike_sa_id),
this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
this->ike_sa_id, &ike_sa);
this->ike_sa_id, &ike_sa);
if (status != SUCCESS)
{
this->logger->log(this->logger, ERROR|LEVEL1,
"IKE SA could not be checked out. Already deleted?");
return DESTROY_ME;
}
last_msg_tv = ike_sa->get_last_traffic_out_tv(ike_sa);
if (0 > gettimeofday(&current_tv, NULL) )
{
this->logger->log(this->logger, ERROR|LEVEL1,
"Warning: Failed to get time of day.");
}
dt = (current_tv.tv_sec - last_msg_tv.tv_sec) * 1000
+ (current_tv.tv_usec - last_msg_tv.tv_usec) / 1000;
if (dt >= interval)
{
packet = packet_create();
connection = ike_sa->get_connection(ike_sa);
host = connection->get_my_host(connection);
packet->set_source(packet, host->clone(host));
host = connection->get_other_host(connection);
packet->set_destination(packet, host->clone(host));
data = chunk_alloc(1);
data.ptr[0] = 0xFF;
packet->set_data(packet, data);
charon->send_queue->add(charon->send_queue, packet);
dt = 0;
this->logger->log(this->logger, CONTROL|LEVEL1,
"NAT keepalive packet scheduled");
}
charon->event_queue->add_relative(charon->event_queue, (job_t*) this, interval - dt);
this->logger->log(this->logger, CONTROL|LEVEL2,
"Checkin IKE SA %lld:%lld, role %s",
this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
this->ike_sa_id->get_responder_spi(this->ike_sa_id),
this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
if (status != SUCCESS)
{
this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!");
}
return SUCCESS;
ike_sa->send_keepalive(ike_sa);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
return DESTROY_ME;
}
/**
+15 -1
View File
@@ -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);
}
+2 -2
View File
@@ -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);
+2 -9
View File
@@ -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_ */
+1
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+293 -529
View File
@@ -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_*/
+1 -1
View File
@@ -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;
}
+98 -38
View File
@@ -175,7 +175,7 @@ struct private_ike_sa_manager_t {
status_t (*get_entry_by_sa) (private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry);
/**
* @brief Felete an entry from the linked list.
* @brief Delete an entry from the linked list.
*
* @param this calling object
* @param entry entry to delete
@@ -229,10 +229,13 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike
if (current->ike_sa_id->get_responder_spi(current->ike_sa_id) == 0)
{
/* seems to be a half ready ike_sa */
if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) == ike_sa_id->get_initiator_spi(ike_sa_id))
&& (ike_sa_id->is_initiator(ike_sa_id) == current->ike_sa_id->is_initiator(current->ike_sa_id)))
if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) ==
ike_sa_id->get_initiator_spi(ike_sa_id)) &&
(ike_sa_id->is_initiator(ike_sa_id) ==
current->ike_sa_id->is_initiator(current->ike_sa_id)))
{
this->logger->log(this->logger, CONTROL|LEVEL2, "found entry by initiator spi %d",
this->logger->log(this->logger, CONTROL|LEVEL2,
"found entry by initiator spi %d",
ike_sa_id->get_initiator_spi(ike_sa_id));
*entry = current;
status = SUCCESS;
@@ -241,8 +244,10 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike
}
else if (ike_sa_id->get_responder_spi(ike_sa_id) == 0)
{
if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) == ike_sa_id->get_initiator_spi(ike_sa_id))
&& (ike_sa_id->is_initiator(ike_sa_id) == current->ike_sa_id->is_initiator(current->ike_sa_id)))
if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) ==
ike_sa_id->get_initiator_spi(ike_sa_id)) &&
(ike_sa_id->is_initiator(ike_sa_id) ==
current->ike_sa_id->is_initiator(current->ike_sa_id)))
{
this->logger->log(this->logger, CONTROL|LEVEL2, "found entry by initiator spi %d",
ike_sa_id->get_initiator_spi(ike_sa_id));
@@ -315,7 +320,8 @@ static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *ent
iterator->current(iterator, (void**)&current);
if (current == entry)
{
this->logger->log(this->logger, CONTROL|LEVEL2, "found entry by pointer. Going to delete it.");
this->logger->log(this->logger, CONTROL|LEVEL2,
"found entry by pointer. Going to delete it");
iterator->remove(iterator);
entry->destroy(entry);
status = SUCCESS;
@@ -355,6 +361,11 @@ static void create_and_checkout(private_ike_sa_manager_t *this,ike_sa_t **ike_sa
/* create entry */
new_ike_sa_entry = ike_sa_entry_create(new_ike_sa_id);
new_ike_sa_id->destroy(new_ike_sa_id);
this->logger->log(this->logger, CONTROL|LEVEL2,
"created IKE_SA %llx:%llx, role %s",
new_ike_sa_id->get_initiator_spi(new_ike_sa_id),
new_ike_sa_id->get_responder_spi(new_ike_sa_id),
new_ike_sa_id->is_initiator(new_ike_sa_id) ? "initiator" : "responder");
/* each access is locked */
pthread_mutex_lock(&(this->mutex));
@@ -362,7 +373,8 @@ static void create_and_checkout(private_ike_sa_manager_t *this,ike_sa_t **ike_sa
this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry);
/* check ike_sa out */
this->logger->log(this->logger, CONTROL|LEVEL1, "new IKE_SA created and added to list of known IKE_SA's");
this->logger->log(this->logger, CONTROL|LEVEL1,
"new IKE_SA created and added to list of known IKE_SA's");
new_ike_sa_entry->checked_out = TRUE;
*ike_sa = new_ike_sa_entry->ike_sa;
@@ -379,6 +391,15 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
bool original_initiator;
status_t retval;
this->logger->log(this->logger, CONTROL|LEVEL2,
"checkout IKE_SA %llx:%llx, role %s",
ike_sa_id->get_initiator_spi(ike_sa_id),
ike_sa_id->get_responder_spi(ike_sa_id),
ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
this->logger->log(this->logger, CONTROL|LEVEL2, "%d IKE_SAs in manager",
this->ike_sa_list->get_count(this->ike_sa_list));
/* each access is locked */
pthread_mutex_lock(&(this->mutex));
@@ -399,7 +420,8 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
/* can we give this ike_sa out to new requesters?*/
if (entry->driveout_new_threads)
{
this->logger->log(this->logger, CONTROL|LEVEL1, "drive out new thread for existing IKE_SA");
this->logger->log(this->logger, CONTROL|LEVEL1,
"drive out new thread for existing IKE_SA");
/* no we can't */
retval = NOT_FOUND;
}
@@ -422,12 +444,14 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
{
/* we must signal here, others are interested that we leave */
pthread_cond_signal(&(entry->condvar));
this->logger->log(this->logger, CONTROL|LEVEL1, "drive out waiting thread for existing IKE_SA");
this->logger->log(this->logger, CONTROL|LEVEL1,
"drive out waiting thread for existing IKE_SA");
retval = NOT_FOUND;
}
else
{
this->logger->log(this->logger, CONTROL|LEVEL2, "IKE SA successfully checked out");
this->logger->log(this->logger, CONTROL|LEVEL2,
"IKE SA successfully checked out");
/* ok, this IKE_SA is finally ours */
entry->checked_out = TRUE;
*ike_sa = entry->ike_sa;
@@ -438,7 +462,8 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
}
else
{
this->logger->log(this->logger, ERROR|LEVEL1, "IKE SA not stored in known IKE_SA list");
this->logger->log(this->logger, ERROR|LEVEL1,
"IKE SA not stored in known IKE_SA list");
/* looks like there is no such IKE_SA, better luck next time... */
/* DON'T use return, we must unlock the mutex! */
retval = NOT_FOUND;
@@ -469,11 +494,12 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry);
/* check ike_sa out */
this->logger->log(this->logger, CONTROL|LEVEL1 ,"IKE_SA added to list of known IKE_SA's");
this->logger->log(this->logger, CONTROL|LEVEL1,
"IKE_SA added to list of known IKE_SA's");
new_ike_sa_entry->checked_out = TRUE;
*ike_sa = new_ike_sa_entry->ike_sa;
retval = CREATED;
retval = SUCCESS;
}
else
{
@@ -482,7 +508,7 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
/* DON'T use return, we must unlock the mutex! */
retval = INVALID_ARG;
}
pthread_mutex_unlock(&(this->mutex));
/* OK, unlocked... */
return retval;
@@ -491,7 +517,8 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
/**
* Implementation of of ike_sa_manager.checkout_by_reqid.
*/
static status_t checkout_by_reqid(private_ike_sa_manager_t *this, u_int32_t reqid, ike_sa_t **ike_sa)
static status_t checkout_by_reqid(private_ike_sa_manager_t *this,
u_int32_t reqid, ike_sa_t **ike_sa)
{
iterator_t *iterator;
status_t status = NOT_FOUND;
@@ -600,15 +627,16 @@ linked_list_t *get_ike_sa_list_by_name(private_ike_sa_manager_t* this, const cha
static void log_status(private_ike_sa_manager_t* this, logger_t* logger, char* name)
{
iterator_t *iterator;
u_int instances;
pthread_mutex_lock(&(this->mutex));
iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
if (iterator->get_count(iterator))
instances = this->ike_sa_list->get_count(this->ike_sa_list);
if (instances)
{
logger->log(logger, CONTROL, "Instances:");
logger->log(logger, CONTROL, "Instances (%d):", instances);
}
iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
while (iterator->has_next(iterator))
{
ike_sa_entry_t *entry;
@@ -633,6 +661,15 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
*/
status_t retval;
ike_sa_entry_t *entry;
ike_sa_id_t *ike_sa_id;
ike_sa_id = ike_sa->get_id(ike_sa);
this->logger->log(this->logger, CONTROL|LEVEL2,
"checkin IKE_SA %llx:%llx, role %s",
ike_sa_id->get_initiator_spi(ike_sa_id),
ike_sa_id->get_responder_spi(ike_sa_id),
ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
pthread_mutex_lock(&(this->mutex));
@@ -649,10 +686,14 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
}
else
{
this->logger->log(this->logger, ERROR, "tried to check in nonexisting IKE_SA");
this->logger->log(this->logger, ERROR,
"tried to check in nonexisting IKE_SA");
/* this SA is no more, this REALLY should not happen */
retval = NOT_FOUND;
}
this->logger->log(this->logger, CONTROL|LEVEL2, "%d IKE_SAs in manager now",
this->ike_sa_list->get_count(this->ike_sa_list));
pthread_mutex_unlock(&(this->mutex));
return retval;
}
@@ -670,6 +711,14 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik
*/
ike_sa_entry_t *entry;
status_t retval;
ike_sa_id_t *ike_sa_id;
ike_sa_id = ike_sa->get_id(ike_sa);
this->logger->log(this->logger, CONTROL|LEVEL2,
"checkin and destroy IKE_SA %llx:%llx, role %s",
ike_sa_id->get_initiator_spi(ike_sa_id),
ike_sa_id->get_responder_spi(ike_sa_id),
ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
pthread_mutex_lock(&(this->mutex));
@@ -690,12 +739,14 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik
}
/* ok, we are alone now, no threads waiting in the entry's condvar */
this->delete_entry(this, entry);
this->logger->log(this->logger, CONTROL|LEVEL1, "check-in and destroy of IKE_SA successful");
this->logger->log(this->logger, CONTROL|LEVEL1,
"check-in and destroy of IKE_SA successful");
retval = SUCCESS;
}
else
{
this->logger->log(this->logger,ERROR, "tried to check-in and delete nonexisting IKE_SA");
this->logger->log(this->logger,ERROR,
"tried to check-in and delete nonexisting IKE_SA");
retval = NOT_FOUND;
}
@@ -715,9 +766,15 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
*/
ike_sa_entry_t *entry;
status_t retval;
this->logger->log(this->logger, CONTROL|LEVEL2,
"delete IKE_SA %llx:%llx, role %s",
ike_sa_id->get_initiator_spi(ike_sa_id),
ike_sa_id->get_responder_spi(ike_sa_id),
ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
pthread_mutex_lock(&(this->mutex));
if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
{
/* we try a delete. If it succeeds, our job is done here. The
@@ -725,11 +782,13 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
*/
if (entry->ike_sa->delete(entry->ike_sa) == SUCCESS)
{
this->logger->log(this->logger, CONTROL|LEVEL1, "initiated delete for IKE_SA");
this->logger->log(this->logger, CONTROL|LEVEL1,
"initiated delete for IKE_SA");
}
/* but if the IKE SA is not in a state where the deletion is negotiated with
* the other peer, we can destroy the IKE SA on our own. For this, we must
* be sure that really NO other threads are waiting for this SA...
/* but if the IKE SA is not in a state where the deletion is
* negotiated with the other peer, we can destroy the IKE SA on our own.
* For this, we must be sure that really NO other threads are
* waiting for this SA...
*/
else
{
@@ -740,7 +799,8 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
{
/* wake up all */
pthread_cond_broadcast(&(entry->condvar));
/* and the nice thing, they will wake us again when their work is done */
/* and the nice thing, they will wake us again when their work
* is done */
pthread_cond_wait(&(entry->condvar), &(this->mutex));
}
/* ok, we are alone now, no threads waiting in the entry's condvar */
@@ -751,7 +811,8 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
}
else
{
this->logger->log(this->logger,ERROR, "tried to delete nonexisting IKE_SA");
this->logger->log(this->logger,ERROR,
"tried to delete nonexisting IKE_SA");
retval = NOT_FOUND;
}
@@ -770,13 +831,12 @@ static void destroy(private_ike_sa_manager_t *this)
ike_sa_entry_t *entry;
pthread_mutex_lock(&(this->mutex));
this->logger->log(this->logger, CONTROL|LEVEL1, "going to destroy IKE_SA manager and all managed IKE_SA's");
this->logger->log(this->logger, CONTROL|LEVEL1,
"going to destroy IKE_SA manager and all managed IKE_SA's");
/* Step 1: drive out all waiting threads */
this->logger->log(this->logger, CONTROL|LEVEL2,
"set driveout flags for all stored IKE_SA's");
iterator = list->create_iterator(list, TRUE);
this->logger->log(this->logger, CONTROL|LEVEL2, "set driveout flags for all stored IKE_SA's");
while (iterator->has_next(iterator))
{
iterator->current(iterator, (void**)&entry);
@@ -784,8 +844,8 @@ static void destroy(private_ike_sa_manager_t *this)
entry->driveout_new_threads = TRUE;
entry->driveout_waiting_threads = TRUE;
}
this->logger->log(this->logger, CONTROL|LEVEL2, "wait for all threads to leave IKE_SA's");
this->logger->log(this->logger, CONTROL|LEVEL2,
"wait for all threads to leave IKE_SA's");
/* Step 2: wait until all are gone */
iterator->reset(iterator);
while (iterator->has_next(iterator))
@@ -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_*/
-719
View File
@@ -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);
}
-72
View File
@@ -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_*/
-671
View File
@@ -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);
}
-64
View File
@@ -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_*/
-440
View File
@@ -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);
}
-84
View File
@@ -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_*/
-798
View File
@@ -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);
}
-68
View File
@@ -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_*/
-41
View File
@@ -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}
};
-228
View File
@@ -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_ */
+271
View File
@@ -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
+86
View File
@@ -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
+73
View File
@@ -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_ */
+147
View File
@@ -0,0 +1,147 @@
/**
* @file transaction.c
*
* @brief Generic contstructor for the different transaction types.
*
*/
/*
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "transaction.h"
#include <sa/child_sa.h>
#include <sa/transactions/ike_sa_init.h>
#include <sa/transactions/ike_auth.h>
#include <sa/transactions/delete_ike_sa.h>
#include <sa/transactions/dead_peer_detection.h>
#include <encoding/payloads/ts_payload.h>
#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/notify_payload.h>
#include <encoding/payloads/delete_payload.h>
#include <utils/logger_manager.h>
/*
* see header file
*/
transaction_t *transaction_create(ike_sa_t *ike_sa, message_t *request)
{
iterator_t *iterator;
payload_t *current;
notify_payload_t *notify;
transaction_t *transaction = NULL;
u_int32_t message_id;
if (!request->get_request(request))
{
return NULL;
}
message_id = request->get_message_id(request);
switch (request->get_exchange_type(request))
{
case IKE_SA_INIT:
{
transaction = (transaction_t*)ike_sa_init_create(ike_sa, message_id);
break;
}
case IKE_AUTH:
{
/* IKE_AUTH is always created in IKE_SA_INIT, it never should
* appear alone */
break;
}
case CREATE_CHILD_SA:
{
/* look for a REKEY_SA notify */
iterator = request->get_payload_iterator(request);
while (iterator->has_next(iterator))
{
iterator->current(iterator, (void**)&current);
if (current->get_type(current) != NOTIFY)
{
continue;
}
notify = (notify_payload_t*)current;
if (notify->get_notify_type(notify) != REKEY_SA)
{
continue;
}
switch (notify->get_protocol_id(notify))
{
case PROTO_IKE:
/* TODO: transaction = rekey_ike_sa_create(ike_sa, message_id); */
break;
case PROTO_AH:
case PROTO_ESP:
{
/* TODO: transaction = rekey_child_sa_create(ike_sa, message_id); */
break;
}
default:
break;
}
if (transaction)
{
break;
}
}
iterator->destroy(iterator);
break;
}
case INFORMATIONAL:
{
u_int payload_count = 0;
iterator = request->get_payload_iterator(request);
while (iterator->has_next(iterator))
{
payload_count++;
iterator->current(iterator, (void**)&current);
switch (current->get_type(current))
{
case DELETE:
{
delete_payload_t *delete_payload;
delete_payload = (delete_payload_t*)current;
if (delete_payload->get_protocol_id(delete_payload) == PROTO_IKE)
{
transaction = (transaction_t*)
delete_ike_sa_create(ike_sa, message_id);
break;
}
}
default:
break;
}
if (transaction)
{
break;
}
}
iterator->destroy(iterator);
if (payload_count == 0)
{
transaction = (transaction_t*)
dead_peer_detection_create(ike_sa, message_id);
}
break;
}
default:
break;
}
return transaction;
}
+181
View File
@@ -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_ */
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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");
-2
View File
@@ -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);