* TRUE if payload has to get encrypted
*/
bool encrypted;
+
+ /**
+ * Verifying can stop after checking this payload.
+ */
+ bool can_be_last;
};
typedef struct message_rule_t message_rule_t;
*/
static supported_payload_entry_t supported_ike_sa_init_i_payloads[] =
{
- {SECURITY_ASSOCIATION,1,1,FALSE},
- {KEY_EXCHANGE,1,1,FALSE},
- {NONCE,1,1,FALSE},
+ {SECURITY_ASSOCIATION,1,1,FALSE,FALSE},
+ {KEY_EXCHANGE,1,1,FALSE,FALSE},
+ {NONCE,1,1,FALSE,FALSE},
};
/**
*/
static supported_payload_entry_t supported_ike_sa_init_r_payloads[] =
{
- {SECURITY_ASSOCIATION,1,1,FALSE},
- {KEY_EXCHANGE,1,1,FALSE},
- {NONCE,1,1,FALSE},
+ {NOTIFY,0,1,FALSE,TRUE},
+ {SECURITY_ASSOCIATION,1,1,FALSE,FALSE},
+ {KEY_EXCHANGE,1,1,FALSE,FALSE},
+ {NONCE,1,1,FALSE,FALSE},
};
/**
*/
static supported_payload_entry_t supported_ike_auth_i_payloads[] =
{
- {ID_INITIATOR,1,1,TRUE},
- {CERTIFICATE,0,1,TRUE},
- {CERTIFICATE_REQUEST,0,1,TRUE},
- {ID_RESPONDER,0,1,TRUE},
- {AUTHENTICATION,1,1,TRUE},
- {SECURITY_ASSOCIATION,1,1,TRUE},
- {TRAFFIC_SELECTOR_INITIATOR,1,1,TRUE},
- {TRAFFIC_SELECTOR_RESPONDER,1,1,TRUE},
+ {ID_INITIATOR,1,1,TRUE,FALSE},
+ {CERTIFICATE,0,1,TRUE,FALSE},
+ {CERTIFICATE_REQUEST,0,1,TRUE,FALSE},
+ {ID_RESPONDER,0,1,TRUE,FALSE},
+ {AUTHENTICATION,1,1,TRUE,FALSE},
+ {SECURITY_ASSOCIATION,1,1,TRUE,FALSE},
+ {TRAFFIC_SELECTOR_INITIATOR,1,1,TRUE,FALSE},
+ {TRAFFIC_SELECTOR_RESPONDER,1,1,TRUE,FALSE},
};
/**
*/
static supported_payload_entry_t supported_ike_auth_r_payloads[] =
{
- {CERTIFICATE,0,1,TRUE},
- {ID_RESPONDER,0,1,TRUE},
- {AUTHENTICATION,1,1,TRUE},
- {SECURITY_ASSOCIATION,1,1,TRUE},
- {TRAFFIC_SELECTOR_INITIATOR,1,1,TRUE},
- {TRAFFIC_SELECTOR_RESPONDER,1,1,TRUE},
+ {CERTIFICATE,0,1,TRUE,FALSE},
+ {ID_RESPONDER,0,1,TRUE,FALSE},
+ {AUTHENTICATION,1,1,TRUE,FALSE},
+ {SECURITY_ASSOCIATION,1,1,TRUE,FALSE},
+ {TRAFFIC_SELECTOR_INITIATOR,1,1,TRUE,FALSE},
+ {TRAFFIC_SELECTOR_RESPONDER,1,1,TRUE,FALSE},
};
/**
status_t status;
iterator_t *iterator;
message_rule_t *message_rule;
+ size_t total_found_payloads = 0;
this->logger->log(this->logger, CONTROL|MORE, "Verifying message structure");
mapping_find(exchange_type_m,this->exchange_type));
return status;
}
-
+
iterator = this->payloads->create_iterator(this->payloads,TRUE);
/* check for payloads with wrong count*/
for (i = 0; i < message_rule->supported_payloads_count;i++)
if (current_payload->get_type(current_payload) == message_rule->supported_payloads[i].payload_type)
{
found_payloads++;
+ total_found_payloads++;
this->logger->log(this->logger, CONTROL | MOST, "Found payload of type %s",
mapping_find(payload_type_m,message_rule->supported_payloads[i].payload_type));
iterator->destroy(iterator);
return NOT_SUPPORTED;
}
+ if ((message_rule->supported_payloads[i].can_be_last) && (this->payloads->get_count(this->payloads) == total_found_payloads))
+ {
+ iterator->destroy(iterator);
+ return SUCCESS;
+ }
}
iterator->destroy(iterator);
#include <encoding/payloads/encodings.h>
#include <utils/allocator.h>
+/**
+ * String mappings for notify_message_type_t.
+ */
+mapping_t notify_message_type_m[] = {
+ {UNSUPPORTED_CRITICAL_PAYLOAD, "UNSUPPORTED_CRITICAL_PAYLOAD"},
+ {INVALID_IKE_SPI, "INVALID_IKE_SPI"},
+ {INVALID_MAJOR_VERSION, "INVALID_MAJOR_VERSION"},
+ {INVALID_SYNTAX, "INVALID_SYNTAX"},
+ {INVALID_MESSAGE_ID, "MODP_2048_BIT"},
+ {INVALID_SPI, "INVALID_SPI"},
+ {NO_PROPOSAL_CHOSEN, "NO_PROPOSAL_CHOSEN"},
+ {INVALID_KE_PAYLOAD, "INVALID_KE_PAYLOAD"},
+ {AUTHENTICATION_FAILED, "AUTHENTICATION_FAILED"},
+ {SINGLE_PAIR_REQUIRED, "SINGLE_PAIR_REQUIRED"},
+ {NO_ADDITIONAL_SAS, "NO_ADDITIONAL_SAS"},
+ {INTERNAL_ADDRESS_FAILURE, "INTERNAL_ADDRESS_FAILURE"},
+ {FAILED_CP_REQUIRED, "FAILED_CP_REQUIRED"},
+ {TS_UACCEPTABLE, "TS_UACCEPTABLE"},
+ {INVALID_SELECTORS, "INVALID_SELECTORS"},
+ {MAPPING_END, NULL}
+};
typedef struct private_notify_payload_t private_notify_payload_t;
*/
static payload_type_t get_type(private_notify_payload_t *this)
{
- return KEY_EXCHANGE;
+ return NOTIFY;
}
/**
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 = notify_payload_create();
+
+ notify->set_notify_message_type(notify,notify_message_type);
+ notify->set_protocol_id(notify,protocol_id);
+
+ return notify;
+}
#include <types.h>
#include <encoding/payloads/payload.h>
+#include <encoding/payloads/proposal_substructure.h>
#include <utils/linked_list.h>
/**
*/
#define NOTIFY_PAYLOAD_HEADER_LENGTH 8
+typedef enum notify_message_type_t notify_message_type_t;
+
+
+/**
+ * @brief Notify message types.
+ *
+ * Ssee IKEv2 draft 3.10.1.
+ *
+ * @ingroup payloads
+ */
+enum notify_message_type_t {
+ UNSUPPORTED_CRITICAL_PAYLOAD = 1,
+ INVALID_IKE_SPI = 4,
+ INVALID_MAJOR_VERSION = 5,
+ INVALID_SYNTAX = 7,
+ INVALID_MESSAGE_ID = 9,
+ INVALID_SPI = 11,
+ NO_PROPOSAL_CHOSEN = 14,
+ INVALID_KE_PAYLOAD = 17,
+ AUTHENTICATION_FAILED = 24,
+ SINGLE_PAIR_REQUIRED = 34,
+ NO_ADDITIONAL_SAS = 35,
+ INTERNAL_ADDRESS_FAILURE = 36,
+ FAILED_CP_REQUIRED = 37,
+ TS_UACCEPTABLE = 38,
+ INVALID_SELECTORS = 39
+};
+
+/**
+ * String mappings for notify_message_type_t.
+ */
+extern mapping_t notify_message_type_m[];
+
+
+
typedef struct notify_payload_t notify_payload_t;
/**
*/
notify_payload_t *notify_payload_create();
+/**
+ * @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)
+ * @return created 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);
+
#endif /*NOTIFY_PAYLOAD_H_*/
#include <utils/allocator.h>
#include <utils/linked_list.h>
+/**
+ * String mappings for protocol_id_t.
+ */
+mapping_t protocol_id_m[] = {
+ {UNDEFINED_PROTOCOL_ID, "UNDEFINED_PROTOCOL_ID"},
+ {IKE, "IKE"},
+ {AH, "AH"},
+ {ESP, "ESP"},
+ {MAPPING_END, NULL}
+};
+
+
typedef struct private_proposal_substructure_t private_proposal_substructure_t;
/**
IKE = 1,
AH = 2,
ESP = 3,
-};
+};
+
+/**
+ * String mappings for protocol_id_t.
+ */
+extern mapping_t protocol_id_m[];
typedef struct proposal_substructure_t proposal_substructure_t;
return SUCCESS;
}
+/**
+ * Implementation of protected_ike_sa_t.destroy.
+ */
+static void reset_message_buffers (private_ike_sa_t *this)
+{
+ this->logger->log(this->logger, CONTROL|MOST, "Reset message counters and destroy stored messages");
+ /* destroy stored requested message */
+ if (this->last_requested_message != NULL)
+ {
+ this->last_requested_message->destroy(this->last_requested_message);
+ this->last_requested_message = NULL;
+ }
+
+ /* destroy stored responded messages */
+ if (this->last_responded_message != NULL)
+ {
+ this->last_responded_message->destroy(this->last_responded_message);
+ this->last_responded_message = NULL;
+ }
+
+ this->message_id_out = 0;
+ this->message_id_in = 0;
+}
/**
- * Implements protected_ike_sa_t.destroy.
+ * Implementation of protected_ike_sa_t.destroy.
*/
static void destroy (private_ike_sa_t *this)
{
this->protected.set_new_state = (void (*) (protected_ike_sa_t *,state_t *)) set_new_state;
this->protected.get_crypter_initiator = (crypter_t *(*) (protected_ike_sa_t *)) get_crypter_initiator;
this->protected.get_signer_initiator = (signer_t *(*) (protected_ike_sa_t *)) get_signer_initiator;
+ this->protected.reset_message_buffers = (void (*) (protected_ike_sa_t *)) reset_message_buffers;
/* private functions */
this->resend_last_reply = resend_last_reply;
*/
signer_t *(*get_signer_initiator) (protected_ike_sa_t *this);
+ /**
+ * Resets message id counters and does destroy stored received and sent messages.
+ *
+ * @param this calling object
+ */
+ void (*reset_message_buffers) (protected_ike_sa_t *this);
};
#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/auth_payload.h>
#include <encoding/payloads/ts_payload.h>
#include <transforms/diffie_hellman.h>
#include <sa/states/ike_auth_requested.h>
+#include <sa/states/initiator_init.h>
typedef struct private_ike_sa_init_requested_t private_ike_sa_init_requested_t;
this->logger->log(this->logger, CONTROL|MORE, "Processing payload %s", mapping_find(payload_type_m, payload->get_type(payload)));
switch (payload->get_type(payload))
{
+ case NOTIFY:
+ {
+ notify_payload_t *notify_payload = (notify_payload_t *) payload;
+
+
+ this->logger->log(this->logger, CONTROL|MORE, "Process notify type %s for protocol %s",
+ mapping_find(notify_message_type_m, notify_payload->get_notify_message_type(notify_payload)),
+ mapping_find(protocol_id_m, notify_payload->get_protocol_id(notify_payload)));
+
+ if (notify_payload->get_protocol_id(notify_payload) != IKE)
+ {
+ this->logger->log(this->logger, ERROR | MORE, "Notify reply not for IKE protocol.");
+ payloads->destroy(payloads);
+ return FAILED;
+ }
+ switch (notify_payload->get_notify_message_type(notify_payload))
+ {
+ case NO_PROPOSAL_CHOSEN:
+ {
+ this->logger->log(this->logger, ERROR, "Peer didn't choose a proposal!!!");
+ payloads->destroy(payloads);
+ return DELETE_ME;
+ }
+ case INVALID_KE_PAYLOAD:
+ {
+ initiator_init_t *initiator_init_state;
+ u_int16_t new_dh_group_priority;
+
+ this->logger->log(this->logger, ERROR, "Selected DH group is not the one in the proposal selected by the responder!");
+ payloads->destroy(payloads);
+ /* Going to change state back to initiator_init_t */
+ this->logger->log(this->logger, CONTROL|MOST, "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|MORE, "Changed state of IKE_SA from %s to %s", mapping_find(ike_sa_state_m,INITIATOR_INIT),mapping_find(ike_sa_state_m,IKE_SA_INIT_REQUESTED) );
+
+ this->logger->log(this->logger, CONTROL|MOST, "Destroy old sate object");
+ this->logger->log(this->logger, CONTROL|MOST, "Going to retry initialization of connection");
+ new_dh_group_priority = this->dh_group_priority + 1;
+
+ this->public.state_interface.destroy(&(this->public.state_interface));
+ return (initiator_init_state->retry_initiate_connection (initiator_init_state,new_dh_group_priority));
+ }
+ default:
+ {
+ /*
+ * If an unrecognized Notify type is received, the IKE_SA gets destroyed.
+ *
+ */
+
+ this->logger->log(this->logger, ERROR, "Notify type %s not recognized in state ike_sa_init_requested.",
+ mapping_find(notify_message_type_m,notify_payload->get_notify_message_type(notify_payload)));
+ payloads->destroy(payloads);
+ return DELETE_ME;
+ }
+ }
+
/**
* TODO check for notify of type
*
*
* call destroy after state change not destroy_after_state_change!!!
*/
-
+ }
case SECURITY_ASSOCIATION:
{
sa_payload_t *sa_payload = (sa_payload_t*)payload;
if (status != SUCCESS)
{
this->logger->log(this->logger, ERROR | MORE, "Could not retrieve INIT configuration informations for %s",name);
- return INVALID_ARG;
+ return DELETE_ME;
}
this->ike_sa->set_init_config(this->ike_sa,init_config);
if (status != SUCCESS)
{
this->logger->log(this->logger, ERROR | MORE, "Could not retrieve SA configuration informations for %s",name);
- return INVALID_ARG;
+ return DELETE_ME;
}
this->ike_sa->set_sa_config(this->ike_sa,sa_config);
if (this->dh_group_number == MODP_UNDEFINED)
{
this->logger->log(this->logger, ERROR | MORE, "Diffie hellman group could not be retrieved with priority %d", this->dh_group_priority);
- return INVALID_ARG;
+ return DELETE_ME;
}
/* next step is done in retry_initiate_connection */
message_t *message;
packet_t *packet;
status_t status;
+ ike_sa_id_t *ike_sa_id;
+
+ this->dh_group_priority = dh_group_priority;
init_config = this->ike_sa->get_init_config(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);
+
this->dh_group_number = init_config->get_dh_group_number(init_config,dh_group_priority);
if (this->dh_group_number == MODP_UNDEFINED)
{
- this->logger->log(this->logger, ERROR | MORE, "Diffie hellman group could not be retrieved with priority %d", this->dh_group_priority);
- return INVALID_ARG;
+ this->logger->log(this->logger, ERROR | MORE, "Diffie hellman group could not be retrieved with priority %d", dh_group_priority);
+ return DELETE_ME;
}
this->diffie_hellman = diffie_hellman_create(this->dh_group_number);
{
this->logger->log(this->logger, ERROR, "could not generate packet from message");
message->destroy(message);
- return status;
+ return DELETE_ME;
}
this->logger->log(this->logger, CONTROL|MOST, "Add packet to global send queue");
/* state can now be changed */
this->logger->log(this->logger, CONTROL|MOST, "Create next state object");
- next_state = ike_sa_init_requested_create(this->ike_sa, this->dh_group_number, this->diffie_hellman, this->sent_nonce);
+ next_state = ike_sa_init_requested_create(this->ike_sa, this->dh_group_priority, this->diffie_hellman, this->sent_nonce);
/* last message can now be set */
status = this->ike_sa->set_last_requested_message(this->ike_sa, message);
this->logger->log(this->logger, ERROR, "Could not set last requested message");
(next_state->state_interface).destroy(&(next_state->state_interface));
message->destroy(message);
- return status;
+ return DELETE_ME;
}
/* state can now be changed */
/**
* Implements state_t.get_state
*/
-static status_t process_message(private_initiator_init_t *this, message_t *message, state_t **new_state)
+static status_t process_message(private_initiator_init_t *this, message_t *message)
{
- *new_state = (state_t *) this;
this->logger->log(this->logger, ERROR|MORE, "In state INITIATOR_INIT no message is processed");
return FAILED;
}
#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 <transforms/diffie_hellman.h>
* @param this calling object
*/
void (*destroy_after_state_change) (private_responder_init_t *this);
+
+ /**
+ * Sends a IKE_SA_INIT reply with a notify payload.
+ *
+ * @param this calling object
+ * @param type type of notify message
+ * @param data data of notify message
+ */
+ void (*send_notify_reply) (private_responder_init_t *this,notify_message_type_t type, chunk_t data);
+
};
/**
{
this->logger->log(this->logger, ERROR | MORE, "No proposal of suggested proposals selected");
payloads->destroy(payloads);
+ this->send_notify_reply(this,NO_PROPOSAL_CHOSEN,CHUNK_INITIALIZER);
return DELETE_ME;
}
}
if (this->dh_group_number != group)
{
- /* group not same as selected one */
+ 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, ERROR | MORE, "Diffie hellman group not as in selected proposal!");
+ payloads->destroy(payloads);
- /**
- * TODO send notify reply
- */
+ accepted_group = htons(this->dh_group_number);
+ accepted_group_chunk.ptr = (u_int8_t*) &(accepted_group);
+ accepted_group_chunk.len = 2;
+ this->send_notify_reply(this,INVALID_KE_PAYLOAD,accepted_group_chunk);
+ return DELETE_ME;
}
/* create diffie hellman object to handle DH exchange */
return RESPONDER_INIT;
}
+/**
+ * Implementation of private_initiator_init_t.send_notify_reply.
+ */
+static void send_notify_reply (private_responder_init_t *this,notify_message_type_t type, chunk_t data)
+{
+ notify_payload_t *payload;
+ message_t *response;
+ packet_t *packet;
+ status_t status;
+
+ this->logger->log(this->logger, CONTROL|MOST, "Going to build message with notify payload");
+ /* set up the reply */
+ this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response);
+ payload = notify_payload_create_from_protocol_and_type(IKE,type);
+ if ((data.ptr != NULL) && (data.len > 0))
+ {
+ this->logger->log(this->logger, CONTROL|MOST, "Add Data to notify payload");
+ payload->set_notification_data(payload,data);
+ }
+
+ this->logger->log(this->logger, CONTROL|MOST, "Add Notify payload to message");
+ response->add_payload(response,(payload_t *) payload);
+
+ /* generate packet */
+ this->logger->log(this->logger, CONTROL|MOST, "Gnerate packet from message");
+ status = response->generate(response, NULL, NULL, &packet);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "Could not generate packet from message");
+ return;
+ }
+
+ this->logger->log(this->logger, CONTROL|MOST, "Add packet to global send queue");
+ charon->send_queue->add(charon->send_queue, packet);
+ this->logger->log(this->logger, CONTROL|MOST, "Destroy message");
+ response->destroy(response);
+}
+
/**
* Implements state_t.get_state
*/
this->build_ke_payload = build_ke_payload;
this->build_nonce_payload = build_nonce_payload;
this->destroy_after_state_change = destroy_after_state_change;
+ this->send_notify_reply = send_notify_reply;
/* private data */
this->ike_sa = ike_sa;
this->logger = this->ike_sa->get_logger(this->ike_sa);
this->sent_nonce = CHUNK_INITIALIZER;
this->received_nonce = CHUNK_INITIALIZER;
+ this->dh_group_number = MODP_UNDEFINED;
return &(this->public);
}
this->worker_logger->log(this->worker_logger, ERROR, "IKE version %d.%d not supported",
message->get_major_version(message),
message->get_minor_version(message));
- /* Todo send notify */
+ /*
+ * TODO send notify reply of type INVALID_MAJOR_VERSION
+ */
}
message->get_ike_sa_id(message, &ike_sa_id);
this->worker_logger->log(this->worker_logger, ERROR, "IKE SA could not be checked out");
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;
}
status = ike_sa->process_message(ike_sa, message);
- if (status != SUCCESS)
+ if ((status != SUCCESS) && (status != DELETE_ME))
{
this->worker_logger->log(this->worker_logger, ERROR, "message could not be processed by IKE SA");
}
- this->worker_logger->log(this->worker_logger, CONTROL|MOST, "checking in IKE SA %lld:%lld, role %s",
+ this->worker_logger->log(this->worker_logger, CONTROL|MOST, "%s IKE SA %lld:%lld, role %s",
+ (status == DELETE_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");