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:
@@ -47,7 +47,7 @@ struct private_authenticator_t {
|
||||
/**
|
||||
* Assigned IKE_SA. Needed to get objects of type prf_t and logger_t.
|
||||
*/
|
||||
protected_ike_sa_t *ike_sa;
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* PRF taken from the IKE_SA.
|
||||
@@ -404,7 +404,7 @@ static void destroy (private_authenticator_t *this)
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
authenticator_t *authenticator_create(protected_ike_sa_t *ike_sa)
|
||||
authenticator_t *authenticator_create(ike_sa_t *ike_sa)
|
||||
{
|
||||
private_authenticator_t *this = malloc_thing(private_authenticator_t);
|
||||
|
||||
|
||||
@@ -120,19 +120,12 @@ struct authenticator_t {
|
||||
/**
|
||||
* @brief Creates an authenticator object.
|
||||
*
|
||||
* @warning: The following functions of the assigned protected_ike_sa_t object
|
||||
* must return a valid value:
|
||||
* - protected_ike_sa_t.get_policy
|
||||
* - protected_ike_sa_t.get_prf
|
||||
* - protected_ike_sa_t.get_logger
|
||||
* This preconditions are not given in IKE_SA states INITIATOR_INIT or RESPONDER_INIT!
|
||||
*
|
||||
* @param ike_sa object of type protected_ike_sa_t
|
||||
* @param ike_sa associated ike_sa
|
||||
*
|
||||
* @return authenticator_t object
|
||||
*
|
||||
* @ingroup sa
|
||||
*/
|
||||
authenticator_t *authenticator_create(protected_ike_sa_t *ike_sa);
|
||||
authenticator_t *authenticator_create(ike_sa_t *ike_sa);
|
||||
|
||||
#endif /* AUTHENTICATOR_H_ */
|
||||
|
||||
@@ -858,6 +858,7 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
|
||||
this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
|
||||
this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add;
|
||||
this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update;
|
||||
this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,int,int))update_hosts;
|
||||
this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
|
||||
this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
|
||||
this->public.set_rekeyed = (void (*)(child_sa_t*))set_rekeyed;
|
||||
|
||||
+875
-1050
File diff suppressed because it is too large
Load Diff
+293
-529
@@ -29,7 +29,6 @@
|
||||
#include <encoding/payloads/proposal_substructure.h>
|
||||
#include <sa/ike_sa_id.h>
|
||||
#include <sa/child_sa.h>
|
||||
#include <sa/states/state.h>
|
||||
#include <config/configuration.h>
|
||||
#include <utils/logger.h>
|
||||
#include <utils/randomizer.h>
|
||||
@@ -40,25 +39,53 @@
|
||||
#include <config/policies/policy.h>
|
||||
#include <utils/logger.h>
|
||||
|
||||
|
||||
typedef enum ike_sa_state_t ike_sa_state_t;
|
||||
|
||||
/**
|
||||
* Nonce size in bytes for nonces sending to other peer.
|
||||
*
|
||||
* @warning Nonce size MUST be between 16 and 256 bytes.
|
||||
* @brief State of an IKE_SA.
|
||||
*
|
||||
* @ingroup sa
|
||||
*/
|
||||
#define NONCE_SIZE 16
|
||||
enum ike_sa_state_t {
|
||||
|
||||
/**
|
||||
* IKE_SA just got created, but is not initiating nor responding yet.
|
||||
*/
|
||||
SA_CREATED,
|
||||
|
||||
/**
|
||||
* IKE_SA gets initiated actively or passively
|
||||
*/
|
||||
SA_CONNECTING,
|
||||
|
||||
/**
|
||||
* IKE_SA is fully established
|
||||
*/
|
||||
SA_ESTABLISHED,
|
||||
|
||||
/**
|
||||
* IKE_SA is in progress of deletion
|
||||
*/
|
||||
SA_DELETING,
|
||||
};
|
||||
|
||||
/**
|
||||
* String mappings for ike_sa_state_t.
|
||||
*/
|
||||
extern mapping_t ike_sa_state_m[];
|
||||
|
||||
|
||||
typedef struct ike_sa_t ike_sa_t;
|
||||
|
||||
/**
|
||||
* @brief Class ike_sa_t representing an IKE_SA.
|
||||
*
|
||||
* An object of this type is managed by an ike_sa_manager_t object
|
||||
* and represents an IKE_SA. Message processing is split up in different states.
|
||||
* They will handle all related things for the state they represent.
|
||||
*
|
||||
* @brief Class ike_sa_t representing an IKE_SA.
|
||||
*
|
||||
* An IKE_SA contains crypto information related to a connection
|
||||
* with a peer. It contains multiple IPsec CHILD_SA, for which
|
||||
* it is responsible. All traffic is handled by an IKE_SA, using
|
||||
* transactions.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - ike_sa_create()
|
||||
*
|
||||
@@ -66,55 +93,6 @@ typedef struct ike_sa_t ike_sa_t;
|
||||
*/
|
||||
struct ike_sa_t {
|
||||
|
||||
/**
|
||||
* @brief Processes a incoming IKEv2-Message of type message_t.
|
||||
*
|
||||
* @param this ike_sa_t object object
|
||||
* @param[in] message message_t object to process
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
* - DESTROY_ME if this IKE_SA MUST be deleted
|
||||
*/
|
||||
status_t (*process_message) (ike_sa_t *this,message_t *message);
|
||||
|
||||
/**
|
||||
* @brief Initiate a new connection with given connection_t object.
|
||||
*
|
||||
* The connection_t object is owned by the IKE_SA after the call, so
|
||||
* do not modify or destroy it.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param connection connection to initiate
|
||||
* @return
|
||||
* - SUCCESS if initialization started
|
||||
* - FAILED if in wrong state
|
||||
* - DESTROY_ME if initialization failed and IKE_SA MUST be deleted
|
||||
*/
|
||||
status_t (*initiate_connection) (ike_sa_t *this, connection_t *connection);
|
||||
|
||||
/**
|
||||
* @brief Checks whether retransmission is possible.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param message_id ID of the request to retransmit
|
||||
* @return
|
||||
* - TRUE if retransmit is possible
|
||||
* - FALSE if not
|
||||
*/
|
||||
bool (*retransmit_possible) (ike_sa_t *this, u_int32_t message_id);
|
||||
|
||||
/**
|
||||
* @brief Retransmits a request.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param message_id ID of the request to retransmit
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - NOT_FOUND if request doesn't have to be retransmited
|
||||
*/
|
||||
status_t (*retransmit_request) (ike_sa_t *this, u_int32_t message_id);
|
||||
|
||||
/**
|
||||
* @brief Get the id of the SA.
|
||||
*
|
||||
@@ -124,161 +102,37 @@ struct ike_sa_t {
|
||||
* @return ike_sa's ike_sa_id_t
|
||||
*/
|
||||
ike_sa_id_t* (*get_id) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the CHILD_SA with the specified reqid.
|
||||
*
|
||||
* The reqid is a unique ID for a child SA, which is
|
||||
* generated on child SA creation.
|
||||
* Returned child_sa_t object is not cloned!
|
||||
*
|
||||
* @param this calling object
|
||||
* @param reqid reqid of the child SA, as used in the kernel
|
||||
* @return child_sa, or NULL if not found
|
||||
*/
|
||||
child_sa_t* (*get_child_sa) (ike_sa_t *this, u_int32_t reqid);
|
||||
|
||||
/**
|
||||
* @brief Close the CHILD SA with the specified reqid.
|
||||
*
|
||||
* Looks for a CHILD SA owned by this IKE_SA, deletes it and
|
||||
* notify's the remote peer about the delete. The associated
|
||||
* states and policies in the kernel get deleted, if they exist.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param reqid reqid of the child SA, as used in the kernel
|
||||
* @return
|
||||
* - NOT_FOUND, if IKE_SA has no such CHILD_SA
|
||||
* - SUCCESS, if deleted and delete message sent
|
||||
*/
|
||||
status_t (*delete_child_sa) (ike_sa_t *this, u_int32_t reqid);
|
||||
|
||||
/**
|
||||
* @brief Rekey the CHILD SA with the specified reqid.
|
||||
*
|
||||
* Looks for a CHILD SA owned by this IKE_SA, and start the rekeing.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param spi security parameter index identifying the SA to rekey
|
||||
* @return
|
||||
* - NOT_FOUND, if IKE_SA has no such CHILD_SA
|
||||
* - SUCCESS, if rekeying initiated
|
||||
*/
|
||||
status_t (*rekey_child_sa) (ike_sa_t *this, u_int32_t reqid);
|
||||
|
||||
/**
|
||||
* @brief Get local peer address of the IKE_SA.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return local host_t
|
||||
*/
|
||||
host_t* (*get_my_host) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get remote peer address of the IKE_SA.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return remote host_t
|
||||
*/
|
||||
host_t* (*get_other_host) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get own ID of the IKE_SA.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return local identification_t
|
||||
*/
|
||||
identification_t* (*get_my_id) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get remote ID the IKE_SA.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return remote identification_t
|
||||
*/
|
||||
identification_t* (*get_other_id) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the connection of the IKE_SA.
|
||||
*
|
||||
* The internal used connection specification
|
||||
* can be queried to get some data of an IKE_SA.
|
||||
* The connection is still owned to the IKE_SA
|
||||
* and must not be manipulated.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return connection_t
|
||||
*/
|
||||
connection_t* (*get_connection) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Query NAT detection status for local host.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return TRUE if this host is behind NAT
|
||||
*/
|
||||
bool (*is_my_host_behind_nat) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Query NAT detection status for remote host.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return TRUE if other host is behind NAT
|
||||
*/
|
||||
bool (*is_other_host_behind_nat) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Query NAT detection status for any host.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return TRUE if this or other host is behind NAT
|
||||
*/
|
||||
bool (*is_any_host_behind_nat) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Query timeval of last inbound IKE or ESP traffic.
|
||||
* @brief Get the state of the IKE_SA.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return time when the last traffic was seen
|
||||
*/
|
||||
struct timeval (*get_last_traffic_in_tv) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Query timeval of last outbound IKE or ESP traffic.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return time when the last traffic was seen
|
||||
*/
|
||||
struct timeval (*get_last_traffic_out_tv) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the state of type of associated state object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return state of IKE_SA
|
||||
* @return state of the IKE_SA
|
||||
*/
|
||||
ike_sa_state_t (*get_state) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Sends a DPD request to the peer.
|
||||
*
|
||||
* @param this calling object
|
||||
* @brief Set the state of the IKE_SA.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param state state to set for the IKE_SA
|
||||
*/
|
||||
status_t (*send_dpd_request) (ike_sa_t *this);
|
||||
|
||||
void (*set_state) (ike_sa_t *this, ike_sa_state_t ike_sa);
|
||||
|
||||
/**
|
||||
* @brief Log the status of a the ike sa to a logger.
|
||||
* @brief Initiate a new connection.
|
||||
*
|
||||
* The status of the IKE SA and all child SAs is logged.
|
||||
* Supplying NULL as logger uses the internal child_sa logger
|
||||
* to do the logging. The log is only done if the supplied
|
||||
* connection name is NULL or matches the connections name.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param logger logger to use for logging
|
||||
* @param name name of the connection
|
||||
*/
|
||||
void (*log_status) (ike_sa_t *this, logger_t *logger, char *name);
|
||||
* The connection_t object is owned by the IKE_SA after the call, so
|
||||
* do not modify or destroy it.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param connection connection to initiate
|
||||
* @return
|
||||
* - SUCCESS if initialization started
|
||||
* - FAILED if in wrong state
|
||||
* - DESTROY_ME if initialization failed and IKE_SA MUST be deleted
|
||||
*/
|
||||
status_t (*initiate) (ike_sa_t *this, connection_t *connection);
|
||||
|
||||
/**
|
||||
* @brief Initiates the deletion of an IKE_SA.
|
||||
@@ -295,7 +149,238 @@ struct ike_sa_t {
|
||||
* delete (but destroyed).
|
||||
*/
|
||||
status_t (*delete) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Retransmits a request.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param message_id ID of the request to retransmit
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - NOT_FOUND if request doesn't have to be retransmited
|
||||
*/
|
||||
status_t (*retransmit_request) (ike_sa_t *this, u_int32_t message_id);
|
||||
|
||||
/**
|
||||
* @brief Processes a incoming IKEv2-Message.
|
||||
*
|
||||
* Message processing may fail. If a critical failure occurs,
|
||||
* process_message() return DESTROY_ME. Then the caller must
|
||||
* destroy the IKE_SA immediatly, as it is unusable.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param[in] message message to process
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
* - DESTROY_ME if this IKE_SA MUST be deleted
|
||||
*/
|
||||
status_t (*process_message) (ike_sa_t *this,message_t *message);
|
||||
|
||||
/**
|
||||
* @brief Check if NAT traversal is enabled for this IKE_SA.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return TRUE if NAT traversal enabled
|
||||
*/
|
||||
bool (*is_natt_enabled) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Enable NAT detection for this IKE_SA.
|
||||
*
|
||||
* If a Network address translation is detected with
|
||||
* NAT_DETECTION notifys, a SA must switch to ports
|
||||
* 4500. To enable this behavior, call enable_natt().
|
||||
* It is relevant which peer is NATted, this is specified
|
||||
* with the "local" parameter. Call it twice when both
|
||||
* are NATted.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param local TRUE, if we are NATted, FALSE if other
|
||||
*/
|
||||
void (*enable_natt) (ike_sa_t *this, bool local);
|
||||
|
||||
/**
|
||||
* @brief Sends a DPD request to the peer.
|
||||
*
|
||||
* To check if a peer is still alive, periodic
|
||||
* empty INFORMATIONAL messages are sent if no
|
||||
* other traffic was received.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - DESTROY_ME, if peer did not respond
|
||||
*/
|
||||
status_t (*send_dpd) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Sends a keep alive packet.
|
||||
*
|
||||
* To refresh NAT tables in a NAT router
|
||||
* between the peers, periodic empty
|
||||
* UDP packets are sent if no other traffic
|
||||
* was sent.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*send_keepalive) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Log the status of a the ike sa to a logger.
|
||||
*
|
||||
* The status of the IKE SA and all child SAs is logged.
|
||||
* Supplying NULL as logger uses the internal child_sa logger
|
||||
* to do the logging. The log is only done if the supplied
|
||||
* connection name is NULL or matches the connections name.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param logger logger to use for logging
|
||||
* @param name name of the connection
|
||||
*/
|
||||
void (*log_status) (ike_sa_t *this, logger_t *logger, char *name);
|
||||
|
||||
/**
|
||||
* @brief Get the internal stored connection_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to the internal stored connection_t object
|
||||
*/
|
||||
connection_t *(*get_connection) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Set the internal connection object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param connection object of type connection_t
|
||||
*/
|
||||
void (*set_connection) (ike_sa_t *this, connection_t *connection);
|
||||
|
||||
/**
|
||||
* @brief Get the internal stored policy object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to the internal stored policy_t object
|
||||
*/
|
||||
policy_t *(*get_policy) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Set the internal policy_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param policy object of type policy_t
|
||||
*/
|
||||
void (*set_policy) (ike_sa_t *this, policy_t *policy);
|
||||
|
||||
/**
|
||||
* @brief Derive all keys and create the transforms for IKE communication.
|
||||
*
|
||||
* Keys are derived using the diffie hellman secret, nonces and internal
|
||||
* stored SPIs.
|
||||
* Already existing objects get destroyed.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param proposal proposal which contains algorithms to use
|
||||
* @param dh diffie hellman object with shared secret
|
||||
* @param nonce_i initiators nonce
|
||||
* @param nonce_r responders nonce
|
||||
* @param initiator role of this IKE SA (TRUE = originial initiator)
|
||||
*/
|
||||
status_t (*build_transforms) (ike_sa_t *this, proposal_t* proposal,
|
||||
diffie_hellman_t *dh,
|
||||
chunk_t nonce_i, chunk_t nonce_r,
|
||||
bool initiator);
|
||||
|
||||
/**
|
||||
* @brief Get the multi purpose prf.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to prf_t object
|
||||
*/
|
||||
prf_t *(*get_prf) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the prf-object, which is used to derive keys for child SAs.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to prf_t object
|
||||
*/
|
||||
prf_t *(*get_child_prf) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the prf used for authentication of initiator.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to prf_t object
|
||||
*/
|
||||
prf_t *(*get_prf_auth_i) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the prf used for authentication of responder.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to prf_t object
|
||||
*/
|
||||
prf_t *(*get_prf_auth_r) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get a CHILD_SA upon request from the other peer.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param spi spi of the CHILD_SA
|
||||
* @return child_sa, or NULL if none found
|
||||
*/
|
||||
child_sa_t* (*get_child_sa) (ike_sa_t *this, u_int32_t spi);
|
||||
|
||||
/**
|
||||
* @brief Close the CHILD SA with the specified reqid.
|
||||
*
|
||||
* Looks for a CHILD SA owned by this IKE_SA, deletes it and
|
||||
* notify's the remote peer about the delete. The associated
|
||||
* states and policies in the kernel get deleted, if they exist.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param reqid reqid of the child SA, as used in the kernel
|
||||
* @return
|
||||
* - NOT_FOUND, if IKE_SA has no such CHILD_SA
|
||||
* - SUCCESS, if deleted and delete message sent
|
||||
*
|
||||
* @TODO use spi, not reqid
|
||||
*/
|
||||
status_t (*delete_child_sa) (ike_sa_t *this, u_int32_t reqid);
|
||||
|
||||
/**
|
||||
* @brief Rekey the CHILD SA with the specified reqid.
|
||||
*
|
||||
* Looks for a CHILD SA owned by this IKE_SA, and start the rekeing.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param spi security parameter index identifying the SA to rekey
|
||||
* @return
|
||||
* - NOT_FOUND, if IKE_SA has no such CHILD_SA
|
||||
* - SUCCESS, if rekeying initiated
|
||||
*
|
||||
* @TODO use spi, not reqid
|
||||
*/
|
||||
status_t (*rekey_child_sa) (ike_sa_t *this, u_int32_t reqid);
|
||||
|
||||
/**
|
||||
* @brief Associates a child SA to this IKE SA
|
||||
*
|
||||
* @param this calling object
|
||||
* @param child_sa child_sa to add
|
||||
*/
|
||||
void (*add_child_sa) (ike_sa_t *this, child_sa_t *child_sa);
|
||||
|
||||
/**
|
||||
* @brief Destroys a CHILD_SA upon request from the other peer.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param spi inbound spi of the CHILD_SA to destroy
|
||||
* @return outbound spi of the destroyed CHILD_SA
|
||||
*/
|
||||
u_int32_t (*destroy_child_sa) (ike_sa_t *this, u_int32_t spi);
|
||||
|
||||
/**
|
||||
* @brief Destroys a ike_sa_t object.
|
||||
*
|
||||
@@ -304,337 +389,16 @@ struct ike_sa_t {
|
||||
void (*destroy) (ike_sa_t *this);
|
||||
};
|
||||
|
||||
|
||||
typedef struct protected_ike_sa_t protected_ike_sa_t;
|
||||
|
||||
/**
|
||||
* @brief Protected functions of an ike_sa_t object.
|
||||
*
|
||||
* This members are only accessed out from
|
||||
* the various state_t implementations.
|
||||
*
|
||||
* @ingroup sa
|
||||
*/
|
||||
struct protected_ike_sa_t {
|
||||
|
||||
/**
|
||||
* Public interface of an ike_sa_t object.
|
||||
*/
|
||||
ike_sa_t public;
|
||||
|
||||
/**
|
||||
* @brief Build an empty IKEv2-Message and fills in default informations.
|
||||
*
|
||||
* Depending on the type of message (request or response), the message id is
|
||||
* either message_id_out or message_id_in.
|
||||
*
|
||||
* Used in state_t Implementation to build an empty IKEv2-Message.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param type exchange type of new message
|
||||
* @param request TRUE, if message has to be a request
|
||||
* @param message new message is stored at this location
|
||||
*/
|
||||
void (*build_message) (protected_ike_sa_t *this, exchange_type_t type, bool request, message_t **message);
|
||||
|
||||
/**
|
||||
* @brief Get the internal stored connection_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to the internal stored connection_t object
|
||||
*/
|
||||
connection_t *(*get_connection) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Set the internal connection object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param connection object of type connection_t
|
||||
*/
|
||||
void (*set_connection) (protected_ike_sa_t *this, connection_t *connection);
|
||||
|
||||
/**
|
||||
* @brief Get the internal stored policy object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to the internal stored policy_t object
|
||||
*/
|
||||
policy_t *(*get_policy) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Set the internal policy_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param policy object of type policy_t
|
||||
*/
|
||||
void (*set_policy) (protected_ike_sa_t *this,policy_t *policy);
|
||||
|
||||
/**
|
||||
* @brief Derive all keys and create the transforms for IKE communication.
|
||||
*
|
||||
* Keys are derived using the diffie hellman secret, nonces and internal
|
||||
* stored SPIs.
|
||||
* Already existing objects get destroyed.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param proposal proposal which contains algorithms to use
|
||||
* @param dh diffie hellman object with shared secret
|
||||
* @param nonce_i initiators nonce
|
||||
* @param nonce_r responders nonce
|
||||
*/
|
||||
status_t (*build_transforms) (protected_ike_sa_t *this, proposal_t* proposal,
|
||||
diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r);
|
||||
|
||||
/**
|
||||
* @brief Send the next request message.
|
||||
*
|
||||
* Also the first retransmit job is created.
|
||||
*
|
||||
* Last stored requested message gets destroyed. Object gets not cloned!
|
||||
*
|
||||
* @param this calling object
|
||||
* @param message pointer to the message which should be sent
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED if message id is not next expected one
|
||||
*/
|
||||
status_t (*send_request) (protected_ike_sa_t *this,message_t * message);
|
||||
|
||||
/**
|
||||
* @brief Send the next response message.
|
||||
*
|
||||
* Last stored responded message gets destroyed. Object gets not cloned!
|
||||
*
|
||||
* @param this calling object
|
||||
* @param message pointer to the message which should be sent
|
||||
* return
|
||||
* - SUCCESS
|
||||
* - FAILED if message id is not next expected one
|
||||
*/
|
||||
status_t (*send_response) (protected_ike_sa_t *this,message_t * message);
|
||||
|
||||
/**
|
||||
* @brief Send a notify reply message.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param exchange_type type of exchange in which the notify should be wrapped
|
||||
* @param type type of the notify message to send
|
||||
* @param data notification data
|
||||
*/
|
||||
void (*send_notify) (protected_ike_sa_t *this, exchange_type_t exchange_type, notify_message_type_t type, chunk_t data);
|
||||
|
||||
/**
|
||||
* @brief Get the internal stored randomizer_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to the internal randomizer_t object
|
||||
*/
|
||||
randomizer_t *(*get_randomizer) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Set the new state_t object of the IKE_SA object.
|
||||
*
|
||||
* The old state_t object gets not destroyed. It's the callers duty to
|
||||
* make sure old state is destroyed (Normally the old state is the caller).
|
||||
*
|
||||
* @param this calling object
|
||||
* @param state pointer to the new state_t object
|
||||
*/
|
||||
void (*set_new_state) (protected_ike_sa_t *this,state_t *state);
|
||||
|
||||
/**
|
||||
* @brief Set the last replied message id.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param message_id message id
|
||||
*/
|
||||
void (*set_last_replied_message_id) (protected_ike_sa_t *this,u_int32_t message_id);
|
||||
|
||||
/**
|
||||
* @brief Get the internal stored initiator crypter_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to crypter_t object
|
||||
*/
|
||||
crypter_t *(*get_crypter_initiator) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the internal stored initiator signer_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to signer_t object
|
||||
*/
|
||||
signer_t *(*get_signer_initiator) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the internal stored responder crypter_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to crypter_t object
|
||||
*/
|
||||
crypter_t *(*get_crypter_responder) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the internal stored responder signer object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to signer_t object
|
||||
*/
|
||||
signer_t *(*get_signer_responder) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the multi purpose prf.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to prf_t object
|
||||
*/
|
||||
prf_t *(*get_prf) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the prf-object, which is used to derive keys for child SAs.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to prf_t object
|
||||
*/
|
||||
prf_t *(*get_child_prf) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the prf used for authentication of initiator.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to prf_t object
|
||||
*/
|
||||
prf_t *(*get_prf_auth_i) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the prf used for authentication of responder.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return pointer to prf_t object
|
||||
*/
|
||||
prf_t *(*get_prf_auth_r) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Associates a child SA to this IKE SA
|
||||
*
|
||||
* @param this calling object
|
||||
* @param child_sa child_sa to add
|
||||
*/
|
||||
void (*add_child_sa) (protected_ike_sa_t *this, child_sa_t *child_sa);
|
||||
|
||||
/**
|
||||
* @brief Destroys a CHILD_SA upon request from the other peer.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param spi inbound spi of the CHILD_SA to destroy
|
||||
* @return outbound spi of the destroyed CHILD_SA
|
||||
*/
|
||||
u_int32_t (*destroy_child_sa) (protected_ike_sa_t *this, u_int32_t spi);
|
||||
|
||||
/**
|
||||
* @brief Get a CHILD_SA upon request from the other peer.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param spi spi of the CHILD_SA
|
||||
* @return child_sa, or NULL if none found
|
||||
*/
|
||||
child_sa_t* (*get_child_sa) (protected_ike_sa_t *this, u_int32_t spi);
|
||||
|
||||
/**
|
||||
* @brief establish the IKE SA
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*establish) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the last responded message.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return
|
||||
* - last received as message_t object
|
||||
* - NULL if no last request available
|
||||
*/
|
||||
message_t *(*get_last_responded_message) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the last requested message.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return
|
||||
* - last sent as message_t object
|
||||
* - NULL if no last request available
|
||||
*/
|
||||
message_t *(*get_last_requested_message) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Resets message counters and does destroy stored received and sent messages.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*reset_message_buffers) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Set NAT detection status for local host.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param nat if TRUE, local host is behing NAT
|
||||
*/
|
||||
void (*set_my_host_behind_nat) (protected_ike_sa_t *this, bool nat);
|
||||
|
||||
/**
|
||||
* @brief Set NAT detection status for remote host.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param nat if TRUE, remote host is behing NAT
|
||||
*/
|
||||
void (*set_other_host_behind_nat) (protected_ike_sa_t *this, bool nat);
|
||||
|
||||
/**
|
||||
* @brief Generate NAT-D payload hash.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param spi_i IKE SPI of initiator
|
||||
* @param spi_r IKE SPI of responder
|
||||
* @param host address and port of the host/interface
|
||||
* @return chunk containing calculated NAT-D hash
|
||||
*/
|
||||
chunk_t (*generate_natd_hash) (protected_ike_sa_t *this, u_int64_t spi_i, u_int64_t spi_r, host_t *host);
|
||||
|
||||
/**
|
||||
* @brief Dynamically update hosts on the associated connection.
|
||||
*
|
||||
* Warning: me and other host are cloned.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param me local address and port
|
||||
* @param other remote address and port
|
||||
*/
|
||||
status_t (*update_connection_hosts) (protected_ike_sa_t *this, host_t *me, host_t *other);
|
||||
|
||||
/**
|
||||
* @brief Return the message id of the last DPD message
|
||||
*
|
||||
* @param this calling object
|
||||
* @return the messages id
|
||||
*/
|
||||
u_int32_t (*get_last_dpd_message_id) (protected_ike_sa_t *this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Creates an ike_sa_t object with a specific ID.
|
||||
*
|
||||
* @warning the Content of internal ike_sa_id_t object can change over time
|
||||
* e.g. when a IKE_SA_INIT has been finished.
|
||||
*
|
||||
* @param[in] ike_sa_id ike_sa_id_t object to associate with new IKE_SA.
|
||||
* The object is internal getting cloned
|
||||
* and so has to be destroyed by the caller.
|
||||
* The ID gets cloned internally.
|
||||
*
|
||||
* @param[in] ike_sa_id ike_sa_id_t object to associate with new IKE_SA
|
||||
* @return ike_sa_t object
|
||||
*
|
||||
* @ingroup sa
|
||||
*/
|
||||
ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id);
|
||||
ike_sa_t *ike_sa_create(ike_sa_id_t *ike_sa_id);
|
||||
|
||||
#endif /*IKE_SA_H_*/
|
||||
|
||||
@@ -181,5 +181,5 @@ ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi,
|
||||
this->responder_spi = responder_spi;
|
||||
this->is_initiator_flag = is_initiator_flag;
|
||||
|
||||
return (&this->public);
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ struct private_ike_sa_manager_t {
|
||||
status_t (*get_entry_by_sa) (private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry);
|
||||
|
||||
/**
|
||||
* @brief Felete an entry from the linked list.
|
||||
* @brief Delete an entry from the linked list.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param entry entry to delete
|
||||
@@ -229,10 +229,13 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike
|
||||
if (current->ike_sa_id->get_responder_spi(current->ike_sa_id) == 0)
|
||||
{
|
||||
/* seems to be a half ready ike_sa */
|
||||
if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) == ike_sa_id->get_initiator_spi(ike_sa_id))
|
||||
&& (ike_sa_id->is_initiator(ike_sa_id) == current->ike_sa_id->is_initiator(current->ike_sa_id)))
|
||||
if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) ==
|
||||
ike_sa_id->get_initiator_spi(ike_sa_id)) &&
|
||||
(ike_sa_id->is_initiator(ike_sa_id) ==
|
||||
current->ike_sa_id->is_initiator(current->ike_sa_id)))
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "found entry by initiator spi %d",
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2,
|
||||
"found entry by initiator spi %d",
|
||||
ike_sa_id->get_initiator_spi(ike_sa_id));
|
||||
*entry = current;
|
||||
status = SUCCESS;
|
||||
@@ -241,8 +244,10 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike
|
||||
}
|
||||
else if (ike_sa_id->get_responder_spi(ike_sa_id) == 0)
|
||||
{
|
||||
if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) == ike_sa_id->get_initiator_spi(ike_sa_id))
|
||||
&& (ike_sa_id->is_initiator(ike_sa_id) == current->ike_sa_id->is_initiator(current->ike_sa_id)))
|
||||
if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) ==
|
||||
ike_sa_id->get_initiator_spi(ike_sa_id)) &&
|
||||
(ike_sa_id->is_initiator(ike_sa_id) ==
|
||||
current->ike_sa_id->is_initiator(current->ike_sa_id)))
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "found entry by initiator spi %d",
|
||||
ike_sa_id->get_initiator_spi(ike_sa_id));
|
||||
@@ -315,7 +320,8 @@ static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *ent
|
||||
iterator->current(iterator, (void**)¤t);
|
||||
if (current == entry)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "found entry by pointer. Going to delete it.");
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2,
|
||||
"found entry by pointer. Going to delete it");
|
||||
iterator->remove(iterator);
|
||||
entry->destroy(entry);
|
||||
status = SUCCESS;
|
||||
@@ -355,6 +361,11 @@ static void create_and_checkout(private_ike_sa_manager_t *this,ike_sa_t **ike_sa
|
||||
/* create entry */
|
||||
new_ike_sa_entry = ike_sa_entry_create(new_ike_sa_id);
|
||||
new_ike_sa_id->destroy(new_ike_sa_id);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2,
|
||||
"created IKE_SA %llx:%llx, role %s",
|
||||
new_ike_sa_id->get_initiator_spi(new_ike_sa_id),
|
||||
new_ike_sa_id->get_responder_spi(new_ike_sa_id),
|
||||
new_ike_sa_id->is_initiator(new_ike_sa_id) ? "initiator" : "responder");
|
||||
|
||||
/* each access is locked */
|
||||
pthread_mutex_lock(&(this->mutex));
|
||||
@@ -362,7 +373,8 @@ static void create_and_checkout(private_ike_sa_manager_t *this,ike_sa_t **ike_sa
|
||||
this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry);
|
||||
|
||||
/* check ike_sa out */
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "new IKE_SA created and added to list of known IKE_SA's");
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1,
|
||||
"new IKE_SA created and added to list of known IKE_SA's");
|
||||
new_ike_sa_entry->checked_out = TRUE;
|
||||
*ike_sa = new_ike_sa_entry->ike_sa;
|
||||
|
||||
@@ -379,6 +391,15 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
|
||||
bool original_initiator;
|
||||
status_t retval;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2,
|
||||
"checkout IKE_SA %llx:%llx, role %s",
|
||||
ike_sa_id->get_initiator_spi(ike_sa_id),
|
||||
ike_sa_id->get_responder_spi(ike_sa_id),
|
||||
ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "%d IKE_SAs in manager",
|
||||
this->ike_sa_list->get_count(this->ike_sa_list));
|
||||
|
||||
/* each access is locked */
|
||||
pthread_mutex_lock(&(this->mutex));
|
||||
|
||||
@@ -399,7 +420,8 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
|
||||
/* can we give this ike_sa out to new requesters?*/
|
||||
if (entry->driveout_new_threads)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "drive out new thread for existing IKE_SA");
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1,
|
||||
"drive out new thread for existing IKE_SA");
|
||||
/* no we can't */
|
||||
retval = NOT_FOUND;
|
||||
}
|
||||
@@ -422,12 +444,14 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
|
||||
{
|
||||
/* we must signal here, others are interested that we leave */
|
||||
pthread_cond_signal(&(entry->condvar));
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "drive out waiting thread for existing IKE_SA");
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1,
|
||||
"drive out waiting thread for existing IKE_SA");
|
||||
retval = NOT_FOUND;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "IKE SA successfully checked out");
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2,
|
||||
"IKE SA successfully checked out");
|
||||
/* ok, this IKE_SA is finally ours */
|
||||
entry->checked_out = TRUE;
|
||||
*ike_sa = entry->ike_sa;
|
||||
@@ -438,7 +462,8 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "IKE SA not stored in known IKE_SA list");
|
||||
this->logger->log(this->logger, ERROR|LEVEL1,
|
||||
"IKE SA not stored in known IKE_SA list");
|
||||
/* looks like there is no such IKE_SA, better luck next time... */
|
||||
/* DON'T use return, we must unlock the mutex! */
|
||||
retval = NOT_FOUND;
|
||||
@@ -469,11 +494,12 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
|
||||
this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry);
|
||||
|
||||
/* check ike_sa out */
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1 ,"IKE_SA added to list of known IKE_SA's");
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1,
|
||||
"IKE_SA added to list of known IKE_SA's");
|
||||
new_ike_sa_entry->checked_out = TRUE;
|
||||
*ike_sa = new_ike_sa_entry->ike_sa;
|
||||
|
||||
retval = CREATED;
|
||||
retval = SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -482,7 +508,7 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
|
||||
/* DON'T use return, we must unlock the mutex! */
|
||||
retval = INVALID_ARG;
|
||||
}
|
||||
|
||||
|
||||
pthread_mutex_unlock(&(this->mutex));
|
||||
/* OK, unlocked... */
|
||||
return retval;
|
||||
@@ -491,7 +517,8 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
|
||||
/**
|
||||
* Implementation of of ike_sa_manager.checkout_by_reqid.
|
||||
*/
|
||||
static status_t checkout_by_reqid(private_ike_sa_manager_t *this, u_int32_t reqid, ike_sa_t **ike_sa)
|
||||
static status_t checkout_by_reqid(private_ike_sa_manager_t *this,
|
||||
u_int32_t reqid, ike_sa_t **ike_sa)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
status_t status = NOT_FOUND;
|
||||
@@ -600,15 +627,16 @@ linked_list_t *get_ike_sa_list_by_name(private_ike_sa_manager_t* this, const cha
|
||||
static void log_status(private_ike_sa_manager_t* this, logger_t* logger, char* name)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
u_int instances;
|
||||
|
||||
pthread_mutex_lock(&(this->mutex));
|
||||
|
||||
iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
|
||||
|
||||
if (iterator->get_count(iterator))
|
||||
instances = this->ike_sa_list->get_count(this->ike_sa_list);
|
||||
if (instances)
|
||||
{
|
||||
logger->log(logger, CONTROL, "Instances:");
|
||||
logger->log(logger, CONTROL, "Instances (%d):", instances);
|
||||
}
|
||||
iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
|
||||
while (iterator->has_next(iterator))
|
||||
{
|
||||
ike_sa_entry_t *entry;
|
||||
@@ -633,6 +661,15 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
|
||||
*/
|
||||
status_t retval;
|
||||
ike_sa_entry_t *entry;
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
|
||||
ike_sa_id = ike_sa->get_id(ike_sa);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2,
|
||||
"checkin IKE_SA %llx:%llx, role %s",
|
||||
ike_sa_id->get_initiator_spi(ike_sa_id),
|
||||
ike_sa_id->get_responder_spi(ike_sa_id),
|
||||
ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
|
||||
|
||||
pthread_mutex_lock(&(this->mutex));
|
||||
|
||||
@@ -649,10 +686,14 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "tried to check in nonexisting IKE_SA");
|
||||
this->logger->log(this->logger, ERROR,
|
||||
"tried to check in nonexisting IKE_SA");
|
||||
/* this SA is no more, this REALLY should not happen */
|
||||
retval = NOT_FOUND;
|
||||
}
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "%d IKE_SAs in manager now",
|
||||
this->ike_sa_list->get_count(this->ike_sa_list));
|
||||
pthread_mutex_unlock(&(this->mutex));
|
||||
return retval;
|
||||
}
|
||||
@@ -670,6 +711,14 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik
|
||||
*/
|
||||
ike_sa_entry_t *entry;
|
||||
status_t retval;
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
|
||||
ike_sa_id = ike_sa->get_id(ike_sa);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2,
|
||||
"checkin and destroy IKE_SA %llx:%llx, role %s",
|
||||
ike_sa_id->get_initiator_spi(ike_sa_id),
|
||||
ike_sa_id->get_responder_spi(ike_sa_id),
|
||||
ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
|
||||
|
||||
pthread_mutex_lock(&(this->mutex));
|
||||
|
||||
@@ -690,12 +739,14 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik
|
||||
}
|
||||
/* ok, we are alone now, no threads waiting in the entry's condvar */
|
||||
this->delete_entry(this, entry);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "check-in and destroy of IKE_SA successful");
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1,
|
||||
"check-in and destroy of IKE_SA successful");
|
||||
retval = SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger,ERROR, "tried to check-in and delete nonexisting IKE_SA");
|
||||
this->logger->log(this->logger,ERROR,
|
||||
"tried to check-in and delete nonexisting IKE_SA");
|
||||
retval = NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -715,9 +766,15 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
|
||||
*/
|
||||
ike_sa_entry_t *entry;
|
||||
status_t retval;
|
||||
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2,
|
||||
"delete IKE_SA %llx:%llx, role %s",
|
||||
ike_sa_id->get_initiator_spi(ike_sa_id),
|
||||
ike_sa_id->get_responder_spi(ike_sa_id),
|
||||
ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
|
||||
|
||||
pthread_mutex_lock(&(this->mutex));
|
||||
|
||||
|
||||
if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
|
||||
{
|
||||
/* we try a delete. If it succeeds, our job is done here. The
|
||||
@@ -725,11 +782,13 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
|
||||
*/
|
||||
if (entry->ike_sa->delete(entry->ike_sa) == SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "initiated delete for IKE_SA");
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1,
|
||||
"initiated delete for IKE_SA");
|
||||
}
|
||||
/* but if the IKE SA is not in a state where the deletion is negotiated with
|
||||
* the other peer, we can destroy the IKE SA on our own. For this, we must
|
||||
* be sure that really NO other threads are waiting for this SA...
|
||||
/* but if the IKE SA is not in a state where the deletion is
|
||||
* negotiated with the other peer, we can destroy the IKE SA on our own.
|
||||
* For this, we must be sure that really NO other threads are
|
||||
* waiting for this SA...
|
||||
*/
|
||||
else
|
||||
{
|
||||
@@ -740,7 +799,8 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
|
||||
{
|
||||
/* wake up all */
|
||||
pthread_cond_broadcast(&(entry->condvar));
|
||||
/* and the nice thing, they will wake us again when their work is done */
|
||||
/* and the nice thing, they will wake us again when their work
|
||||
* is done */
|
||||
pthread_cond_wait(&(entry->condvar), &(this->mutex));
|
||||
}
|
||||
/* ok, we are alone now, no threads waiting in the entry's condvar */
|
||||
@@ -751,7 +811,8 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger,ERROR, "tried to delete nonexisting IKE_SA");
|
||||
this->logger->log(this->logger,ERROR,
|
||||
"tried to delete nonexisting IKE_SA");
|
||||
retval = NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -770,13 +831,12 @@ static void destroy(private_ike_sa_manager_t *this)
|
||||
ike_sa_entry_t *entry;
|
||||
|
||||
pthread_mutex_lock(&(this->mutex));
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "going to destroy IKE_SA manager and all managed IKE_SA's");
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1,
|
||||
"going to destroy IKE_SA manager and all managed IKE_SA's");
|
||||
/* Step 1: drive out all waiting threads */
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2,
|
||||
"set driveout flags for all stored IKE_SA's");
|
||||
iterator = list->create_iterator(list, TRUE);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "set driveout flags for all stored IKE_SA's");
|
||||
while (iterator->has_next(iterator))
|
||||
{
|
||||
iterator->current(iterator, (void**)&entry);
|
||||
@@ -784,8 +844,8 @@ static void destroy(private_ike_sa_manager_t *this)
|
||||
entry->driveout_new_threads = TRUE;
|
||||
entry->driveout_waiting_threads = TRUE;
|
||||
}
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "wait for all threads to leave IKE_SA's");
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2,
|
||||
"wait for all threads to leave IKE_SA's");
|
||||
/* Step 2: wait until all are gone */
|
||||
iterator->reset(iterator);
|
||||
while (iterator->has_next(iterator))
|
||||
|
||||
@@ -1,435 +0,0 @@
|
||||
/**
|
||||
* @file create_child_sa_requested.c
|
||||
*
|
||||
* @brief State after a CREATE_CHILD_SA request was sent.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "create_child_sa_requested.h"
|
||||
|
||||
#include <sa/child_sa.h>
|
||||
#include <sa/states/delete_ike_sa_requested.h>
|
||||
#include <sa/states/ike_sa_established.h>
|
||||
#include <encoding/payloads/ts_payload.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <utils/logger_manager.h>
|
||||
|
||||
|
||||
typedef struct private_create_child_sa_requested_t private_create_child_sa_requested_t;
|
||||
|
||||
/**
|
||||
* Private data of a create_child_sa_requested_t object.
|
||||
*/
|
||||
struct private_create_child_sa_requested_t {
|
||||
/**
|
||||
* Public interface of create_child_sa_requested_t.
|
||||
*/
|
||||
create_child_sa_requested_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
protected_ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* nonce chosen by initiator
|
||||
*/
|
||||
chunk_t nonce_i;
|
||||
|
||||
/**
|
||||
* nonce chosen by the responder
|
||||
*/
|
||||
chunk_t nonce_r;
|
||||
|
||||
/**
|
||||
* Policy to use for new child_sa
|
||||
*/
|
||||
policy_t *policy;
|
||||
|
||||
/**
|
||||
* Proposal negotiated
|
||||
*/
|
||||
proposal_t *proposal;
|
||||
|
||||
/**
|
||||
* Negotiated list of traffic selectors for local site
|
||||
*/
|
||||
linked_list_t *my_ts;
|
||||
|
||||
/**
|
||||
* Negotiated list of traffic selectors for remote site
|
||||
*/
|
||||
linked_list_t *other_ts;
|
||||
|
||||
/**
|
||||
* Child SA to create
|
||||
*/
|
||||
child_sa_t *child_sa;
|
||||
|
||||
/**
|
||||
* Reqid of the old CHILD_SA, when rekeying
|
||||
*/
|
||||
u_int32_t reqid;
|
||||
|
||||
/**
|
||||
* Assigned logger.
|
||||
*
|
||||
* Is logger of ike_sa!
|
||||
*/
|
||||
logger_t *logger;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of private_create_child_sa_requested_t.process_sa_payload.
|
||||
*/
|
||||
static status_t process_sa_payload(private_create_child_sa_requested_t *this, sa_payload_t *sa_payload)
|
||||
{
|
||||
proposal_t *proposal, *proposal_tmp;
|
||||
linked_list_t *proposal_list;
|
||||
|
||||
/* get his selected proposal */
|
||||
proposal_list = sa_payload->get_proposals(sa_payload);
|
||||
/* check count of proposals */
|
||||
if (proposal_list->get_count(proposal_list) == 0)
|
||||
{
|
||||
/* no proposal? we accept this, but no child sa is built */
|
||||
this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA reply contained no proposals. CHILD_SA not created");
|
||||
proposal_list->destroy(proposal_list);
|
||||
return FAILED;
|
||||
}
|
||||
if (proposal_list->get_count(proposal_list) > 1)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA reply contained %d proposals. Aborting",
|
||||
proposal_list->get_count(proposal_list));
|
||||
while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
|
||||
{
|
||||
proposal->destroy(proposal);
|
||||
}
|
||||
proposal_list->destroy(proposal_list);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* we have to re-check here if other's selection is valid */
|
||||
proposal = this->policy->select_proposal(this->policy, proposal_list);
|
||||
/* list not needed anymore */
|
||||
while (proposal_list->remove_last(proposal_list, (void**)&proposal_tmp) == SUCCESS)
|
||||
{
|
||||
proposal_tmp->destroy(proposal_tmp);
|
||||
}
|
||||
proposal_list->destroy(proposal_list);
|
||||
/* got a match? */
|
||||
if (proposal == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA reply contained a not offered proposal. Aborting");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* apply proposal */
|
||||
this->proposal = proposal;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_create_child_sa_requested_t.process_ts_payload.
|
||||
*/
|
||||
static status_t process_ts_payload(private_create_child_sa_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload)
|
||||
{
|
||||
linked_list_t *ts_received, *ts_selected;
|
||||
traffic_selector_t *ts;
|
||||
|
||||
/* get ts form payload */
|
||||
ts_received = ts_payload->get_traffic_selectors(ts_payload);
|
||||
/* select ts depending on payload type */
|
||||
if (ts_initiator)
|
||||
{
|
||||
ts_selected = this->policy->select_my_traffic_selectors(this->policy, ts_received);
|
||||
this->my_ts = ts_selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts_selected = this->policy->select_other_traffic_selectors(this->policy, ts_received);
|
||||
this->other_ts = ts_selected;
|
||||
}
|
||||
/* check if the responder selected valid proposals */
|
||||
if (ts_selected->get_count(ts_selected) != ts_received->get_count(ts_received))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained not offered traffic selectors.");
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
ts->destroy(ts);
|
||||
}
|
||||
ts_received->destroy(ts_received);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_create_child_sa_requested_t.process_nonce_payload.
|
||||
*/
|
||||
static status_t process_nonce_payload(private_create_child_sa_requested_t *this, nonce_payload_t *nonce_request)
|
||||
{
|
||||
this->nonce_r = nonce_request->get_nonce(nonce_request);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a CREATE_CHILD_SA response
|
||||
*/
|
||||
static status_t process_message(private_create_child_sa_requested_t *this, message_t *response)
|
||||
{
|
||||
ts_payload_t *tsi_request = NULL, *tsr_request = NULL;
|
||||
sa_payload_t *sa_request = NULL;
|
||||
nonce_payload_t *nonce_request = NULL;
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
iterator_t *payloads;
|
||||
crypter_t *crypter;
|
||||
signer_t *signer;
|
||||
status_t status;
|
||||
chunk_t seed;
|
||||
prf_plus_t *prf_plus;
|
||||
child_sa_t *old_child_sa;
|
||||
|
||||
this->policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
if (response->get_exchange_type(response) != CREATE_CHILD_SA)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state create_child_sa_requested",
|
||||
mapping_find(exchange_type_m, response->get_exchange_type(response)));
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (response->get_request(response))
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "CREATE_CHILD_SA requests not allowed state create_child_sa_requested");
|
||||
/* TODO: our state implementation currently can not handle incoming requests cleanly here.
|
||||
* If a request comes in before an outstanding reply, we can not handle it the correct way.
|
||||
* Currently, we create a ESTABLISHED state and let it process the message... But we
|
||||
* need changes in the whole state mechanism.
|
||||
*/
|
||||
state_t *state = (state_t*)ike_sa_established_create(this->ike_sa);
|
||||
state->process_message(state, response);
|
||||
state->destroy(state);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* get signer for verification and crypter for decryption */
|
||||
ike_sa_id = this->ike_sa->public.get_id(&this->ike_sa->public);
|
||||
if (!ike_sa_id->is_initiator(ike_sa_id))
|
||||
{
|
||||
crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
|
||||
signer = this->ike_sa->get_signer_initiator(this->ike_sa);
|
||||
}
|
||||
else
|
||||
{
|
||||
crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
|
||||
signer = this->ike_sa->get_signer_responder(this->ike_sa);
|
||||
}
|
||||
|
||||
/* parse incoming message */
|
||||
status = response->parse_body(response, crypter, signer);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA r decryption failed. Ignoring message");
|
||||
return status;
|
||||
}
|
||||
|
||||
/* iterate over incoming payloads. Message is verified, we can be sure there are the required payloads */
|
||||
payloads = response->get_payload_iterator(response);
|
||||
while (payloads->has_next(payloads))
|
||||
{
|
||||
payload_t *payload;
|
||||
payloads->current(payloads, (void**)&payload);
|
||||
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case SECURITY_ASSOCIATION:
|
||||
{
|
||||
sa_request = (sa_payload_t*)payload;
|
||||
break;
|
||||
}
|
||||
case TRAFFIC_SELECTOR_INITIATOR:
|
||||
{
|
||||
tsi_request = (ts_payload_t*)payload;
|
||||
break;
|
||||
}
|
||||
case TRAFFIC_SELECTOR_RESPONDER:
|
||||
{
|
||||
tsr_request = (ts_payload_t*)payload;
|
||||
break;
|
||||
}
|
||||
case NONCE:
|
||||
{
|
||||
nonce_request = (nonce_payload_t*)payload;
|
||||
break;
|
||||
}
|
||||
case NOTIFY:
|
||||
{
|
||||
/* TODO: handle notifys */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "Ignoring payload %s (%d)",
|
||||
mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* iterator can be destroyed */
|
||||
payloads->destroy(payloads);
|
||||
|
||||
/* check if we have all payloads */
|
||||
if (!(sa_request && nonce_request && tsi_request && tsr_request))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA request did not contain all required payloads. Ignored");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* add payloads to it */
|
||||
status = process_nonce_payload(this, nonce_request);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
response->destroy(response);
|
||||
return status;
|
||||
}
|
||||
status = process_sa_payload(this, sa_request);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
response->destroy(response);
|
||||
return status;
|
||||
}
|
||||
status = process_ts_payload(this, TRUE, tsi_request);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
response->destroy(response);
|
||||
return status;
|
||||
}
|
||||
status = process_ts_payload(this, FALSE, tsr_request);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
response->destroy(response);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* install child SAs for AH and esp */
|
||||
if (!this->proposal)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "Proposal negotiation failed, no CHILD_SA built");
|
||||
this->child_sa->destroy(this->child_sa);
|
||||
this->child_sa = NULL;
|
||||
}
|
||||
else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "Traffic selector negotiation failed, no CHILD_SA built");
|
||||
this->child_sa->destroy(this->child_sa);
|
||||
this->child_sa = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
seed = chunk_alloc(this->nonce_i.len + this->nonce_r.len);
|
||||
memcpy(seed.ptr, this->nonce_i.ptr, this->nonce_i.len);
|
||||
memcpy(seed.ptr + this->nonce_i.len, this->nonce_r.ptr, this->nonce_r.len);
|
||||
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
|
||||
|
||||
this->logger->log_chunk(this->logger, RAW|LEVEL2, "Rekey seed", seed);
|
||||
chunk_free(&seed);
|
||||
|
||||
status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
|
||||
prf_plus->destroy(prf_plus);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
status = this->child_sa->add_policies(this->child_sa, this->my_ts, this->other_ts);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA policy! Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
|
||||
}
|
||||
|
||||
this->ike_sa->set_last_replied_message_id(this->ike_sa, response->get_message_id(response));
|
||||
|
||||
/* create new state */
|
||||
this->ike_sa->set_new_state(this->ike_sa, (state_t*)ike_sa_established_create(this->ike_sa));
|
||||
|
||||
/* if we are rekeying, inform the old child SA that it has been superseeded and
|
||||
* start its delete */
|
||||
if (this->reqid)
|
||||
{
|
||||
old_child_sa = this->ike_sa->public.get_child_sa(&this->ike_sa->public, this->reqid);
|
||||
if (old_child_sa)
|
||||
{
|
||||
old_child_sa->set_rekeyed(old_child_sa);
|
||||
}
|
||||
|
||||
this->ike_sa->public.delete_child_sa(&this->ike_sa->public, this->reqid);
|
||||
}
|
||||
this->public.state_interface.destroy(&this->public.state_interface);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements state_t.get_state
|
||||
*/
|
||||
static ike_sa_state_t get_state(private_create_child_sa_requested_t *this)
|
||||
{
|
||||
return CREATE_CHILD_SA_REQUESTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.destroy.
|
||||
*/
|
||||
static void destroy(private_create_child_sa_requested_t *this)
|
||||
{
|
||||
chunk_free(&this->nonce_i);
|
||||
chunk_free(&this->nonce_r);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
create_child_sa_requested_t *create_child_sa_requested_create(protected_ike_sa_t *ike_sa, child_sa_t *child_sa, chunk_t nonce_i, u_int32_t reqid)
|
||||
{
|
||||
private_create_child_sa_requested_t *this = malloc_thing(private_create_child_sa_requested_t);
|
||||
|
||||
/* interface functions */
|
||||
this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
|
||||
this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
|
||||
this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
|
||||
|
||||
/* private data */
|
||||
this->ike_sa = ike_sa;
|
||||
this->child_sa = child_sa;
|
||||
this->nonce_i = nonce_i;
|
||||
this->nonce_r = CHUNK_INITIALIZER;
|
||||
this->reqid = reqid;
|
||||
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/**
|
||||
* @file create_child_sa_requested.h
|
||||
*
|
||||
* @brief Interface of create_child_sa_requested_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef CREATE_CHILD_SA_REQEUSTED_H_
|
||||
#define CREATE_CHILD_SA_REQEUSTED_H_
|
||||
|
||||
#include <sa/states/state.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/child_sa.h>
|
||||
|
||||
typedef struct create_child_sa_requested_t create_child_sa_requested_t;
|
||||
|
||||
/**
|
||||
* @brief State after a CREATE_CHILD_SA request was sent.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - create_child_sa_requested_create()
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
struct create_child_sa_requested_t {
|
||||
/**
|
||||
* methods of the state_t interface
|
||||
*/
|
||||
state_t state_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor of class create_child_sa_requested_t
|
||||
*
|
||||
* If this CREATE_CHILD_SA message is to rekey a CHILD_SA,
|
||||
* the child_sa with the specified reqid gets deleted after a new
|
||||
* one is set up.
|
||||
*
|
||||
* @param ike_sa assigned ike_sa
|
||||
* @param child_sa newly created child sa to complete
|
||||
* @param nonce nonce sent at initialization
|
||||
* @param reqid reqid, when rekeying a child SA.
|
||||
* @return created create_child_sa_requested_t object
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
create_child_sa_requested_t *create_child_sa_requested_create(protected_ike_sa_t *ike_sa, child_sa_t *child_sa, chunk_t nonce_i, u_int32_t reqid);
|
||||
|
||||
#endif /*CREATE_CHILD_SA_REQEUSTED_H_*/
|
||||
@@ -1,185 +0,0 @@
|
||||
/**
|
||||
* @file delete_child_sa_requested.c
|
||||
*
|
||||
* @brief State after a CREATE_CHILD_SA request was sent.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "delete_child_sa_requested.h"
|
||||
|
||||
#include <sa/child_sa.h>
|
||||
#include <sa/states/delete_ike_sa_requested.h>
|
||||
#include <sa/states/ike_sa_established.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <encoding/payloads/delete_payload.h>
|
||||
#include <utils/logger_manager.h>
|
||||
|
||||
|
||||
typedef struct private_delete_child_sa_requested_t private_delete_child_sa_requested_t;
|
||||
|
||||
/**
|
||||
* Private data of a delete_child_sa_requested_t object.
|
||||
*/
|
||||
struct private_delete_child_sa_requested_t {
|
||||
/**
|
||||
* Public interface of delete_child_sa_requested_t.
|
||||
*/
|
||||
delete_child_sa_requested_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
protected_ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Assigned logger.
|
||||
*
|
||||
* Is logger of ike_sa!
|
||||
*/
|
||||
logger_t *logger;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Process the response
|
||||
*/
|
||||
static status_t process_message(private_delete_child_sa_requested_t *this, message_t *response)
|
||||
{
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
crypter_t *crypter;
|
||||
signer_t *signer;
|
||||
status_t status;
|
||||
iterator_t *iterator;
|
||||
payload_t *payload;
|
||||
delete_payload_t *delete_response;
|
||||
|
||||
if (response->get_exchange_type(response) != INFORMATIONAL)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state delete_child_sa_requested",
|
||||
mapping_find(exchange_type_m, response->get_exchange_type(response)));
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (response->get_request(response))
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "INFORMATIONAL requests not allowed state delete_child_sa_requested");
|
||||
/* TODO: our state implementation currently can not handle incoming requests cleanly here.
|
||||
* If a request comes in before an outstanding reply, we can not handle it cleanly.
|
||||
* Currently, we create a ESTABLISHED state and let it process the message... But we
|
||||
* need changes in the whole state mechanism.
|
||||
*/
|
||||
state_t *state = (state_t*)ike_sa_established_create(this->ike_sa);
|
||||
state->process_message(state, response);
|
||||
state->destroy(state);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* get signer for verification and crypter for decryption */
|
||||
ike_sa_id = this->ike_sa->public.get_id(&this->ike_sa->public);
|
||||
if (!ike_sa_id->is_initiator(ike_sa_id))
|
||||
{
|
||||
crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
|
||||
signer = this->ike_sa->get_signer_initiator(this->ike_sa);
|
||||
}
|
||||
else
|
||||
{
|
||||
crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
|
||||
signer = this->ike_sa->get_signer_responder(this->ike_sa);
|
||||
}
|
||||
|
||||
/* parse incoming message */
|
||||
status = response->parse_body(response, crypter, signer);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "INFORMATIONAL response decryption failed. Ignoring message");
|
||||
return status;
|
||||
}
|
||||
|
||||
iterator = response->get_payload_iterator(response);
|
||||
while (iterator->has_next(iterator)) {
|
||||
iterator->current(iterator, (void**)&payload);
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case DELETE:
|
||||
delete_response = (delete_payload_t*)payload;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
if (delete_response)
|
||||
{
|
||||
iterator = delete_response->create_spi_iterator(delete_response);
|
||||
while (iterator->has_next(iterator))
|
||||
{
|
||||
u_int32_t spi;
|
||||
iterator->current(iterator, (void**)&spi);
|
||||
this->logger->log(this->logger, CONTROL, "DELETE request for CHILD_SA with SPI 0x%x received", spi);
|
||||
this->ike_sa->destroy_child_sa(this->ike_sa, spi);
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
|
||||
this->ike_sa->set_last_replied_message_id(this->ike_sa, response->get_message_id(response));
|
||||
|
||||
/* create new state */
|
||||
this->ike_sa->set_new_state(this->ike_sa, (state_t*)ike_sa_established_create(this->ike_sa));
|
||||
this->public.state_interface.destroy(&this->public.state_interface);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements state_t.get_state
|
||||
*/
|
||||
static ike_sa_state_t get_state(private_delete_child_sa_requested_t *this)
|
||||
{
|
||||
return DELETE_CHILD_SA_REQUESTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.destroy.
|
||||
*/
|
||||
static void destroy(private_delete_child_sa_requested_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
delete_child_sa_requested_t *delete_child_sa_requested_create(protected_ike_sa_t *ike_sa)
|
||||
{
|
||||
private_delete_child_sa_requested_t *this = malloc_thing(private_delete_child_sa_requested_t);
|
||||
|
||||
/* interface functions */
|
||||
this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
|
||||
this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
|
||||
this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
|
||||
|
||||
/* private data */
|
||||
this->ike_sa = ike_sa;
|
||||
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/**
|
||||
* @file delete_child_sa_requested.h
|
||||
*
|
||||
* @brief Interface of delete_child_sa_requested_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef DELETE_CHILD_SA_REQEUSTED_H_
|
||||
#define DELETE_CHILD_SA_REQEUSTED_H_
|
||||
|
||||
#include <sa/states/state.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/child_sa.h>
|
||||
|
||||
typedef struct delete_child_sa_requested_t delete_child_sa_requested_t;
|
||||
|
||||
/**
|
||||
* @brief State after a CREATE_CHILD_SA request was sent.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - delete_child_sa_requested_create()
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
struct delete_child_sa_requested_t {
|
||||
/**
|
||||
* methods of the state_t interface
|
||||
*/
|
||||
state_t state_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor of class delete_child_sa_requested_t
|
||||
*
|
||||
* @param ike_sa assigned ike_sa
|
||||
* @return created delete_child_sa_requested_t object
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
delete_child_sa_requested_t *delete_child_sa_requested_create(protected_ike_sa_t *ike_sa);
|
||||
|
||||
#endif /*DELETE_CHILD_SA_REQEUSTED_H_*/
|
||||
@@ -1,163 +0,0 @@
|
||||
/**
|
||||
* @file delete_ike_sa_requested.c
|
||||
*
|
||||
* @brief Implementation of delete_ike_sa_requested_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "delete_ike_sa_requested.h"
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
|
||||
typedef struct private_delete_ike_sa_requested_t private_delete_ike_sa_requested_t;
|
||||
|
||||
/**
|
||||
* Private data of a delete_ike_sa_requested_t object.
|
||||
*/
|
||||
struct private_delete_ike_sa_requested_t {
|
||||
|
||||
/**
|
||||
* methods of the state_t interface
|
||||
*/
|
||||
delete_ike_sa_requested_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
protected_ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Assigned logger. Use logger of IKE_SA.
|
||||
*/
|
||||
logger_t *logger;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements state_t.get_state
|
||||
*/
|
||||
static status_t process_message(private_delete_ike_sa_requested_t *this, message_t *message)
|
||||
{
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
crypter_t *crypter;
|
||||
signer_t *signer;
|
||||
status_t status;
|
||||
|
||||
/* Notation as follows:
|
||||
* Mx{D} means: Message, with message ID "x", containing a Delete payload
|
||||
*
|
||||
* The clarifcation Document says in 5.8, that a IKE_SA delete should not
|
||||
* be acknowledged with the same delete. This only makes sense for CHILD_SAs,
|
||||
* as they are paired. IKE_SAs are not, there is only one for both ends.
|
||||
*
|
||||
* Normal case:
|
||||
* ----------------
|
||||
* Mx{D} -->
|
||||
* <-- Mx{}
|
||||
* Delete request is sent, and we wait for the acknowledge.
|
||||
*
|
||||
* Special case 1:
|
||||
* ---------------
|
||||
* Mx{D} -->
|
||||
* <-- My{D}
|
||||
* My{} -->
|
||||
* <-- Mx{}
|
||||
* Both initate a delete at the same time. We ack the delete, but wait for
|
||||
* our delete to be acknowledged.
|
||||
*/
|
||||
|
||||
if (message->get_exchange_type(message) != INFORMATIONAL)
|
||||
{
|
||||
/* anything other than information is ignored. We can an will not handle
|
||||
* messages such as CREATE_CHILD_SA */
|
||||
this->logger->log(this->logger, ERROR | LEVEL1,
|
||||
"%s messages not supported in state delete_ike_sa_requested. Ignored",
|
||||
mapping_find(exchange_type_m, message->get_exchange_type(message)));
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (message->get_request(message))
|
||||
{
|
||||
/* if it is a request, not a reply to our delete request, we
|
||||
* just acknowledge this. We stay in our state, as the other peer
|
||||
* has to ACK our request.
|
||||
*/
|
||||
message_t *acknowledge;
|
||||
this->ike_sa->build_message(this->ike_sa, INFORMATIONAL, FALSE, &acknowledge);
|
||||
return this->ike_sa->send_response(this->ike_sa, acknowledge);
|
||||
}
|
||||
|
||||
/* get signer for verification and crypter for decryption */
|
||||
ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public));
|
||||
if (!ike_sa_id->is_initiator(ike_sa_id))
|
||||
{
|
||||
crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
|
||||
signer = this->ike_sa->get_signer_initiator(this->ike_sa);
|
||||
}
|
||||
else
|
||||
{
|
||||
crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
|
||||
signer = this->ike_sa->get_signer_responder(this->ike_sa);
|
||||
}
|
||||
|
||||
/* parse incoming message, check if it's proper signed */
|
||||
status = message->parse_body(message, crypter, signer);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "INFORMATIONAL message decryption failed. Ignoring message");
|
||||
return status;
|
||||
}
|
||||
|
||||
/* ok, he knows about the deletion, destroy this IKE SA */
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.get_state.
|
||||
*/
|
||||
static ike_sa_state_t get_state(private_delete_ike_sa_requested_t *this)
|
||||
{
|
||||
return DELETE_IKE_SA_REQUESTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.get_state
|
||||
*/
|
||||
static void destroy(private_delete_ike_sa_requested_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
delete_ike_sa_requested_t *delete_ike_sa_requested_create(protected_ike_sa_t *ike_sa)
|
||||
{
|
||||
private_delete_ike_sa_requested_t *this = malloc_thing(private_delete_ike_sa_requested_t);
|
||||
|
||||
/* interface functions */
|
||||
this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
|
||||
this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
|
||||
this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
|
||||
|
||||
/* private data */
|
||||
this->ike_sa = ike_sa;
|
||||
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/**
|
||||
* @file delete_ike_sa_requested.h
|
||||
*
|
||||
* @brief Interface of delete_ike_sa_requested_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef DELETE_IKE_SA_REQUESTED_H_
|
||||
#define DELETE_IKE_SA_REQUESTED_H_
|
||||
|
||||
#include <sa/states/state.h>
|
||||
#include <sa/ike_sa.h>
|
||||
|
||||
typedef struct delete_ike_sa_requested_t delete_ike_sa_requested_t;
|
||||
|
||||
/**
|
||||
* @brief This class represents an the state of a half closed IKE_SA.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - delete_ike_sa_requested_create()
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
struct delete_ike_sa_requested_t {
|
||||
/**
|
||||
* methods of the state_t interface
|
||||
*/
|
||||
state_t state_interface;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor of class delete_ike_sa_requested_t
|
||||
*
|
||||
* @param ike_sa assigned ike_sa
|
||||
* @return created delete_ike_sa_requested_t object
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
delete_ike_sa_requested_t *delete_ike_sa_requested_create(protected_ike_sa_t *ike_sa);
|
||||
|
||||
#endif /*DELETE_IKE_SA_REQUESTED_H_*/
|
||||
@@ -1,719 +0,0 @@
|
||||
/**
|
||||
* @file ike_auth_requested.c
|
||||
*
|
||||
* @brief Implementation of ike_auth_requested_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ike_auth_requested.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/ts_payload.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/id_payload.h>
|
||||
#include <encoding/payloads/cert_payload.h>
|
||||
#include <encoding/payloads/auth_payload.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <crypto/signers/signer.h>
|
||||
#include <crypto/crypters/crypter.h>
|
||||
#include <sa/states/ike_sa_established.h>
|
||||
#include <sa/authenticator.h>
|
||||
#include <sa/child_sa.h>
|
||||
|
||||
typedef struct private_ike_auth_requested_t private_ike_auth_requested_t;
|
||||
|
||||
/**
|
||||
* Private data of a ike_auth_requested_t object.
|
||||
*
|
||||
*/
|
||||
struct private_ike_auth_requested_t {
|
||||
/**
|
||||
* Public interface of ike_auth_requested_t.
|
||||
*/
|
||||
ike_auth_requested_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
protected_ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* SA config, just a copy of the one stored in the ike_sa.
|
||||
*/
|
||||
policy_t *policy;
|
||||
|
||||
/**
|
||||
* Received nonce from responder.
|
||||
*/
|
||||
chunk_t received_nonce;
|
||||
|
||||
/**
|
||||
* Sent nonce in IKE_SA_INIT request.
|
||||
*/
|
||||
chunk_t sent_nonce;
|
||||
|
||||
/**
|
||||
* IKE_SA_INIT-Request in binary form.
|
||||
*/
|
||||
chunk_t ike_sa_init_reply_data;
|
||||
|
||||
/**
|
||||
* Proposal to setup CHILD_SA
|
||||
*/
|
||||
proposal_t *proposal;
|
||||
|
||||
/**
|
||||
* Traffic selectors applicable at our site
|
||||
*/
|
||||
linked_list_t *my_ts;
|
||||
|
||||
/**
|
||||
* Traffic selectors applicable at remote site
|
||||
*/
|
||||
linked_list_t *other_ts;
|
||||
|
||||
/**
|
||||
* Child sa created in ike_sa_init_requested
|
||||
*/
|
||||
child_sa_t *child_sa;
|
||||
|
||||
/**
|
||||
* Assigned Logger.
|
||||
*
|
||||
* Is logger of ike_sa!
|
||||
*/
|
||||
logger_t *logger;
|
||||
|
||||
/**
|
||||
* Process the IDr payload (check if other id is valid)
|
||||
*
|
||||
* @param this calling object
|
||||
* @param idr_payload ID payload of responder
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - DESTROY_ME
|
||||
*/
|
||||
status_t (*process_idr_payload) (private_ike_auth_requested_t *this, id_payload_t *idr_payload);
|
||||
|
||||
/**
|
||||
* Process received CERT payload
|
||||
*
|
||||
* @param this calling object
|
||||
* @param cert_payload payload to process
|
||||
* @return
|
||||
* - DESTROY_ME if IKE_SA should be deleted
|
||||
* - SUCCSS if processed successful
|
||||
*/
|
||||
status_t (*process_cert_payload) (private_ike_auth_requested_t *this, cert_payload_t *cert_payload);
|
||||
|
||||
/**
|
||||
* Process the SA payload (check if selected proposals are valid, setup child sa)
|
||||
*
|
||||
* @param this calling object
|
||||
* @param sa_payload SA payload of responder
|
||||
*
|
||||
* - SUCCESS
|
||||
* - DESTROY_ME
|
||||
*/
|
||||
status_t (*process_sa_payload) (private_ike_auth_requested_t *this, sa_payload_t *sa_payload);
|
||||
|
||||
/**
|
||||
* Process the AUTH payload (check authenticity of message)
|
||||
*
|
||||
* @param this calling object
|
||||
* @param auth_payload AUTH payload of responder
|
||||
* @param other_id_payload ID payload of responder
|
||||
*
|
||||
* - SUCCESS
|
||||
* - DESTROY_ME
|
||||
*/
|
||||
status_t (*process_auth_payload) (private_ike_auth_requested_t *this, auth_payload_t *auth_payload, id_payload_t *other_id_payload);
|
||||
|
||||
/**
|
||||
* Process the TS payload (check if selected traffic selectors are valid)
|
||||
*
|
||||
* @param this calling object
|
||||
* @param ts_initiator TRUE if TS payload is TSi, FALSE for TSr
|
||||
* @param ts_payload TS payload of responder
|
||||
*
|
||||
* - SUCCESS
|
||||
* - DESTROY_ME
|
||||
*/
|
||||
status_t (*process_ts_payload) (private_ike_auth_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload);
|
||||
|
||||
/**
|
||||
* Process a notify payload
|
||||
*
|
||||
* @param this calling object
|
||||
* @param notify_payload notify payload
|
||||
*
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
* - DESTROY_ME
|
||||
*/
|
||||
status_t (*process_notify_payload) (private_ike_auth_requested_t *this, notify_payload_t *notify_payload);
|
||||
|
||||
/**
|
||||
* Destroy function called internally of this class after state change to
|
||||
* state IKE_SA_ESTABLISHED succeeded.
|
||||
*
|
||||
* This destroy function does not destroy objects which were passed to the new state.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*destroy_after_state_change) (private_ike_auth_requested_t *this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Implements state_t.process_message
|
||||
*/
|
||||
static status_t process_message(private_ike_auth_requested_t *this, message_t *ike_auth_reply)
|
||||
{
|
||||
ts_payload_t *tsi_payload = NULL;
|
||||
ts_payload_t *tsr_payload = NULL;
|
||||
id_payload_t *idr_payload = NULL;
|
||||
cert_payload_t *cert_payload = NULL;
|
||||
auth_payload_t *auth_payload = NULL;
|
||||
sa_payload_t *sa_payload = NULL;
|
||||
iterator_t *payloads = NULL;
|
||||
crypter_t *crypter = NULL;
|
||||
signer_t *signer = NULL;
|
||||
status_t status;
|
||||
host_t *my_host, *other_host;
|
||||
identification_t *my_id, *other_id;
|
||||
chunk_t seed;
|
||||
prf_plus_t *prf_plus;
|
||||
connection_t *connection;
|
||||
policy_t *policy;
|
||||
|
||||
if (ike_auth_reply->get_exchange_type(ike_auth_reply) != IKE_AUTH)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "message of type %s not supported in state ike_auth_requested",
|
||||
mapping_find(exchange_type_m,ike_auth_reply->get_exchange_type(ike_auth_reply)));
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (ike_auth_reply->get_request(ike_auth_reply))
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "IKE_AUTH requests not allowed state ike_sa_init_responded");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* get signer for verification and crypter for decryption */
|
||||
signer = this->ike_sa->get_signer_responder(this->ike_sa);
|
||||
crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
|
||||
|
||||
/* parse incoming message */
|
||||
status = ike_auth_reply->parse_body(ike_auth_reply, crypter, signer);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH reply decryption failed. Ignoring message");
|
||||
return status;
|
||||
}
|
||||
|
||||
this->policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
|
||||
/* we collect all payloads, which are processed later. Notify's are processed
|
||||
* in place, since we don't know how may are there.
|
||||
*/
|
||||
payloads = ike_auth_reply->get_payload_iterator(ike_auth_reply);
|
||||
while (payloads->has_next(payloads))
|
||||
{
|
||||
payload_t *payload;
|
||||
payloads->current(payloads, (void**)&payload);
|
||||
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case AUTHENTICATION:
|
||||
auth_payload = (auth_payload_t*)payload;
|
||||
break;
|
||||
case CERTIFICATE:
|
||||
cert_payload = (cert_payload_t*)payload;
|
||||
status = this->process_cert_payload(this, cert_payload);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
payloads->destroy(payloads);
|
||||
return status;
|
||||
|
||||
}
|
||||
break;
|
||||
case ID_RESPONDER:
|
||||
idr_payload = (id_payload_t*)payload;
|
||||
break;
|
||||
case SECURITY_ASSOCIATION:
|
||||
sa_payload = (sa_payload_t*)payload;
|
||||
break;
|
||||
case TRAFFIC_SELECTOR_INITIATOR:
|
||||
tsi_payload = (ts_payload_t*)payload;
|
||||
break;
|
||||
case TRAFFIC_SELECTOR_RESPONDER:
|
||||
tsr_payload = (ts_payload_t*)payload;
|
||||
break;
|
||||
case NOTIFY:
|
||||
{
|
||||
notify_payload_t *notify_payload = (notify_payload_t *) payload;
|
||||
|
||||
/* handle the notify directly, abort if no further processing required */
|
||||
status = this->process_notify_payload(this, notify_payload);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
payloads->destroy(payloads);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
default:
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "ignoring Payload %s (%d)",
|
||||
mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* iterator can be destroyed */
|
||||
payloads->destroy(payloads);
|
||||
|
||||
/* check if we have all payloads */
|
||||
if (!(idr_payload && sa_payload && auth_payload && tsi_payload && tsr_payload))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH reply did not contain all required payloads. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
status = this->ike_sa->update_connection_hosts(this->ike_sa,
|
||||
ike_auth_reply->get_destination(ike_auth_reply),
|
||||
ike_auth_reply->get_source(ike_auth_reply));
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
/* process all payloads */
|
||||
status = this->process_idr_payload(this, idr_payload);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
status = this->process_auth_payload(this, auth_payload,idr_payload);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
status = this->process_sa_payload(this, sa_payload);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
status = this->process_ts_payload(this, TRUE, tsi_payload);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
status = this->process_ts_payload(this, FALSE, tsr_payload);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
/* install child SAs for AH and esp */
|
||||
if (!this->child_sa)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "no CHILD_SA requested, no CHILD_SA built");
|
||||
}
|
||||
else if (!this->proposal)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "proposal negotiation failed, no CHILD_SA built");
|
||||
this->child_sa->destroy(this->child_sa);
|
||||
this->child_sa = NULL;
|
||||
}
|
||||
else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "traffic selector negotiation failed, no CHILD_SA built");
|
||||
this->child_sa->destroy(this->child_sa);
|
||||
this->child_sa = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
seed = chunk_alloc(this->sent_nonce.len + this->received_nonce.len);
|
||||
memcpy(seed.ptr, this->sent_nonce.ptr, this->sent_nonce.len);
|
||||
memcpy(seed.ptr + this->sent_nonce.len, this->received_nonce.ptr, this->received_nonce.len);
|
||||
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
|
||||
chunk_free(&seed);
|
||||
|
||||
status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
|
||||
prf_plus->destroy(prf_plus);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "could not install CHILD_SA! Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
status = this->child_sa->add_policies(this->child_sa, this->my_ts, this->other_ts);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "could not install CHILD_SA policy! Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
|
||||
}
|
||||
|
||||
this->ike_sa->set_last_replied_message_id(this->ike_sa,ike_auth_reply->get_message_id(ike_auth_reply));
|
||||
|
||||
/* create new state */
|
||||
this->ike_sa->establish(this->ike_sa);
|
||||
this->destroy_after_state_change(this);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements private_ike_auth_requested_t.process_idr_payload
|
||||
*/
|
||||
static status_t process_idr_payload(private_ike_auth_requested_t *this, id_payload_t *idr_payload)
|
||||
{
|
||||
identification_t *other_id, *configured_other_id;
|
||||
|
||||
other_id = idr_payload->get_identification(idr_payload);
|
||||
configured_other_id = this->policy->get_other_id(this->policy);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "configured ID: %s, ID of responder: %s",
|
||||
configured_other_id->get_string(configured_other_id),
|
||||
other_id->get_string(other_id));
|
||||
|
||||
if (!other_id->belongs_to(other_id, configured_other_id))
|
||||
{
|
||||
other_id->destroy(other_id);
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a not acceptable ID. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
this->policy->update_other_id(this->policy, other_id);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements private_ike_auth_requested_t.process_cert_payload
|
||||
*/
|
||||
static status_t process_cert_payload(private_ike_auth_requested_t *this, cert_payload_t * cert_payload)
|
||||
{
|
||||
bool found;
|
||||
x509_t *cert;
|
||||
|
||||
if (cert_payload->get_cert_encoding(cert_payload) != CERT_X509_SIGNATURE)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "certificate encoding is %s, ignored",
|
||||
enum_name(&cert_encoding_names, cert_payload->get_cert_encoding(cert_payload)));
|
||||
return SUCCESS;
|
||||
}
|
||||
cert = x509_create_from_chunk(cert_payload->get_data_clone(cert_payload));
|
||||
|
||||
if (charon->credentials->verify(charon->credentials, cert, &found))
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "end entity certificate is trusted");
|
||||
if (!found)
|
||||
{
|
||||
cert = charon->credentials->add_end_certificate(charon->credentials, cert);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "end entity certificate is not trusted");
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements private_ike_auth_requested_t.process_sa_payload
|
||||
*/
|
||||
static status_t process_sa_payload(private_ike_auth_requested_t *this, sa_payload_t *sa_payload)
|
||||
{
|
||||
proposal_t *proposal, *proposal_tmp;
|
||||
linked_list_t *proposal_list;
|
||||
|
||||
/* get his selected proposal */
|
||||
proposal_list = sa_payload->get_proposals(sa_payload);
|
||||
/* check count of proposals */
|
||||
if (proposal_list->get_count(proposal_list) == 0)
|
||||
{
|
||||
/* no proposal? we accept this, but no child sa is built */
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH reply's SA_PAYLOAD didn't contain any proposals. No CHILD_SA created",
|
||||
proposal_list->get_count(proposal_list));
|
||||
proposal_list->destroy(proposal_list);
|
||||
return SUCCESS;
|
||||
}
|
||||
if (proposal_list->get_count(proposal_list) > 1)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH reply's SA_PAYLOAD contained %d proposal. Deleting IKE_SA",
|
||||
proposal_list->get_count(proposal_list));
|
||||
while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
|
||||
{
|
||||
proposal->destroy(proposal);
|
||||
}
|
||||
proposal_list->destroy(proposal_list);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* we have to re-check here if other's selection is valid */
|
||||
proposal = this->policy->select_proposal(this->policy, proposal_list);
|
||||
/* list not needed anymore */
|
||||
while (proposal_list->remove_last(proposal_list, (void**)&proposal_tmp) == SUCCESS)
|
||||
{
|
||||
proposal_tmp->destroy(proposal_tmp);
|
||||
}
|
||||
proposal_list->destroy(proposal_list);
|
||||
/* got a match? */
|
||||
if (proposal == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a not offered proposal. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* apply proposal */
|
||||
this->proposal = proposal;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements private_ike_auth_requested_t.process_auth_payload
|
||||
*/
|
||||
static status_t process_auth_payload(private_ike_auth_requested_t *this, auth_payload_t *auth_payload, id_payload_t *other_id_payload)
|
||||
{
|
||||
authenticator_t *authenticator;
|
||||
status_t status;
|
||||
|
||||
authenticator = authenticator_create(this->ike_sa);
|
||||
status = authenticator->verify_auth_data(authenticator,auth_payload,this->ike_sa_init_reply_data,this->sent_nonce,other_id_payload,FALSE);
|
||||
authenticator->destroy(authenticator);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "verification of IKE_AUTH reply failed. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "AUTH data verified successfully");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements private_ike_auth_requested_t.process_ts_payload
|
||||
*/
|
||||
static status_t process_ts_payload(private_ike_auth_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload)
|
||||
{
|
||||
linked_list_t *ts_received, *ts_selected;
|
||||
traffic_selector_t *ts;
|
||||
|
||||
/* get ts form payload */
|
||||
ts_received = ts_payload->get_traffic_selectors(ts_payload);
|
||||
/* select ts depending on payload type */
|
||||
if (ts_initiator)
|
||||
{
|
||||
ts_selected = this->policy->select_my_traffic_selectors(this->policy, ts_received);
|
||||
this->my_ts = ts_selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts_selected = this->policy->select_other_traffic_selectors(this->policy, ts_received);
|
||||
this->other_ts = ts_selected;
|
||||
}
|
||||
/* check if the responder selected valid proposals */
|
||||
if (ts_selected->get_count(ts_selected) != ts_received->get_count(ts_received))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained not offered traffic selectors.");
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
ts->destroy(ts);
|
||||
}
|
||||
ts_received->destroy(ts_received);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements private_ike_auth_requested_t.process_notify_payload
|
||||
*/
|
||||
static status_t process_notify_payload(private_ike_auth_requested_t *this, notify_payload_t *notify_payload)
|
||||
{
|
||||
notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s",
|
||||
mapping_find(notify_message_type_m, notify_message_type));
|
||||
|
||||
switch (notify_message_type)
|
||||
{
|
||||
case INVALID_SYNTAX:
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an INVALID_SYNTAX notify. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
|
||||
}
|
||||
case AUTHENTICATION_FAILED:
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an AUTHENTICATION_FAILED notify. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
|
||||
}
|
||||
case SINGLE_PAIR_REQUIRED:
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a SINGLE_PAIR_REQUIRED notify. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
case TS_UNACCEPTABLE:
|
||||
{
|
||||
/* TODO: We currently check only the replied TS payloads, which should be empty. Should
|
||||
* we interpret the notify additionaly? */
|
||||
this->logger->log(this->logger, CONTROL, "IKE_AUTH reply contained a TS_UNACCEPTABLE notify. Ignored");
|
||||
return SUCCESS;
|
||||
}
|
||||
case NO_PROPOSAL_CHOSEN:
|
||||
{
|
||||
/* TODO: We currently check only the replied SA payload, which should be empty. Should
|
||||
* we interpret the notify additionaly? */
|
||||
this->logger->log(this->logger, CONTROL, "IKE_AUTH reply contained a NO_PROPOSAL_CHOSEN notify. Ignored");
|
||||
return SUCCESS;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/*
|
||||
* - In case of unknown error: IKE_SA gets destroyed.
|
||||
* - In case of unknown status: logging
|
||||
*/
|
||||
|
||||
if (notify_message_type < 16383)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an unknown notify error (%d). Deleting IKE_SA",
|
||||
notify_message_type);
|
||||
return DESTROY_ME;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "IKE_AUTH reply contained an unknown notify (%d), ignored.",
|
||||
notify_message_type);
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements state_t.get_state
|
||||
*/
|
||||
static ike_sa_state_t get_state(private_ike_auth_requested_t *this)
|
||||
{
|
||||
return IKE_AUTH_REQUESTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements state_t.get_state
|
||||
*/
|
||||
static void destroy(private_ike_auth_requested_t *this)
|
||||
{
|
||||
chunk_free(&(this->received_nonce));
|
||||
chunk_free(&(this->sent_nonce));
|
||||
chunk_free(&(this->ike_sa_init_reply_data));
|
||||
if (this->child_sa)
|
||||
{
|
||||
this->child_sa->destroy(this->child_sa);
|
||||
}
|
||||
if (this->my_ts)
|
||||
{
|
||||
traffic_selector_t *ts;
|
||||
while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
ts->destroy(ts);
|
||||
}
|
||||
this->my_ts->destroy(this->my_ts);
|
||||
}
|
||||
if (this->other_ts)
|
||||
{
|
||||
traffic_selector_t *ts;
|
||||
while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
ts->destroy(ts);
|
||||
}
|
||||
this->other_ts->destroy(this->other_ts);
|
||||
}
|
||||
if (this->proposal)
|
||||
{
|
||||
this->proposal->destroy(this->proposal);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
/**
|
||||
* Implements protected_ike_sa_t.destroy_after_state_change
|
||||
*/
|
||||
static void destroy_after_state_change(private_ike_auth_requested_t *this)
|
||||
{
|
||||
chunk_free(&(this->received_nonce));
|
||||
chunk_free(&(this->sent_nonce));
|
||||
chunk_free(&(this->ike_sa_init_reply_data));
|
||||
if (this->my_ts)
|
||||
{
|
||||
traffic_selector_t *ts;
|
||||
while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
ts->destroy(ts);
|
||||
}
|
||||
this->my_ts->destroy(this->my_ts);
|
||||
}
|
||||
if (this->other_ts)
|
||||
{
|
||||
traffic_selector_t *ts;
|
||||
while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
ts->destroy(ts);
|
||||
}
|
||||
this->other_ts->destroy(this->other_ts);
|
||||
}
|
||||
if (this->proposal)
|
||||
{
|
||||
this->proposal->destroy(this->proposal);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,chunk_t sent_nonce,chunk_t received_nonce,chunk_t ike_sa_init_reply_data, child_sa_t *child_sa)
|
||||
{
|
||||
private_ike_auth_requested_t *this = malloc_thing(private_ike_auth_requested_t);
|
||||
|
||||
/* interface functions */
|
||||
this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
|
||||
this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
|
||||
this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
|
||||
|
||||
/* private functions */
|
||||
this->process_idr_payload = process_idr_payload;
|
||||
this->process_cert_payload = process_cert_payload;
|
||||
this->process_sa_payload = process_sa_payload;
|
||||
this->process_auth_payload = process_auth_payload;
|
||||
this->process_ts_payload = process_ts_payload;
|
||||
this->process_notify_payload = process_notify_payload;
|
||||
this->destroy_after_state_change = destroy_after_state_change;
|
||||
|
||||
/* private data */
|
||||
this->ike_sa = ike_sa;
|
||||
this->received_nonce = received_nonce;
|
||||
this->sent_nonce = sent_nonce;
|
||||
this->ike_sa_init_reply_data = ike_sa_init_reply_data;
|
||||
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
|
||||
this->my_ts = NULL;
|
||||
this->other_ts = NULL;
|
||||
this->proposal = NULL;
|
||||
this->child_sa = child_sa;
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/**
|
||||
* @file ike_auth_requested.h
|
||||
*
|
||||
* @brief Interface of ike_auth_requested_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef IKE_AUTH_REQUESTED_H_
|
||||
#define IKE_AUTH_REQUESTED_H_
|
||||
|
||||
#include <sa/states/state.h>
|
||||
#include <sa/ike_sa.h>
|
||||
|
||||
|
||||
typedef struct ike_auth_requested_t ike_auth_requested_t;
|
||||
|
||||
/**
|
||||
* @brief This class represents an IKE_SA, which has requested an IKE_AUTH.
|
||||
*
|
||||
* The state accpets IKE_AUTH responses. It proves the authenticity
|
||||
* and sets up the first child sa. After that, it changes IKE_SA state to
|
||||
* IKE_SA_ESTABLISHED.
|
||||
*
|
||||
* @ Constructors:
|
||||
* - ike_auth_requested_create()
|
||||
*
|
||||
* @todo handle certificate payloads
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
struct ike_auth_requested_t {
|
||||
/**
|
||||
* The state_t interface.
|
||||
*/
|
||||
state_t state_interface;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor of class ike_auth_requested_t
|
||||
*
|
||||
* @param ike_sa assigned ike_sa object
|
||||
* @param sent_nonce Sent nonce value in IKE_SA_INIT request
|
||||
* @param received_nonce Received nonce value in IKE_SA_INIT response
|
||||
* @param ike_sa_init_reply_data binary representation of IKE_SA_INIT reply
|
||||
* @param child_sa opened but not completed child_sa
|
||||
* @return created ike_auth_requested_t object
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,
|
||||
chunk_t sent_nonce,
|
||||
chunk_t received_nonce,
|
||||
chunk_t ike_sa_init_reply_data,
|
||||
child_sa_t *child_sa);
|
||||
|
||||
#endif /*IKE_AUTH_REQUESTED_H_*/
|
||||
@@ -1,671 +0,0 @@
|
||||
/**
|
||||
* @file ike_sa_established.c
|
||||
*
|
||||
* @brief Implementation of ike_sa_established_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ike_sa_established.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/delete_payload.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/ts_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
#include <sa/child_sa.h>
|
||||
#include <sa/states/delete_ike_sa_requested.h>
|
||||
#include <queues/jobs/send_dpd_job.h>
|
||||
|
||||
typedef struct private_ike_sa_established_t private_ike_sa_established_t;
|
||||
|
||||
/**
|
||||
* Private data of a ike_sa_established_t object.
|
||||
*/
|
||||
struct private_ike_sa_established_t {
|
||||
/**
|
||||
* methods of the state_t interface
|
||||
*/
|
||||
ike_sa_established_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
protected_ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Nonce for a new child SA, chosen by initiator
|
||||
*/
|
||||
chunk_t nonce_i;
|
||||
|
||||
/**
|
||||
* Nonce for a new child SA, chosen by responder
|
||||
*/
|
||||
chunk_t nonce_r;
|
||||
|
||||
/**
|
||||
* Traffic selectors for a new child SA, responder side
|
||||
*/
|
||||
linked_list_t *my_ts;
|
||||
|
||||
/**
|
||||
* Traffic selectors for a new child SA, initiator side
|
||||
*/
|
||||
linked_list_t *other_ts;
|
||||
|
||||
/**
|
||||
* Newly set up child sa
|
||||
*/
|
||||
child_sa_t *child_sa;
|
||||
|
||||
/**
|
||||
* Old child sa, if we are rekeying
|
||||
*/
|
||||
child_sa_t *old_child_sa;
|
||||
|
||||
/**
|
||||
* Assigned logger. Use logger of IKE_SA.
|
||||
*/
|
||||
logger_t *logger;
|
||||
};
|
||||
|
||||
/**
|
||||
* Schedule send dpd job
|
||||
*/
|
||||
static void schedule_dpd_job(private_ike_sa_established_t *this)
|
||||
{
|
||||
u_int32_t interval = charon->configuration->get_dpd_interval(charon->configuration);
|
||||
|
||||
if (interval)
|
||||
{
|
||||
charon->event_queue->add_relative(charon->event_queue,
|
||||
(job_t*)send_dpd_job_create(this->ike_sa->public.get_id(&this->ike_sa->public)),
|
||||
interval);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_established_t.build_sa_payload.
|
||||
*/
|
||||
static status_t build_sa_payload(private_ike_sa_established_t *this, sa_payload_t *request, message_t *response)
|
||||
{
|
||||
proposal_t *proposal, *proposal_tmp;
|
||||
linked_list_t *proposal_list;
|
||||
sa_payload_t *sa_response;
|
||||
chunk_t seed;
|
||||
prf_plus_t *prf_plus;
|
||||
status_t status;
|
||||
connection_t *connection;
|
||||
policy_t *policy;
|
||||
u_int32_t reqid = 0;
|
||||
bool use_natt;
|
||||
|
||||
/* prepare reply */
|
||||
sa_response = sa_payload_create();
|
||||
|
||||
/* get proposals from request, and select one with ours */
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
proposal_list = request->get_proposals(request);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "selecting proposals:");
|
||||
proposal = policy->select_proposal(policy, proposal_list);
|
||||
/* list is not needed anymore */
|
||||
while (proposal_list->remove_last(proposal_list, (void**)&proposal_tmp) == SUCCESS)
|
||||
{
|
||||
proposal_tmp->destroy(proposal_tmp);
|
||||
}
|
||||
proposal_list->destroy(proposal_list);
|
||||
/* do we have a proposal? */
|
||||
if (proposal == NULL)
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA request did not contain any proposals we accept. "
|
||||
"Adding NO_PROPOSAL_CHOSEN notify");
|
||||
/* add NO_PROPOSAL_CHOSEN and an empty SA payload */
|
||||
notify = notify_payload_create_from_protocol_and_type(PROTO_IKE, NO_PROPOSAL_CHOSEN);
|
||||
response->add_payload(response, (payload_t*)notify);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set up child sa */
|
||||
seed = chunk_alloc(this->nonce_i.len + this->nonce_r.len);
|
||||
memcpy(seed.ptr, this->nonce_i.ptr, this->nonce_i.len);
|
||||
memcpy(seed.ptr + this->nonce_i.len, this->nonce_r.ptr, this->nonce_r.len);
|
||||
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
|
||||
this->logger->log_chunk(this->logger, RAW|LEVEL2, "sekey seed", seed);
|
||||
chunk_free(&seed);
|
||||
chunk_free(&this->nonce_i);
|
||||
chunk_free(&this->nonce_r);
|
||||
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
if (this->old_child_sa)
|
||||
{ /* reuse old reqid if we are rekeying */
|
||||
reqid = this->old_child_sa->get_reqid(this->old_child_sa);
|
||||
}
|
||||
use_natt = this->ike_sa->public.is_any_host_behind_nat(&this->ike_sa->public);
|
||||
this->child_sa = child_sa_create(reqid,
|
||||
connection->get_my_host(connection),
|
||||
connection->get_other_host(connection),
|
||||
policy->get_soft_lifetime(policy),
|
||||
policy->get_hard_lifetime(policy),
|
||||
use_natt);
|
||||
|
||||
status = this->child_sa->add(this->child_sa, proposal, prf_plus);
|
||||
prf_plus->destroy(prf_plus);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "sould not install CHILD_SA!");
|
||||
sa_response->destroy(sa_response);
|
||||
proposal->destroy(proposal);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* add proposal to sa payload */
|
||||
sa_response->add_proposal(sa_response, proposal);
|
||||
proposal->destroy(proposal);
|
||||
}
|
||||
response->add_payload(response, (payload_t*)sa_response);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_established_t.build_ts_payload.
|
||||
*/
|
||||
static status_t build_ts_payload(private_ike_sa_established_t *this, bool ts_initiator, ts_payload_t *request, message_t* response)
|
||||
{
|
||||
linked_list_t *ts_received, *ts_selected;
|
||||
traffic_selector_t *ts;
|
||||
status_t status = SUCCESS;
|
||||
ts_payload_t *ts_response;
|
||||
policy_t *policy;
|
||||
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
|
||||
/* build a reply payload with selected traffic selectors */
|
||||
ts_received = request->get_traffic_selectors(request);
|
||||
/* select ts depending on payload type */
|
||||
if (ts_initiator)
|
||||
{
|
||||
ts_selected = policy->select_other_traffic_selectors(policy, ts_received);
|
||||
this->other_ts = ts_selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts_selected = policy->select_my_traffic_selectors(policy, ts_received);
|
||||
this->my_ts = ts_selected;
|
||||
}
|
||||
|
||||
ts_response = ts_payload_create_from_traffic_selectors(ts_initiator, ts_selected);
|
||||
response->add_payload(response, (payload_t*)ts_response);
|
||||
|
||||
/* add notify if traffic selectors do not match */
|
||||
if (!ts_initiator &&
|
||||
(ts_selected->get_count(ts_selected) == 0 || this->other_ts->get_count(this->other_ts) == 0))
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH request did not contain any traffic selectors we accept. "
|
||||
"Adding TS_UNACCEPTABLE notify");
|
||||
|
||||
notify = notify_payload_create_from_protocol_and_type(0, TS_UNACCEPTABLE);
|
||||
response->add_payload(response, (payload_t*)notify);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
ts->destroy(ts);
|
||||
}
|
||||
ts_received->destroy(ts_received);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_established_t.build_nonce_payload.
|
||||
*/
|
||||
static status_t build_nonce_payload(private_ike_sa_established_t *this, nonce_payload_t *nonce_request, message_t *response)
|
||||
{
|
||||
nonce_payload_t *nonce_payload;
|
||||
randomizer_t *randomizer;
|
||||
status_t status;
|
||||
|
||||
randomizer = this->ike_sa->get_randomizer(this->ike_sa);
|
||||
status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &this->nonce_r);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
nonce_payload = nonce_payload_create();
|
||||
nonce_payload->set_nonce(nonce_payload, this->nonce_r);
|
||||
|
||||
response->add_payload(response,(payload_t *) nonce_payload);
|
||||
|
||||
this->nonce_i = nonce_request->get_nonce(nonce_request);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a CREATE_CHILD_SA request
|
||||
*/
|
||||
static status_t process_create_child_sa(private_ike_sa_established_t *this, message_t *request, message_t *response)
|
||||
{
|
||||
ts_payload_t *tsi_request = NULL, *tsr_request = NULL;
|
||||
sa_payload_t *sa_request = NULL;
|
||||
nonce_payload_t *nonce_request = NULL;
|
||||
notify_payload_t *notify = NULL;
|
||||
iterator_t *payloads;
|
||||
status_t status;
|
||||
|
||||
/* iterate over incoming payloads. Message is verified, we can be sure there are the required payloads */
|
||||
payloads = request->get_payload_iterator(request);
|
||||
while (payloads->has_next(payloads))
|
||||
{
|
||||
payload_t *payload;
|
||||
payloads->current(payloads, (void**)&payload);
|
||||
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case SECURITY_ASSOCIATION:
|
||||
{
|
||||
sa_request = (sa_payload_t*)payload;
|
||||
break;
|
||||
}
|
||||
case TRAFFIC_SELECTOR_INITIATOR:
|
||||
{
|
||||
tsi_request = (ts_payload_t*)payload;
|
||||
break;
|
||||
}
|
||||
case TRAFFIC_SELECTOR_RESPONDER:
|
||||
{
|
||||
tsr_request = (ts_payload_t*)payload;
|
||||
break;
|
||||
}
|
||||
case NONCE:
|
||||
{
|
||||
nonce_request = (nonce_payload_t*)payload;
|
||||
break;
|
||||
}
|
||||
case KEY_EXCHANGE:
|
||||
{
|
||||
/* we currently do not support a diffie hellman exchange
|
||||
* for CHILD_SAs. */
|
||||
u_int16_t no_group[1];
|
||||
no_group[0] = htons(MODP_NONE);
|
||||
chunk_t no_group_chunk = chunk_from_buf((u_int8_t*)no_group);
|
||||
this->ike_sa->send_notify(this->ike_sa, CREATE_CHILD_SA, INVALID_KE_PAYLOAD, no_group_chunk);
|
||||
payloads->destroy(payloads);
|
||||
return FAILED;
|
||||
}
|
||||
case NOTIFY:
|
||||
{
|
||||
notify = (notify_payload_t*)payload;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "sgnoring payload %s (%d)",
|
||||
mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* iterator can be destroyed */
|
||||
payloads->destroy(payloads);
|
||||
|
||||
/* check if we have all payloads */
|
||||
if (!(sa_request && nonce_request && tsi_request && tsr_request))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA request did not contain all required payloads. Ignored");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (notify && notify->get_notify_message_type(notify) == REKEY_SA)
|
||||
{
|
||||
u_int32_t spi = notify->get_spi(notify);
|
||||
this->old_child_sa = this->ike_sa->get_child_sa(this->ike_sa, spi);
|
||||
this->logger->log(this->logger, CONTROL, "sekeying CHILD_SA with SPI 0x%x", spi);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "create new CHILD_SA");
|
||||
}
|
||||
|
||||
/* build response */
|
||||
this->ike_sa->build_message(this->ike_sa, CREATE_CHILD_SA, FALSE, &response);
|
||||
|
||||
/* add payloads to it */
|
||||
status = build_nonce_payload(this, nonce_request, response);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
response->destroy(response);
|
||||
return status;
|
||||
}
|
||||
status = build_sa_payload(this, sa_request, response);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
response->destroy(response);
|
||||
return status;
|
||||
}
|
||||
status = build_ts_payload(this, TRUE, tsi_request, response);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
response->destroy(response);
|
||||
return status;
|
||||
}
|
||||
status = build_ts_payload(this, FALSE, tsr_request, response);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
response->destroy(response);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = this->ike_sa->send_response(this->ike_sa, response);
|
||||
/* message can now be sent (must not be destroyed) */
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "unable to send CREATE_CHILD_SA reply. Ignored");
|
||||
response->destroy(response);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* install child SA policies */
|
||||
if (!this->child_sa)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "proposal negotiation failed, no CHILD_SA built");
|
||||
}
|
||||
else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "traffic selector negotiation failed, no CHILD_SA built");
|
||||
this->child_sa->destroy(this->child_sa);
|
||||
this->child_sa = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = this->child_sa->add_policies(this->child_sa, this->my_ts, this->other_ts);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "could not install CHILD_SA policy!");
|
||||
}
|
||||
if (this->old_child_sa)
|
||||
{ /* mark old child sa as rekeyed */
|
||||
this->old_child_sa->set_rekeyed(this->old_child_sa);
|
||||
}
|
||||
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process an informational request
|
||||
*/
|
||||
static status_t process_informational(private_ike_sa_established_t *this, message_t *request, message_t *response)
|
||||
{
|
||||
delete_payload_t *delete_request = NULL;
|
||||
iterator_t *payloads = request->get_payload_iterator(request);
|
||||
|
||||
if (!payloads->get_count(payloads))
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "DPD request received.");
|
||||
}
|
||||
|
||||
while (payloads->has_next(payloads))
|
||||
{
|
||||
payload_t *payload;
|
||||
payloads->current(payloads, (void**)&payload);
|
||||
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case DELETE:
|
||||
{
|
||||
delete_request = (delete_payload_t *) payload;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "ignoring Payload %s (%d)",
|
||||
mapping_find(payload_type_m, payload->get_type(payload)),
|
||||
payload->get_type(payload));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* iterator can be destroyed */
|
||||
payloads->destroy(payloads);
|
||||
|
||||
if (delete_request)
|
||||
{
|
||||
if (delete_request->get_protocol_id(delete_request) == PROTO_IKE)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "DELETE request for IKE_SA received");
|
||||
/* switch to delete_ike_sa_requested. This is not absolutely correct, but we
|
||||
* allow the clean destruction of an SA only in this state. */
|
||||
this->ike_sa->set_new_state(this->ike_sa, (state_t*)delete_ike_sa_requested_create(this->ike_sa));
|
||||
this->public.state_interface.destroy(&(this->public.state_interface));
|
||||
this->ike_sa->send_response(this->ike_sa, response);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
else
|
||||
{
|
||||
iterator_t *iterator;
|
||||
delete_payload_t *delete_response = delete_payload_create(delete_request->get_protocol_id(delete_request));
|
||||
iterator = delete_request->create_spi_iterator(delete_request);
|
||||
while (iterator->has_next(iterator))
|
||||
{
|
||||
u_int32_t spi;
|
||||
iterator->current(iterator, (void**)&spi);
|
||||
this->logger->log(this->logger, CONTROL, "DELETE request for CHILD_SA with SPI 0x%x received", spi);
|
||||
spi = this->ike_sa->destroy_child_sa(this->ike_sa, spi);
|
||||
if (spi)
|
||||
{
|
||||
delete_response->add_spi(delete_response, spi);
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
response->add_payload(response, (payload_t*)delete_response);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->ike_sa->send_response(this->ike_sa, response) != SUCCESS)
|
||||
{
|
||||
/* something is seriously wrong, kill connection */
|
||||
this->logger->log(this->logger, AUDIT, "unable to send reply. Deleting IKE_SA");
|
||||
response->destroy(response);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an informational response
|
||||
*/
|
||||
static status_t process_informational_response(private_ike_sa_established_t *this, message_t *message)
|
||||
{
|
||||
iterator_t *payloads = message->get_payload_iterator(message);
|
||||
|
||||
if (!payloads->get_count(payloads))
|
||||
{
|
||||
if (message->get_message_id(message)
|
||||
!= this->ike_sa->get_last_dpd_message_id(this->ike_sa))
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "DPD response received that does not match our last sent dpd message.");
|
||||
payloads->destroy(payloads);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
this->logger->log(this->logger, CONTROL, "DPD response received. Schedule job.");
|
||||
schedule_dpd_job(this);
|
||||
|
||||
payloads->destroy(payloads);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
while (payloads->has_next(payloads))
|
||||
{
|
||||
payload_t *payload;
|
||||
payloads->current(payloads, (void**)&payload);
|
||||
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
default:
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "ignoring Payload %s (%d)",
|
||||
mapping_find(payload_type_m, payload->get_type(payload)),
|
||||
payload->get_type(payload));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* iterator can be destroyed */
|
||||
payloads->destroy(payloads);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements state_t.get_state
|
||||
* Implements state_t.process_message
|
||||
*/
|
||||
static status_t process_message(private_ike_sa_established_t *this, message_t *message)
|
||||
{
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
message_t *response;
|
||||
crypter_t *crypter;
|
||||
signer_t *signer;
|
||||
status_t status;
|
||||
|
||||
/* get signer for verification and crypter for decryption */
|
||||
ike_sa_id = this->ike_sa->public.get_id(&this->ike_sa->public);
|
||||
if (!ike_sa_id->is_initiator(ike_sa_id))
|
||||
{
|
||||
crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
|
||||
signer = this->ike_sa->get_signer_initiator(this->ike_sa);
|
||||
}
|
||||
else
|
||||
{
|
||||
crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
|
||||
signer = this->ike_sa->get_signer_responder(this->ike_sa);
|
||||
}
|
||||
|
||||
/* parse incoming message */
|
||||
status = message->parse_body(message, crypter, signer);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "%s request decryption failed. Ignoring message",
|
||||
mapping_find(exchange_type_m, message->get_exchange_type(message)));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = this->ike_sa->update_connection_hosts(this->ike_sa,
|
||||
message->get_destination(message), message->get_source(message));
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
/* process responses */
|
||||
if (!message->get_request(message))
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case INFORMATIONAL:
|
||||
status = process_informational_response(this, message);
|
||||
break;
|
||||
default:
|
||||
this->logger->log(this->logger, ERROR | LEVEL1,
|
||||
"Only INFORMATIONAL responses are handled in state ike_sa_established");
|
||||
status = FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* we don't really reply to this message but the retransmit mechanism relies on this */
|
||||
this->ike_sa->set_last_replied_message_id(this->ike_sa, message->get_message_id(message));
|
||||
|
||||
/* return here */
|
||||
return status;
|
||||
}
|
||||
|
||||
/* prepare a reply of the same type */
|
||||
this->ike_sa->build_message(this->ike_sa, message->get_exchange_type(message), FALSE, &response);
|
||||
|
||||
/* handle the different message types in their functions */
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case INFORMATIONAL:
|
||||
status = process_informational(this, message, response);
|
||||
break;
|
||||
case CREATE_CHILD_SA:
|
||||
status = process_create_child_sa(this, message, response);
|
||||
break;
|
||||
default:
|
||||
this->logger->log(this->logger, ERROR | LEVEL1,
|
||||
"message of type %s not supported in state ike_sa_established",
|
||||
mapping_find(exchange_type_m, message->get_exchange_type(message)));
|
||||
status = NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.get_state.
|
||||
*/
|
||||
static ike_sa_state_t get_state(private_ike_sa_established_t *this)
|
||||
{
|
||||
return IKE_SA_ESTABLISHED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.get_state
|
||||
*/
|
||||
static void destroy(private_ike_sa_established_t *this)
|
||||
{
|
||||
chunk_free(&this->nonce_i);
|
||||
chunk_free(&this->nonce_r);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
ike_sa_established_t *ike_sa_established_create(protected_ike_sa_t *ike_sa)
|
||||
{
|
||||
private_ike_sa_established_t *this = malloc_thing(private_ike_sa_established_t);
|
||||
|
||||
/* interface functions */
|
||||
this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
|
||||
this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
|
||||
this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
|
||||
|
||||
/* private data */
|
||||
this->ike_sa = ike_sa;
|
||||
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
|
||||
this->nonce_i = CHUNK_INITIALIZER;
|
||||
this->nonce_r = CHUNK_INITIALIZER;
|
||||
this->old_child_sa = NULL;
|
||||
|
||||
/* schedule initial dpd job */
|
||||
schedule_dpd_job(this);
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/**
|
||||
* @file ike_sa_established.h
|
||||
*
|
||||
* @brief Interface of ike_sa_established_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef IKE_SA_ESTABLISHED_H_
|
||||
#define IKE_SA_ESTABLISHED_H_
|
||||
|
||||
#include <sa/states/state.h>
|
||||
#include <sa/ike_sa.h>
|
||||
|
||||
typedef struct ike_sa_established_t ike_sa_established_t;
|
||||
|
||||
/**
|
||||
* @brief This class represents an the state of an established
|
||||
* IKE_SA.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - ike_sa_established_create()
|
||||
*
|
||||
* @todo Implement handling of CREATE_CHILD_SA requests
|
||||
*
|
||||
* @todo Implement initialization of CREATE_CHILD_SA requests
|
||||
*
|
||||
* @todo Implement handling of any other message
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
struct ike_sa_established_t {
|
||||
/**
|
||||
* methods of the state_t interface
|
||||
*/
|
||||
state_t state_interface;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor of class ike_sa_established_t
|
||||
*
|
||||
* @param ike_sa assigned ike_sa
|
||||
* @return created ike_sa_established_t object
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
ike_sa_established_t *ike_sa_established_create(protected_ike_sa_t *ike_sa);
|
||||
|
||||
#endif /*IKE_SA_ESTABLISHED_H_*/
|
||||
@@ -1,990 +0,0 @@
|
||||
/**
|
||||
* @file ike_sa_init_requested.c
|
||||
*
|
||||
* @brief Implementation of ike_sa_init_requested_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "ike_sa_init_requested.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/ke_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <encoding/payloads/id_payload.h>
|
||||
#include <encoding/payloads/cert_payload.h>
|
||||
#include <encoding/payloads/certreq_payload.h>
|
||||
#include <encoding/payloads/auth_payload.h>
|
||||
#include <encoding/payloads/ts_payload.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <sa/states/ike_auth_requested.h>
|
||||
#include <sa/states/initiator_init.h>
|
||||
#include <sa/authenticator.h>
|
||||
|
||||
|
||||
typedef struct private_ike_sa_init_requested_t private_ike_sa_init_requested_t;
|
||||
|
||||
/**
|
||||
* Private data of a ike_sa_init_requested_t object.
|
||||
*
|
||||
*/
|
||||
struct private_ike_sa_init_requested_t {
|
||||
/**
|
||||
* Public interface of an ike_sa_init_requested_t object.
|
||||
*/
|
||||
ike_sa_init_requested_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA
|
||||
*/
|
||||
protected_ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Diffie Hellman object used to compute shared secret.
|
||||
*/
|
||||
diffie_hellman_t *diffie_hellman;
|
||||
|
||||
/**
|
||||
* Sent nonce value.
|
||||
*/
|
||||
chunk_t sent_nonce;
|
||||
|
||||
/**
|
||||
* Received nonce
|
||||
*/
|
||||
chunk_t received_nonce;
|
||||
|
||||
/**
|
||||
* Selected proposal
|
||||
*/
|
||||
proposal_t *proposal;
|
||||
|
||||
/**
|
||||
* Packet data of ike_sa_init request
|
||||
*/
|
||||
chunk_t ike_sa_init_request_data;
|
||||
|
||||
/**
|
||||
* Created child sa, if any
|
||||
*/
|
||||
child_sa_t *child_sa;
|
||||
|
||||
/**
|
||||
* Assigned logger
|
||||
*
|
||||
* Is logger of ike_sa!
|
||||
*/
|
||||
logger_t *logger;
|
||||
|
||||
/**
|
||||
* Precomputed NAT-D hash for initiator.
|
||||
*/
|
||||
chunk_t natd_hash_i;
|
||||
|
||||
/**
|
||||
* Flag indicating that an initiator NAT-D hash matched.
|
||||
*/
|
||||
bool natd_hash_i_matched;
|
||||
|
||||
/**
|
||||
* NAT-D payload count for NAT_DETECTION_SOURCE_IP.
|
||||
*/
|
||||
int natd_seen_i;
|
||||
|
||||
/**
|
||||
* Precomputed NAT-D hash of responder.
|
||||
*/
|
||||
chunk_t natd_hash_r;
|
||||
|
||||
/**
|
||||
* Flag indicating that a responder NAT-D hash matched.
|
||||
*/
|
||||
bool natd_hash_r_matched;
|
||||
|
||||
/**
|
||||
* NAT-D payload count for NAT_DETECTION_DESTINATION_IP.
|
||||
*/
|
||||
int natd_seen_r;
|
||||
|
||||
|
||||
/**
|
||||
* Process NONCE payload of IKE_SA_INIT response.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param nonce_payload NONCE payload to process
|
||||
* @return SUCCESS in any case
|
||||
*/
|
||||
status_t (*process_nonce_payload) (private_ike_sa_init_requested_t *this, nonce_payload_t *nonce_payload);
|
||||
|
||||
/**
|
||||
* Process SA payload of IKE_SA_INIT response.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param sa_payload SA payload to process
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
*/
|
||||
status_t (*process_sa_payload) (private_ike_sa_init_requested_t *this, sa_payload_t *sa_payload);
|
||||
|
||||
/**
|
||||
* Process KE payload of IKE_SA_INIT response.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param sa_payload KE payload to process
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
*/
|
||||
status_t (*process_ke_payload) (private_ike_sa_init_requested_t *this, ke_payload_t *ke_payload);
|
||||
|
||||
/**
|
||||
* Build ID payload for IKE_AUTH request.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param[out] id_payload buildet ID payload
|
||||
* @param msg created payload will be added to this message_t object
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
*/
|
||||
status_t (*build_id_payload) (private_ike_sa_init_requested_t *this,id_payload_t **id_payload, message_t *msg);
|
||||
|
||||
/**
|
||||
* Build CERT payload for IKE_AUTH request.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg created payload will be added to this message_t object
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
*/
|
||||
status_t (*build_cert_payload) (private_ike_sa_init_requested_t *this, message_t *msg);
|
||||
|
||||
/**
|
||||
* Build CERTREQ payload for IKE_AUTH request.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg created payload will be added to this message_t object
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
*/
|
||||
status_t (*build_certreq_payload) (private_ike_sa_init_requested_t *this, message_t *msg);
|
||||
|
||||
/**
|
||||
* Build IDr payload for IKE_AUTH request.
|
||||
*
|
||||
* Only built when the ID of the responder contains no wildcards.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg created payload will be added to this message_t object
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
*/
|
||||
status_t (*build_idr_payload) (private_ike_sa_init_requested_t *this, message_t *msg);
|
||||
|
||||
/**
|
||||
* Build AUTH payload for IKE_AUTH request.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param my_id_payload buildet ID payload
|
||||
* @param msg created payload will be added to this message_t object
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
*/
|
||||
status_t (*build_auth_payload) (private_ike_sa_init_requested_t *this,id_payload_t *my_id_payload, message_t *msg);
|
||||
|
||||
/**
|
||||
* Build SA payload for IKE_AUTH request.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg created payload will be added to this message_t object
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
*/
|
||||
status_t (*build_sa_payload) (private_ike_sa_init_requested_t *this, message_t *msg);
|
||||
|
||||
/**
|
||||
* Build TSi payload for IKE_AUTH request.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg created payload will be added to this message_t object
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
*/
|
||||
status_t (*build_tsi_payload) (private_ike_sa_init_requested_t *this, message_t *msg);
|
||||
|
||||
/**
|
||||
* Build TSr payload for IKE_AUTH request.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg created payload will be added to this message_t object
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
*/
|
||||
status_t (*build_tsr_payload) (private_ike_sa_init_requested_t *this, message_t *msg);
|
||||
|
||||
/**
|
||||
* Process a notify payload and react.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param notify_payload notify_payload to handle
|
||||
*/
|
||||
status_t (*process_notify_payload) (private_ike_sa_init_requested_t *this, notify_payload_t *notify_payload);
|
||||
|
||||
/**
|
||||
* Destroy function called internally of this class after state change to
|
||||
* state IKE_AUTH_REQUESTED succeeded.
|
||||
*
|
||||
* This destroy function does not destroy objects which were passed to the new state.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*destroy_after_state_change) (private_ike_sa_init_requested_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of state_t.process_message.
|
||||
*/
|
||||
static status_t process_message(private_ike_sa_init_requested_t *this, message_t *ike_sa_init_reply)
|
||||
{
|
||||
ike_auth_requested_t *next_state;
|
||||
chunk_t ike_sa_init_reply_data;
|
||||
sa_payload_t *sa_payload = NULL;
|
||||
ke_payload_t *ke_payload = NULL;
|
||||
id_payload_t *id_payload = NULL;
|
||||
nonce_payload_t *nonce_payload = NULL;
|
||||
u_int64_t responder_spi;
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
iterator_t *payloads;
|
||||
host_t *me, *other;
|
||||
connection_t *connection;
|
||||
policy_t *policy;
|
||||
|
||||
message_t *request;
|
||||
status_t status;
|
||||
|
||||
/*
|
||||
* In this state a reply message of type IKE_SA_INIT is expected:
|
||||
*
|
||||
* <-- HDR, SAr1, KEr, Nr, [CERTREQ]
|
||||
* or
|
||||
* <-- HDR, N
|
||||
*/
|
||||
|
||||
if (ike_sa_init_reply->get_exchange_type(ike_sa_init_reply) != IKE_SA_INIT)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "message of type %s not supported in state ike_sa_init_requested",
|
||||
mapping_find(exchange_type_m,ike_sa_init_reply->get_exchange_type(ike_sa_init_reply)));
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (ike_sa_init_reply->get_request(ike_sa_init_reply))
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT requests not allowed state ike_sa_init_responded");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* parse incoming message */
|
||||
status = ike_sa_init_reply->parse_body(ike_sa_init_reply, NULL, NULL);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT reply parsing faild. Ignoring message");
|
||||
return status;
|
||||
}
|
||||
|
||||
/* because we are original initiator we have to update the responder SPI to the new one */
|
||||
responder_spi = ike_sa_init_reply->get_responder_spi(ike_sa_init_reply);
|
||||
if (responder_spi == 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT reply contained a SPI of zero");
|
||||
return FAILED;
|
||||
}
|
||||
ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public));
|
||||
ike_sa_id->set_responder_spi(ike_sa_id,responder_spi);
|
||||
|
||||
/*
|
||||
* Precompute NAT-D hashes.
|
||||
* Even though there SHOULD only be a single payload of each
|
||||
* Notify type, we precompute both hashes.
|
||||
*/
|
||||
this->natd_hash_i = this->ike_sa->generate_natd_hash(this->ike_sa,
|
||||
ike_sa_init_reply->get_initiator_spi(ike_sa_init_reply),
|
||||
ike_sa_init_reply->get_responder_spi(ike_sa_init_reply),
|
||||
ike_sa_init_reply->get_source(ike_sa_init_reply));
|
||||
this->natd_hash_i_matched = FALSE;
|
||||
this->natd_seen_i = 0;
|
||||
this->natd_hash_r = this->ike_sa->generate_natd_hash(this->ike_sa,
|
||||
ike_sa_init_reply->get_initiator_spi(ike_sa_init_reply),
|
||||
ike_sa_init_reply->get_responder_spi(ike_sa_init_reply),
|
||||
ike_sa_init_reply->get_destination(ike_sa_init_reply));
|
||||
this->natd_hash_r_matched = FALSE;
|
||||
this->natd_seen_r = 0;
|
||||
this->ike_sa->set_my_host_behind_nat(this->ike_sa, FALSE);
|
||||
this->ike_sa->set_other_host_behind_nat(this->ike_sa, FALSE);
|
||||
|
||||
/* Iterate over all payloads.
|
||||
*
|
||||
* The message is already checked for the right payload types.
|
||||
*/
|
||||
payloads = ike_sa_init_reply->get_payload_iterator(ike_sa_init_reply);
|
||||
while (payloads->has_next(payloads))
|
||||
{
|
||||
payload_t *payload;
|
||||
payloads->current(payloads, (void**)&payload);
|
||||
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case SECURITY_ASSOCIATION:
|
||||
sa_payload = (sa_payload_t*)payload;
|
||||
break;
|
||||
case KEY_EXCHANGE:
|
||||
ke_payload = (ke_payload_t*)payload;
|
||||
break;
|
||||
case NONCE:
|
||||
nonce_payload = (nonce_payload_t*)payload;
|
||||
break;
|
||||
case NOTIFY:
|
||||
{
|
||||
notify_payload_t *notify_payload = (notify_payload_t *) payload;
|
||||
|
||||
status = this->process_notify_payload(this, notify_payload);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
payloads->destroy(payloads);
|
||||
return status;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "ignoring payload %s (%d)",
|
||||
mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
payloads->destroy(payloads);
|
||||
|
||||
if (!(nonce_payload && sa_payload && ke_payload))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT reply did not contain all required payloads. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
status = this->process_nonce_payload (this,nonce_payload);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
status = this->process_sa_payload (this,sa_payload);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
status = this->process_ke_payload (this,ke_payload);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
/* derive all the keys used in the IKE_SA */
|
||||
status = this->ike_sa->build_transforms(this->ike_sa, this->proposal, this->diffie_hellman, this->sent_nonce, this->received_nonce);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "transform objects could not be created from selected proposal. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* NAT-D */
|
||||
if ((!this->natd_seen_i && this->natd_seen_r > 0)
|
||||
|| (this->natd_seen_i > 0 && !this->natd_seen_r))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request contained wrong number of NAT-D payloads. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
if (this->natd_seen_r > 1)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "warning: IKE_SA_INIT request contained multiple Notify(NAT_DETECTION_DESTINATION_IP) payloads.");
|
||||
}
|
||||
if (this->natd_seen_i > 0 && !this->natd_hash_i_matched)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "remote host is behind NAT, using NAT-Traversal");
|
||||
this->ike_sa->set_other_host_behind_nat(this->ike_sa, TRUE);
|
||||
}
|
||||
if (this->natd_seen_r > 0 && !this->natd_hash_r_matched)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "local host is behind NAT, using NAT-Traversal");
|
||||
this->ike_sa->set_my_host_behind_nat(this->ike_sa, TRUE);
|
||||
}
|
||||
|
||||
/* apply the address on wich we really received the packet,
|
||||
* and switch to port 4500 when using NAT-T and NAT was detected.
|
||||
*/
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
me = ike_sa_init_reply->get_destination(ike_sa_init_reply);
|
||||
other = ike_sa_init_reply->get_source(ike_sa_init_reply);
|
||||
|
||||
if (this->ike_sa->public.is_any_host_behind_nat((ike_sa_t*)this->ike_sa))
|
||||
{
|
||||
me->set_port(me, IKEV2_NATT_PORT);
|
||||
other->set_port(other, IKEV2_NATT_PORT);
|
||||
this->logger->log(this->logger, AUDIT, "switching to port %d.", IKEV2_NATT_PORT);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "no NAT detected, not using NAT-Traversal");
|
||||
}
|
||||
|
||||
if (this->ike_sa->public.is_my_host_behind_nat(&this->ike_sa->public))
|
||||
{
|
||||
charon->event_queue->add_relative(charon->event_queue,
|
||||
(job_t*)send_keepalive_job_create(this->ike_sa->public.get_id((ike_sa_t*)this->ike_sa)),
|
||||
charon->configuration->get_keepalive_interval(charon->configuration));
|
||||
}
|
||||
|
||||
status = this->ike_sa->update_connection_hosts(this->ike_sa, me, other);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
policy->update_my_ts(policy, me);
|
||||
policy->update_other_ts(policy, other);
|
||||
|
||||
/* build empty message */
|
||||
this->ike_sa->build_message(this->ike_sa, IKE_AUTH, TRUE, &request);
|
||||
|
||||
status = this->build_id_payload(this, &id_payload, request);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_request;
|
||||
|
||||
status = this->build_cert_payload(this, request);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_request;
|
||||
|
||||
status = this->build_certreq_payload(this, request);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_request;
|
||||
|
||||
status = this->build_idr_payload(this, request);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_request;
|
||||
|
||||
status = this->build_auth_payload(this, (id_payload_t*)id_payload, request);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_request;
|
||||
|
||||
status = this->build_sa_payload(this, request);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_request;
|
||||
|
||||
status = this->build_tsi_payload(this, request);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_request;
|
||||
|
||||
status = this->build_tsr_payload(this, request);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_request;
|
||||
|
||||
/* message can now be sent (must not be destroyed) */
|
||||
status = this->ike_sa->send_request(this->ike_sa, request);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "unable to send IKE_AUTH request. Deleting IKE_SA");
|
||||
request->destroy(request);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
this->ike_sa->set_last_replied_message_id(this->ike_sa,ike_sa_init_reply->get_message_id(ike_sa_init_reply));
|
||||
|
||||
ike_sa_init_reply_data = ike_sa_init_reply->get_packet_data(ike_sa_init_reply);
|
||||
|
||||
/* state can now be changed */
|
||||
next_state = ike_auth_requested_create(this->ike_sa, this->sent_nonce, this->received_nonce,
|
||||
ike_sa_init_reply_data, this->child_sa);
|
||||
this->ike_sa->set_new_state(this->ike_sa,(state_t *) next_state);
|
||||
|
||||
this->destroy_after_state_change(this);
|
||||
return SUCCESS;
|
||||
|
||||
destroy_request:
|
||||
request->destroy(request);
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_requested_t.process_nonce_payload.
|
||||
*/
|
||||
status_t process_nonce_payload (private_ike_sa_init_requested_t *this, nonce_payload_t *nonce_payload)
|
||||
{
|
||||
free(this->received_nonce.ptr);
|
||||
this->received_nonce = nonce_payload->get_nonce(nonce_payload);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_requested_t.process_sa_payload.
|
||||
*/
|
||||
status_t process_sa_payload (private_ike_sa_init_requested_t *this, sa_payload_t *sa_payload)
|
||||
{
|
||||
proposal_t *proposal;
|
||||
linked_list_t *proposal_list;
|
||||
connection_t *connection;
|
||||
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
|
||||
/* get the list of selected proposals, the peer has to select only one proposal */
|
||||
proposal_list = sa_payload->get_proposals (sa_payload);
|
||||
if (proposal_list->get_count(proposal_list) != 1)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response did not contain a single proposal. Deleting IKE_SA");
|
||||
while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
|
||||
{
|
||||
proposal->destroy(proposal);
|
||||
}
|
||||
proposal_list->destroy(proposal_list);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* we have to re-check if the others selection is valid */
|
||||
this->proposal = connection->select_proposal(connection, proposal_list);
|
||||
while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
|
||||
{
|
||||
proposal->destroy(proposal);
|
||||
}
|
||||
proposal_list->destroy(proposal_list);
|
||||
|
||||
if (this->proposal == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained selected proposal we did not offer. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_requested_t.process_ke_payload.
|
||||
*/
|
||||
status_t process_ke_payload (private_ike_sa_init_requested_t *this, ke_payload_t *ke_payload)
|
||||
{
|
||||
this->diffie_hellman->set_other_public_value(this->diffie_hellman, ke_payload->get_key_exchange_data(ke_payload));
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_requested_t.build_id_payload.
|
||||
*/
|
||||
static status_t build_id_payload (private_ike_sa_init_requested_t *this,id_payload_t **id_payload, message_t *msg)
|
||||
{
|
||||
policy_t *policy;
|
||||
identification_t *my_id;
|
||||
id_payload_t *new_id_payload;
|
||||
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
my_id = policy->get_my_id(policy);
|
||||
new_id_payload = id_payload_create_from_identification(TRUE, my_id);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add ID payload to message");
|
||||
msg->add_payload(msg, (payload_t *) new_id_payload);
|
||||
|
||||
*id_payload = new_id_payload;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_requested_t.build_cert_payload.
|
||||
*/
|
||||
static status_t build_cert_payload (private_ike_sa_init_requested_t *this, message_t *msg)
|
||||
{
|
||||
connection_t *connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
|
||||
if (connection->get_cert_policy(connection) != CERT_NEVER_SEND)
|
||||
{
|
||||
policy_t *policy;
|
||||
identification_t *my_id;
|
||||
x509_t *cert;
|
||||
cert_payload_t *cert_payload;
|
||||
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
my_id = policy->get_my_id(policy);
|
||||
|
||||
cert = charon->credentials->get_certificate(charon->credentials, my_id);
|
||||
if (cert == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "could not find my certificate");
|
||||
return NOT_FOUND;
|
||||
}
|
||||
cert_payload = cert_payload_create_from_x509(cert);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add CERT payload to message");
|
||||
msg->add_payload(msg, (payload_t *) cert_payload);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_requested_t.build_certreq_payload.
|
||||
*/
|
||||
static status_t build_certreq_payload (private_ike_sa_init_requested_t *this, message_t *msg)
|
||||
{
|
||||
if (FALSE)
|
||||
{
|
||||
certreq_payload_t *certreq_payload;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add CERTREQ payload to message");
|
||||
msg->add_payload(msg, (payload_t *) certreq_payload);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_requested_t.build_idr_payload.
|
||||
*/
|
||||
static status_t build_idr_payload (private_ike_sa_init_requested_t *this, message_t *msg)
|
||||
{
|
||||
policy_t *policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
identification_t *identification = policy->get_other_id(policy);
|
||||
|
||||
if (!identification->contains_wildcards(identification))
|
||||
{
|
||||
id_payload_t *idr_payload = id_payload_create_from_identification(FALSE, identification);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add IDr payload to message");
|
||||
msg->add_payload(msg, (payload_t *) idr_payload);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_requested_t.build_auth_payload.
|
||||
*/
|
||||
static status_t build_auth_payload (private_ike_sa_init_requested_t *this, id_payload_t *my_id_payload, message_t *msg)
|
||||
{
|
||||
authenticator_t *authenticator;
|
||||
auth_payload_t *auth_payload;
|
||||
status_t status;
|
||||
|
||||
authenticator = authenticator_create(this->ike_sa);
|
||||
status = authenticator->compute_auth_data(authenticator,&auth_payload,this->ike_sa_init_request_data,this->received_nonce,my_id_payload,TRUE);
|
||||
authenticator->destroy(authenticator);
|
||||
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "could not generate AUTH data for IKE_AUTH request. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add AUTH payload to message");
|
||||
msg->add_payload(msg, (payload_t *) auth_payload);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_requested_t.build_sa_payload.
|
||||
*/
|
||||
static status_t build_sa_payload (private_ike_sa_init_requested_t *this, message_t *msg)
|
||||
{
|
||||
linked_list_t *proposal_list;
|
||||
sa_payload_t *sa_payload;
|
||||
policy_t *policy;
|
||||
connection_t *connection;
|
||||
|
||||
/* get proposals form config, add to payload */
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
proposal_list = policy->get_proposals(policy);
|
||||
/* build child sa */
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
this->child_sa = child_sa_create(0,
|
||||
connection->get_my_host(connection),
|
||||
connection->get_other_host(connection),
|
||||
policy->get_soft_lifetime(policy),
|
||||
policy->get_hard_lifetime(policy),
|
||||
this->ike_sa->public.is_any_host_behind_nat(&this->ike_sa->public));
|
||||
if (this->child_sa->alloc(this->child_sa, proposal_list) != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "could not install CHILD_SA! Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
sa_payload = sa_payload_create_from_proposal_list(proposal_list);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add SA payload to message");
|
||||
msg->add_payload(msg, (payload_t *) sa_payload);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_requested_t.build_tsi_payload.
|
||||
*/
|
||||
static status_t build_tsi_payload (private_ike_sa_init_requested_t *this, message_t *msg)
|
||||
{
|
||||
policy_t *policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
linked_list_t *ts_list = policy->get_my_traffic_selectors(policy);
|
||||
ts_payload_t *ts_payload = ts_payload_create_from_traffic_selectors(TRUE, ts_list);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add TSi payload to message");
|
||||
msg->add_payload(msg, (payload_t *) ts_payload);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_requested_t.build_tsr_payload.
|
||||
*/
|
||||
static status_t build_tsr_payload (private_ike_sa_init_requested_t *this, message_t *msg)
|
||||
{
|
||||
policy_t *policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
linked_list_t *ts_list = policy->get_other_traffic_selectors(policy);
|
||||
ts_payload_t *ts_payload = ts_payload_create_from_traffic_selectors(FALSE, ts_list);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add TSr payload to message");
|
||||
msg->add_payload(msg, (payload_t *) ts_payload);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_requested_t.process_notify_payload.
|
||||
*/
|
||||
static status_t process_notify_payload(private_ike_sa_init_requested_t *this, notify_payload_t *notify_payload)
|
||||
{
|
||||
chunk_t notification_data;
|
||||
notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s",
|
||||
mapping_find(notify_message_type_m, notify_message_type));
|
||||
|
||||
switch (notify_message_type)
|
||||
{
|
||||
case NO_PROPOSAL_CHOSEN:
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained a NO_PROPOSAL_CHOSEN notify. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
case INVALID_MAJOR_VERSION:
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained a INVALID_MAJOR_VERSION notify. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
case INVALID_KE_PAYLOAD:
|
||||
{
|
||||
initiator_init_t *initiator_init_state;
|
||||
chunk_t notify_data;
|
||||
diffie_hellman_group_t dh_group, old_dh_group;
|
||||
connection_t *connection;
|
||||
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
old_dh_group = connection->get_dh_group(connection);
|
||||
notify_data = notify_payload->get_notification_data(notify_payload);
|
||||
dh_group = ntohs(*((u_int16_t*)notify_data.ptr));
|
||||
|
||||
/* TODO:
|
||||
* We are very restrictive here: If the other didn't accept
|
||||
* our DH group, and we do not accept his offer, continuation
|
||||
* is cancelled...
|
||||
*/
|
||||
|
||||
this->logger->log(this->logger, AUDIT, "peer didn't accept %s, it requested %s!",
|
||||
mapping_find(diffie_hellman_group_m, old_dh_group),
|
||||
mapping_find(diffie_hellman_group_m, dh_group));
|
||||
/* check if we can accept this dh group */
|
||||
if (!connection->check_dh_group(connection, dh_group))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT,
|
||||
"peer does only accept DH group %s, which we do not accept! Aborting",
|
||||
mapping_find(diffie_hellman_group_m, dh_group));
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* Going to change state back to initiator_init_t */
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "create next state object");
|
||||
initiator_init_state = initiator_init_create(this->ike_sa);
|
||||
|
||||
/* buffer of sent and received messages has to get reseted */
|
||||
this->ike_sa->reset_message_buffers(this->ike_sa);
|
||||
|
||||
/* state can now be changed */
|
||||
this->ike_sa->set_new_state(this->ike_sa,(state_t *) initiator_init_state);
|
||||
|
||||
/* state has NOW changed :-) */
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "destroy old sate object");
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "going to retry initialization of connection");
|
||||
|
||||
this->public.state_interface.destroy(&(this->public.state_interface));
|
||||
if (initiator_init_state->retry_initiate_connection (initiator_init_state, dh_group) != SUCCESS)
|
||||
{
|
||||
return DESTROY_ME;
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
case NAT_DETECTION_DESTINATION_IP:
|
||||
{
|
||||
this->natd_seen_r++;
|
||||
if (this->natd_hash_r_matched)
|
||||
return SUCCESS;
|
||||
|
||||
notification_data = notify_payload->get_notification_data(notify_payload);
|
||||
if (chunk_equals(notification_data, this->natd_hash_r))
|
||||
{
|
||||
this->natd_hash_r_matched = TRUE;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash match");
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash mismatch");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
case NAT_DETECTION_SOURCE_IP:
|
||||
{
|
||||
this->natd_seen_i++;
|
||||
if (this->natd_hash_i_matched)
|
||||
return SUCCESS;
|
||||
|
||||
notification_data = notify_payload->get_notification_data(notify_payload);
|
||||
if (chunk_equals(notification_data, this->natd_hash_i))
|
||||
{
|
||||
this->natd_hash_i_matched = TRUE;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash match");
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash mismatch");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/*
|
||||
* - In case of unknown error: IKE_SA gets destroyed.
|
||||
* - In case of unknown status: logging
|
||||
*/
|
||||
if (notify_message_type < 16383)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT reply contained an unknown notify error (%d). Deleting IKE_SA",
|
||||
notify_message_type);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "IKE_SA_INIT reply contained an unknown notify (%d), ignored.",
|
||||
notify_message_type);
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.get_state.
|
||||
*/
|
||||
static ike_sa_state_t get_state(private_ike_sa_init_requested_t *this)
|
||||
{
|
||||
return IKE_SA_INIT_REQUESTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_requested_t.destroy_after_state_change.
|
||||
*/
|
||||
static void destroy_after_state_change (private_ike_sa_init_requested_t *this)
|
||||
{
|
||||
this->diffie_hellman->destroy(this->diffie_hellman);
|
||||
free(this->natd_hash_i.ptr);
|
||||
free(this->natd_hash_r.ptr);
|
||||
free(this->ike_sa_init_request_data.ptr);
|
||||
if (this->proposal)
|
||||
{
|
||||
this->proposal->destroy(this->proposal);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation state_t.destroy.
|
||||
*/
|
||||
static void destroy(private_ike_sa_init_requested_t *this)
|
||||
{
|
||||
this->diffie_hellman->destroy(this->diffie_hellman);
|
||||
free(this->sent_nonce.ptr);
|
||||
free(this->received_nonce.ptr);
|
||||
free(this->natd_hash_i.ptr);
|
||||
free(this->natd_hash_r.ptr);
|
||||
free(this->ike_sa_init_request_data.ptr);
|
||||
|
||||
if (this->child_sa)
|
||||
{
|
||||
this->child_sa->destroy(this->child_sa);
|
||||
}
|
||||
if (this->proposal)
|
||||
{
|
||||
this->proposal->destroy(this->proposal);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
ike_sa_init_requested_t *ike_sa_init_requested_create(protected_ike_sa_t *ike_sa, diffie_hellman_t *diffie_hellman, chunk_t sent_nonce,chunk_t ike_sa_init_request_data)
|
||||
{
|
||||
private_ike_sa_init_requested_t *this = malloc_thing(private_ike_sa_init_requested_t);
|
||||
|
||||
/* interface functions */
|
||||
this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
|
||||
this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
|
||||
this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
|
||||
|
||||
/* private functions */
|
||||
this->destroy_after_state_change = destroy_after_state_change;
|
||||
this->process_nonce_payload = process_nonce_payload;
|
||||
this->process_sa_payload = process_sa_payload;
|
||||
this->process_ke_payload = process_ke_payload;
|
||||
this->build_auth_payload = build_auth_payload;
|
||||
this->build_tsi_payload = build_tsi_payload;
|
||||
this->build_tsr_payload = build_tsr_payload;
|
||||
this->build_id_payload = build_id_payload;
|
||||
this->build_idr_payload = build_idr_payload;
|
||||
this->build_cert_payload = build_cert_payload;
|
||||
this->build_certreq_payload = build_certreq_payload;
|
||||
this->build_sa_payload = build_sa_payload;
|
||||
this->process_notify_payload = process_notify_payload;
|
||||
|
||||
/* private data */
|
||||
this->ike_sa = ike_sa;
|
||||
this->received_nonce = CHUNK_INITIALIZER;
|
||||
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
|
||||
this->diffie_hellman = diffie_hellman;
|
||||
this->proposal = NULL;
|
||||
this->sent_nonce = sent_nonce;
|
||||
this->child_sa = NULL;
|
||||
this->ike_sa_init_request_data = ike_sa_init_request_data;
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/**
|
||||
* @file ike_sa_init_requested.h
|
||||
*
|
||||
* @brief Interface of ike_sa_init_requestet_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef IKE_SA_INIT_REQUESTED_H_
|
||||
#define IKE_SA_INIT_REQUESTED_H_
|
||||
|
||||
#include <types.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/states/state.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
|
||||
typedef struct ike_sa_init_requested_t ike_sa_init_requested_t;
|
||||
|
||||
/**
|
||||
* @brief This class represents an IKE_SA state when
|
||||
* requested an IKE_SA_INIT as initiator.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - ike_sa_init_requested_create()
|
||||
*
|
||||
* @todo Include valid child sa SPIs in proposal
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
struct ike_sa_init_requested_t {
|
||||
/**
|
||||
* The state_t interface.
|
||||
*/
|
||||
state_t state_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor of class ike_sa_init_requested_t.
|
||||
*
|
||||
* @param ike_sa assigned ike_sa
|
||||
* @param diffie_hellman diffie_hellman object use to retrieve shared secret
|
||||
* @param sent_nonce Sent nonce value
|
||||
* @param ike_sa_init_request_data the binary representation of the IKE_SA_INIT request message
|
||||
* @return created ike_sa_init_request_t object
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
ike_sa_init_requested_t *ike_sa_init_requested_create(protected_ike_sa_t *ike_sa,
|
||||
diffie_hellman_t *diffie_hellman,
|
||||
chunk_t sent_nonce,
|
||||
chunk_t ike_sa_init_request_data);
|
||||
|
||||
#endif /*IKE_SA_INIT_REQUESTED_H_*/
|
||||
@@ -1,796 +0,0 @@
|
||||
/**
|
||||
* @file ike_sa_init_responded.c
|
||||
*
|
||||
* @brief State of a IKE_SA after responding to an IKE_SA_INIT request
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ike_sa_init_responded.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/authenticator.h>
|
||||
#include <sa/child_sa.h>
|
||||
#include <encoding/payloads/ts_payload.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/id_payload.h>
|
||||
#include <encoding/payloads/cert_payload.h>
|
||||
#include <encoding/payloads/auth_payload.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <crypto/signers/signer.h>
|
||||
#include <crypto/crypters/crypter.h>
|
||||
#include <sa/states/ike_sa_established.h>
|
||||
|
||||
|
||||
typedef struct private_ike_sa_init_responded_t private_ike_sa_init_responded_t;
|
||||
|
||||
/**
|
||||
* Private data of a ike_sa_init_responded_t object.
|
||||
*
|
||||
*/
|
||||
struct private_ike_sa_init_responded_t {
|
||||
/**
|
||||
* Public interface of ike_sa_init_responded_t.
|
||||
*/
|
||||
ike_sa_init_responded_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
protected_ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Received nonce.
|
||||
*/
|
||||
chunk_t received_nonce;
|
||||
|
||||
/**
|
||||
* Sent nonce.
|
||||
*/
|
||||
chunk_t sent_nonce;
|
||||
|
||||
/**
|
||||
* Binary representation of the IKE_SA_INIT response.
|
||||
*/
|
||||
chunk_t ike_sa_init_response_data;
|
||||
|
||||
/**
|
||||
* Binary representation of the IKE_SA_INIT request.
|
||||
*/
|
||||
chunk_t ike_sa_init_request_data;
|
||||
|
||||
/**
|
||||
* SA config to use.
|
||||
*/
|
||||
policy_t *policy;
|
||||
|
||||
/**
|
||||
* CHILD_SA, if set up
|
||||
*/
|
||||
child_sa_t *child_sa;
|
||||
|
||||
/**
|
||||
* Traffic selectors applicable at our site
|
||||
*/
|
||||
linked_list_t *my_ts;
|
||||
|
||||
/**
|
||||
* Traffic selectors applicable at remote site
|
||||
*/
|
||||
linked_list_t *other_ts;
|
||||
|
||||
/**
|
||||
* Assigned logger.
|
||||
*
|
||||
* Is logger of ike_sa!
|
||||
*/
|
||||
logger_t *logger;
|
||||
|
||||
/**
|
||||
* Process received IDi and IDr payload and build IDr payload for IKE_AUTH response.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param request_idi ID payload representing initiator
|
||||
* @param request_idr ID payload representing responder (May be zero)
|
||||
* @param msg The created IDr payload is added to this message_t object
|
||||
* @param response_idr The created IDr payload is also written to this location
|
||||
*/
|
||||
status_t (*build_idr_payload) (private_ike_sa_init_responded_t *this,
|
||||
id_payload_t *request_idi,
|
||||
id_payload_t *request_idr,
|
||||
message_t *msg,
|
||||
id_payload_t **response_idr);
|
||||
|
||||
/**
|
||||
* Build CERT payload for IKE_AUTH response.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg The created CERT payload is added to this message_t object
|
||||
*/
|
||||
status_t (*build_cert_payload) (private_ike_sa_init_responded_t *this, message_t *msg);
|
||||
|
||||
/**
|
||||
* Process received AUTH payload and build AUTH payload for IKE_AUTH response.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param request AUTH payload received in IKE_AUTH request
|
||||
* @param other_id_payload other ID payload needed to verify AUTH data
|
||||
* @param my_id_payload my ID payload needed to compute AUTH data
|
||||
* @param msg The created AUTH payload is added to this message_t object
|
||||
*/
|
||||
status_t (*build_auth_payload) (private_ike_sa_init_responded_t *this, auth_payload_t *request,id_payload_t *other_id_payload,id_payload_t *my_id_payload, message_t* msg);
|
||||
|
||||
/**
|
||||
* Process received SA payload and build SA payload for IKE_AUTH response.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param request SA payload received in IKE_AUTH request
|
||||
* @param msg The created SA payload is added to this message_t object
|
||||
*/
|
||||
status_t (*build_sa_payload) (private_ike_sa_init_responded_t *this, sa_payload_t *request, message_t *msg);
|
||||
|
||||
/**
|
||||
* Process received TS payload and build TS payload for IKE_AUTH response.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param is_initiator type of TS payload. TRUE for TSi, FALSE for TSr
|
||||
* @param request TS payload received in IKE_AUTH request
|
||||
* @param msg the created TS payload is added to this message_t object
|
||||
*/
|
||||
status_t (*build_ts_payload) (private_ike_sa_init_responded_t *this, bool ts_initiator, ts_payload_t *request, message_t *msg);
|
||||
|
||||
/**
|
||||
* Process received CERT payload
|
||||
*
|
||||
* @param this calling object
|
||||
* @param cert_payload payload to process
|
||||
* @return
|
||||
* - DESTROY_ME if IKE_SA should be deleted
|
||||
* - SUCCSS if processed successful
|
||||
*/
|
||||
status_t (*process_cert_payload) (private_ike_sa_init_responded_t *this, cert_payload_t *cert_payload);
|
||||
|
||||
/**
|
||||
* Sends a IKE_AUTH reply containing a notify payload.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param notify_payload payload to process
|
||||
* @return
|
||||
* - DESTROY_ME if IKE_SA should be deleted
|
||||
* - SUCCSS if processed successful
|
||||
*/
|
||||
status_t (*process_notify_payload) (private_ike_sa_init_responded_t *this, notify_payload_t* notify_payload);
|
||||
|
||||
/**
|
||||
* Destroy function called internally of this class after state change to
|
||||
* state IKE_SA_ESTABLISHED succeeded.
|
||||
*
|
||||
* This destroy function does not destroy objects which were passed to the new state.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*destroy_after_state_change) (private_ike_sa_init_responded_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements state_t.process_message
|
||||
*/
|
||||
static status_t process_message(private_ike_sa_init_responded_t *this, message_t *request)
|
||||
{
|
||||
id_payload_t *idi_request = NULL;
|
||||
id_payload_t *idr_request = NULL;
|
||||
id_payload_t *idr_response;
|
||||
ts_payload_t *tsi_request = NULL;
|
||||
ts_payload_t *tsr_request = NULL;
|
||||
auth_payload_t *auth_request = NULL;
|
||||
sa_payload_t *sa_request = NULL;
|
||||
cert_payload_t *cert_request = NULL;
|
||||
iterator_t *payloads;
|
||||
message_t *response;
|
||||
crypter_t *crypter;
|
||||
signer_t *signer;
|
||||
status_t status;
|
||||
host_t *my_host, *other_host;
|
||||
identification_t *my_id, *other_id;
|
||||
connection_t *connection;
|
||||
policy_t *policy;
|
||||
|
||||
if (request->get_exchange_type(request) != IKE_AUTH)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "message of type %s not supported in state ike_sa_init_respondd",
|
||||
mapping_find(exchange_type_m,request->get_exchange_type(request)));
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (!request->get_request(request))
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "IKE_AUTH responses not allowed state ike_sa_init_responded");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* get signer for verification and crypter for decryption */
|
||||
signer = this->ike_sa->get_signer_initiator(this->ike_sa);
|
||||
crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
|
||||
|
||||
status = request->parse_body(request, crypter, signer);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
if (status == NOT_SUPPORTED)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "IKE_AUTH request contains unsupported payload with critical flag set. "
|
||||
"Deleting IKE_SA");
|
||||
this->ike_sa->send_notify(this->ike_sa, IKE_AUTH, UNSUPPORTED_CRITICAL_PAYLOAD, CHUNK_INITIALIZER);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH request decryption failed. Ignoring message");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* iterate over incoming payloads. Message is verified, we can be sure there are the required payloads */
|
||||
payloads = request->get_payload_iterator(request);
|
||||
while (payloads->has_next(payloads))
|
||||
{
|
||||
payload_t *payload;
|
||||
payloads->current(payloads, (void**)&payload);
|
||||
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case ID_INITIATOR:
|
||||
idi_request = (id_payload_t*)payload;
|
||||
break;
|
||||
case CERTIFICATE:
|
||||
cert_request = (cert_payload_t*)payload;
|
||||
status = this->process_cert_payload(this, cert_request);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
payloads->destroy(payloads);
|
||||
return status;
|
||||
}
|
||||
break;
|
||||
case AUTHENTICATION:
|
||||
auth_request = (auth_payload_t*)payload;
|
||||
break;
|
||||
case ID_RESPONDER:
|
||||
idr_request = (id_payload_t*)payload;
|
||||
break;
|
||||
case SECURITY_ASSOCIATION:
|
||||
sa_request = (sa_payload_t*)payload;
|
||||
break;
|
||||
case TRAFFIC_SELECTOR_INITIATOR:
|
||||
tsi_request = (ts_payload_t*)payload;
|
||||
break;
|
||||
case TRAFFIC_SELECTOR_RESPONDER:
|
||||
tsr_request = (ts_payload_t*)payload;
|
||||
break;
|
||||
case NOTIFY:
|
||||
{
|
||||
notify_payload_t *notify_payload = (notify_payload_t *) payload;
|
||||
status = this->process_notify_payload(this, notify_payload);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
payloads->destroy(payloads);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
case CERTIFICATE_REQUEST:
|
||||
{
|
||||
/* TODO handle certrequest payloads */
|
||||
}
|
||||
default:
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "ignoring payload %s (%d)",
|
||||
mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* iterator can be destroyed */
|
||||
payloads->destroy(payloads);
|
||||
|
||||
/* check if we have all payloads */
|
||||
if (!(idi_request && sa_request && auth_request && tsi_request && tsr_request))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH reply did not contain all required payloads. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
status = this->ike_sa->update_connection_hosts(this->ike_sa,
|
||||
request->get_destination(request), request->get_source(request));
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
/* build response */
|
||||
this->ike_sa->build_message(this->ike_sa, IKE_AUTH, FALSE, &response);
|
||||
|
||||
/* add payloads to it */
|
||||
status = this->build_idr_payload(this, idi_request, idr_request, response, &idr_response);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_response;
|
||||
|
||||
status = this->build_cert_payload(this, response);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_response;
|
||||
|
||||
status = this->build_auth_payload(this, auth_request,idi_request, idr_response,response);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_response;
|
||||
|
||||
status = this->build_sa_payload(this, sa_request, response);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_response;
|
||||
|
||||
status = this->build_ts_payload(this, TRUE, tsi_request, response);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_response;
|
||||
|
||||
status = this->build_ts_payload(this, FALSE, tsr_request, response);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_response;
|
||||
|
||||
status = this->ike_sa->send_response(this->ike_sa, response);
|
||||
/* message can now be sent (must not be destroyed) */
|
||||
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "unable to send IKE_AUTH reply. Deleting IKE_SA");
|
||||
response->destroy(response);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* install child SA policies */
|
||||
if (!this->child_sa)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "proposal negotiation failed, no CHILD_SA built");
|
||||
}
|
||||
else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "traffic selector negotiation failed, no CHILD_SA built");
|
||||
this->child_sa->destroy(this->child_sa);
|
||||
this->child_sa = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = this->child_sa->add_policies(this->child_sa, this->my_ts, this->other_ts);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "could not install CHILD_SA policy! Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
|
||||
}
|
||||
|
||||
/* create new state */
|
||||
this->ike_sa->establish(this->ike_sa);
|
||||
this->destroy_after_state_change(this);
|
||||
return SUCCESS;
|
||||
|
||||
destroy_response:
|
||||
response->destroy(response);
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_responded_t.build_idr_payload.
|
||||
*/
|
||||
static status_t build_idr_payload(private_ike_sa_init_responded_t *this, id_payload_t *request_idi, id_payload_t *request_idr, message_t *msg,id_payload_t **response_idr)
|
||||
{
|
||||
identification_t *other_id, *my_id;
|
||||
id_payload_t *idr_response;
|
||||
|
||||
/* use others ID, an ours if peer requested one */
|
||||
other_id = request_idi->get_identification(request_idi);
|
||||
if (request_idr)
|
||||
{
|
||||
my_id = request_idr->get_identification(request_idr);
|
||||
}
|
||||
else
|
||||
{
|
||||
my_id = identification_create_from_encoding(ID_ANY, CHUNK_INITIALIZER);
|
||||
}
|
||||
|
||||
/* build new sa config */
|
||||
this->policy = charon->policies->get_policy_by_ids(charon->policies, my_id, other_id);
|
||||
if (this->policy == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "we don't have a policy for IDs %s - %s. Deleting IKE_SA",
|
||||
my_id->get_string(my_id), other_id->get_string(other_id));
|
||||
my_id->destroy(my_id);
|
||||
other_id->destroy(other_id);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
my_id->destroy(my_id);
|
||||
other_id->destroy(other_id);
|
||||
|
||||
/* get my id from policy, which must contain a fully qualified valid id */
|
||||
my_id = this->policy->get_my_id(this->policy);
|
||||
|
||||
/* update others traffic selectors with actually used address */
|
||||
this->policy->update_my_ts(this->policy, msg->get_source(msg));
|
||||
this->policy->update_other_ts(this->policy, msg->get_destination(msg));
|
||||
|
||||
/* set policy in ike_sa for other states */
|
||||
this->ike_sa->set_policy(this->ike_sa, this->policy);
|
||||
|
||||
/* build response */
|
||||
idr_response = id_payload_create_from_identification(FALSE, my_id);
|
||||
msg->add_payload(msg, (payload_t*)idr_response);
|
||||
*response_idr = idr_response;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_responded_t.build_cert_payload.
|
||||
*/
|
||||
static status_t build_cert_payload (private_ike_sa_init_responded_t *this, message_t *msg)
|
||||
{
|
||||
connection_t *connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
|
||||
if (connection->get_cert_policy(connection) != CERT_NEVER_SEND)
|
||||
{
|
||||
policy_t *policy;
|
||||
identification_t *my_id;
|
||||
x509_t *cert;
|
||||
cert_payload_t *cert_payload;
|
||||
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
my_id = policy->get_my_id(policy);
|
||||
|
||||
cert = charon->credentials->get_certificate(charon->credentials, my_id);
|
||||
if (cert == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "could not find my certificate");
|
||||
return NOT_FOUND;
|
||||
}
|
||||
cert_payload = cert_payload_create_from_x509(cert);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add CERT payload to message");
|
||||
msg->add_payload(msg, (payload_t *) cert_payload);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_responded_t.build_auth_payload.
|
||||
*/
|
||||
static status_t build_auth_payload(private_ike_sa_init_responded_t *this, auth_payload_t *auth_request,id_payload_t *other_id_payload,id_payload_t *my_id_payload, message_t* msg)
|
||||
{
|
||||
authenticator_t *authenticator;
|
||||
auth_payload_t *auth_reply;
|
||||
status_t status;
|
||||
|
||||
authenticator = authenticator_create(this->ike_sa);
|
||||
status = authenticator->verify_auth_data(authenticator,auth_request, this->ike_sa_init_request_data,this->sent_nonce,other_id_payload,TRUE);
|
||||
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH request verification failed. Deleting IKE_SA");
|
||||
this->ike_sa->send_notify(this->ike_sa, IKE_AUTH, AUTHENTICATION_FAILED, CHUNK_INITIALIZER);
|
||||
authenticator->destroy(authenticator);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
status = authenticator->compute_auth_data(authenticator,&auth_reply, this->ike_sa_init_response_data,this->received_nonce,my_id_payload,FALSE);
|
||||
authenticator->destroy(authenticator);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "unable to build authentication data for IKE_AUTH reply. Deleting IKE_S");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
msg->add_payload(msg, (payload_t *)auth_reply);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_responded_t.build_sa_payload.
|
||||
*/
|
||||
static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_payload_t *request, message_t *msg)
|
||||
{
|
||||
proposal_t *proposal, *proposal_tmp;
|
||||
linked_list_t *proposal_list;
|
||||
sa_payload_t *sa_response;
|
||||
chunk_t seed;
|
||||
prf_plus_t *prf_plus;
|
||||
status_t status;
|
||||
connection_t *connection;
|
||||
policy_t *policy;
|
||||
bool use_natt;
|
||||
|
||||
/* prepare reply */
|
||||
sa_response = sa_payload_create();
|
||||
|
||||
/* get proposals from request, and select one with ours */
|
||||
proposal_list = request->get_proposals(request);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "selecting proposals:");
|
||||
proposal = this->policy->select_proposal(this->policy, proposal_list);
|
||||
/* list is not needed anymore */
|
||||
while (proposal_list->remove_last(proposal_list, (void**)&proposal_tmp) == SUCCESS)
|
||||
{
|
||||
proposal_tmp->destroy(proposal_tmp);
|
||||
}
|
||||
proposal_list->destroy(proposal_list);
|
||||
/* do we have a proposal? */
|
||||
if (proposal == NULL)
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH request did not contain any proposals we accept. "
|
||||
"Adding NO_PROPOSAL_CHOSEN notify");
|
||||
/* add NO_PROPOSAL_CHOSEN and an empty SA payload */
|
||||
notify = notify_payload_create_from_protocol_and_type(PROTO_IKE, NO_PROPOSAL_CHOSEN);
|
||||
msg->add_payload(msg, (payload_t*) notify);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set up child sa */
|
||||
seed = chunk_alloc(this->received_nonce.len + this->sent_nonce.len);
|
||||
memcpy(seed.ptr, this->received_nonce.ptr, this->received_nonce.len);
|
||||
memcpy(seed.ptr + this->received_nonce.len, this->sent_nonce.ptr, this->sent_nonce.len);
|
||||
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
|
||||
chunk_free(&seed);
|
||||
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
use_natt = this->ike_sa->public.is_any_host_behind_nat(&this->ike_sa->public);
|
||||
this->child_sa = child_sa_create(0,
|
||||
connection->get_my_host(connection),
|
||||
connection->get_other_host(connection),
|
||||
policy->get_soft_lifetime(policy),
|
||||
policy->get_hard_lifetime(policy),
|
||||
use_natt);
|
||||
|
||||
status = this->child_sa->add(this->child_sa, proposal, prf_plus);
|
||||
prf_plus->destroy(prf_plus);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "could not install CHILD_SA! Deleting IKE_SA");
|
||||
/* TODO: how do we handle this cleanly? */
|
||||
sa_response->destroy(sa_response);
|
||||
proposal->destroy(proposal);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* add proposal to sa payload */
|
||||
sa_response->add_proposal(sa_response, proposal);
|
||||
proposal->destroy(proposal);
|
||||
}
|
||||
msg->add_payload(msg, (payload_t*)sa_response);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_responded_t.build_ts_payload.
|
||||
*/
|
||||
static status_t build_ts_payload(private_ike_sa_init_responded_t *this, bool ts_initiator, ts_payload_t *request, message_t* msg)
|
||||
{
|
||||
linked_list_t *ts_received, *ts_selected;
|
||||
traffic_selector_t *ts;
|
||||
status_t status = SUCCESS;
|
||||
ts_payload_t *ts_response;
|
||||
|
||||
/* build a reply payload with selected traffic selectors */
|
||||
ts_received = request->get_traffic_selectors(request);
|
||||
/* select ts depending on payload type */
|
||||
if (ts_initiator)
|
||||
{
|
||||
ts_selected = this->policy->select_other_traffic_selectors(this->policy, ts_received);
|
||||
this->other_ts = ts_selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts_selected = this->policy->select_my_traffic_selectors(this->policy, ts_received);
|
||||
this->my_ts = ts_selected;
|
||||
}
|
||||
|
||||
ts_response = ts_payload_create_from_traffic_selectors(ts_initiator, ts_selected);
|
||||
msg->add_payload(msg, (payload_t*) ts_response);
|
||||
|
||||
/* add notify if traffic selectors do not match */
|
||||
if (!ts_initiator &&
|
||||
(ts_selected->get_count(ts_selected) == 0 || this->other_ts->get_count(this->other_ts) == 0))
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH request did not contain any traffic selectors we accept. "
|
||||
"Adding TS_UNACCEPTABLE notify");
|
||||
|
||||
notify = notify_payload_create_from_protocol_and_type(0, TS_UNACCEPTABLE);
|
||||
msg->add_payload(msg, (payload_t*)notify);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
ts->destroy(ts);
|
||||
}
|
||||
ts_received->destroy(ts_received);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements private_ike_sa_init_responded_t.process_cert_payload
|
||||
*/
|
||||
static status_t process_cert_payload(private_ike_sa_init_responded_t *this, cert_payload_t * cert_payload)
|
||||
{
|
||||
bool found;
|
||||
x509_t *cert;
|
||||
|
||||
if (cert_payload->get_cert_encoding(cert_payload) != CERT_X509_SIGNATURE)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "certificate encoding is %s, ignored",
|
||||
enum_name(&cert_encoding_names, cert_payload->get_cert_encoding(cert_payload)));
|
||||
return SUCCESS;
|
||||
}
|
||||
cert = x509_create_from_chunk(cert_payload->get_data_clone(cert_payload));
|
||||
|
||||
if (charon->credentials->verify(charon->credentials, cert, &found))
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "end entity certificate is trusted");
|
||||
if (!found)
|
||||
{
|
||||
cert = charon->credentials->add_end_certificate(charon->credentials, cert);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "end entity certificate is not trusted");
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements private_ike_sa_init_responded_t.process_notify_payload
|
||||
*/
|
||||
static status_t process_notify_payload(private_ike_sa_init_responded_t *this, notify_payload_t *notify_payload)
|
||||
{
|
||||
notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s",
|
||||
mapping_find(notify_message_type_m, notify_message_type));
|
||||
|
||||
switch (notify_message_type)
|
||||
{
|
||||
case SET_WINDOW_SIZE:
|
||||
/*
|
||||
* TODO Increase window size.
|
||||
*/
|
||||
case INITIAL_CONTACT:
|
||||
/*
|
||||
* TODO Delete existing IKE_SA's with other Identity.
|
||||
*/
|
||||
default:
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH request contained an unknown notify (%d), ignored.", notify_message_type);
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.get_state.
|
||||
*/
|
||||
static ike_sa_state_t get_state(private_ike_sa_init_responded_t *this)
|
||||
{
|
||||
return IKE_SA_INIT_RESPONDED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.destroy.
|
||||
*/
|
||||
static void destroy(private_ike_sa_init_responded_t *this)
|
||||
{
|
||||
chunk_free(&(this->received_nonce));
|
||||
chunk_free(&(this->sent_nonce));
|
||||
chunk_free(&(this->ike_sa_init_response_data));
|
||||
chunk_free(&(this->ike_sa_init_request_data));
|
||||
if (this->my_ts)
|
||||
{
|
||||
traffic_selector_t *ts;
|
||||
while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
ts->destroy(ts);
|
||||
}
|
||||
this->my_ts->destroy(this->my_ts);
|
||||
}
|
||||
if (this->other_ts)
|
||||
{
|
||||
traffic_selector_t *ts;
|
||||
while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
ts->destroy(ts);
|
||||
}
|
||||
this->other_ts->destroy(this->other_ts);
|
||||
}
|
||||
if (this->child_sa)
|
||||
{
|
||||
this->child_sa->destroy(this->child_sa);
|
||||
}
|
||||
|
||||
free(this);
|
||||
}
|
||||
/**
|
||||
* Implementation of private_ike_sa_init_responded.destroy_after_state_change.
|
||||
*/
|
||||
static void destroy_after_state_change(private_ike_sa_init_responded_t *this)
|
||||
{
|
||||
chunk_free(&(this->received_nonce));
|
||||
chunk_free(&(this->sent_nonce));
|
||||
chunk_free(&(this->ike_sa_init_response_data));
|
||||
chunk_free(&(this->ike_sa_init_request_data));
|
||||
if (this->my_ts)
|
||||
{
|
||||
traffic_selector_t *ts;
|
||||
while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
ts->destroy(ts);
|
||||
}
|
||||
this->my_ts->destroy(this->my_ts);
|
||||
}
|
||||
if (this->other_ts)
|
||||
{
|
||||
traffic_selector_t *ts;
|
||||
while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
ts->destroy(ts);
|
||||
}
|
||||
this->other_ts->destroy(this->other_ts);
|
||||
}
|
||||
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
ike_sa_init_responded_t *ike_sa_init_responded_create(protected_ike_sa_t *ike_sa, chunk_t received_nonce, chunk_t sent_nonce,chunk_t ike_sa_init_request_data, chunk_t ike_sa_init_response_data)
|
||||
{
|
||||
private_ike_sa_init_responded_t *this = malloc_thing(private_ike_sa_init_responded_t);
|
||||
|
||||
/* interface functions */
|
||||
this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
|
||||
this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
|
||||
this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
|
||||
|
||||
/* private functions */
|
||||
this->build_idr_payload = build_idr_payload;
|
||||
this->build_cert_payload = build_cert_payload;
|
||||
this->build_auth_payload = build_auth_payload;
|
||||
this->build_sa_payload = build_sa_payload;
|
||||
this->build_ts_payload = build_ts_payload;
|
||||
this->process_cert_payload = process_cert_payload;
|
||||
this->process_notify_payload = process_notify_payload;
|
||||
this->destroy_after_state_change = destroy_after_state_change;
|
||||
|
||||
/* private data */
|
||||
this->ike_sa = ike_sa;
|
||||
this->received_nonce = received_nonce;
|
||||
this->sent_nonce = sent_nonce;
|
||||
this->ike_sa_init_response_data = ike_sa_init_response_data;
|
||||
this->ike_sa_init_request_data = ike_sa_init_request_data;
|
||||
this->my_ts = NULL;
|
||||
this->other_ts = NULL;
|
||||
this->child_sa = NULL;
|
||||
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/**
|
||||
* @file ike_sa_init_responded.h
|
||||
*
|
||||
* @brief Interface of ike_sa_init_responded_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef IKE_SA_INIT_RESPONDED_H_
|
||||
#define IKE_SA_INIT_RESPONDED_H_
|
||||
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/states/state.h>
|
||||
|
||||
typedef struct ike_sa_init_responded_t ike_sa_init_responded_t;
|
||||
|
||||
/**
|
||||
* @brief This class represents an IKE_SA state when
|
||||
* responded to an IKE_SA_INIT request.
|
||||
*
|
||||
* The state accpets IKE_AUTH requests. It proves the authenticity
|
||||
* and sets up the first child sa. Then it sends back an IKE_AUTH
|
||||
* reply and changes to the IKE_SA_ESTABLISHED state.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - ike_sa_init_response_data()
|
||||
*
|
||||
* @todo Implement handling of SET_WINDOW_SIZE notify
|
||||
*
|
||||
* @todo Implement handling of INITIAL_CONTACT notify
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
struct ike_sa_init_responded_t {
|
||||
/**
|
||||
* The state_t interface.
|
||||
*/
|
||||
state_t state_interface;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor of class ike_sa_init_responded_t
|
||||
*
|
||||
* @param ike_sa assigned IKE_SA
|
||||
* @param received_nonce received nonce data in IKE_SA_INIT request
|
||||
* @param sent_nonce sent nonce data in IKE_SA_INIT response
|
||||
* @param ike_sa_init_request_data binary representation of received IKE_SA_INIT request
|
||||
* @param ike_sa_init_response_data binary representation of sent IKE_SA_INIT response
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
ike_sa_init_responded_t *ike_sa_init_responded_create(protected_ike_sa_t *ike_sa,
|
||||
chunk_t received_nonce,
|
||||
chunk_t sent_nonce,
|
||||
chunk_t ike_sa_init_request_data,
|
||||
chunk_t ike_sa_init_response_data);
|
||||
|
||||
#endif /*IKE_SA_INIT_RESPONDED_H_*/
|
||||
@@ -1,440 +0,0 @@
|
||||
/**
|
||||
* @file initiator_init.c
|
||||
*
|
||||
* @brief Implementation of initiator_init_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "initiator_init.h"
|
||||
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/states/state.h>
|
||||
#include <sa/states/ike_sa_init_requested.h>
|
||||
#include <queues/jobs/retransmit_request_job.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/ke_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
|
||||
|
||||
typedef struct private_initiator_init_t private_initiator_init_t;
|
||||
|
||||
/**
|
||||
* Private data of a initiator_init_t object..
|
||||
*
|
||||
*/
|
||||
struct private_initiator_init_t {
|
||||
/**
|
||||
* Methods of the state_t interface.
|
||||
*/
|
||||
initiator_init_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
protected_ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Diffie hellman object used to generate public DH value.
|
||||
* This objet is passed to the next state of type IKE_SA_INIT_REQUESTED.
|
||||
*/
|
||||
diffie_hellman_t *diffie_hellman;
|
||||
|
||||
/**
|
||||
* Sent nonce.
|
||||
* This nonce is passed to the next state of type IKE_SA_INIT_REQUESTED.
|
||||
*/
|
||||
chunk_t sent_nonce;
|
||||
|
||||
/**
|
||||
* Assigned logger.
|
||||
*
|
||||
* Is logger of ike_sa!
|
||||
*/
|
||||
logger_t *logger;
|
||||
|
||||
/**
|
||||
* Builds the SA payload for this state.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg message_t object to add the SA payload
|
||||
*/
|
||||
void (*build_sa_payload) (private_initiator_init_t *this, message_t *msg);
|
||||
|
||||
/**
|
||||
* Builds the KE payload for this state.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg message_t object to add the KE payload
|
||||
*/
|
||||
void (*build_ke_payload) (private_initiator_init_t *this, message_t *msg);
|
||||
|
||||
/**
|
||||
* Builds the NONCE payload for this state.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg message_t object to add the NONCE payload
|
||||
*/
|
||||
status_t (*build_nonce_payload) (private_initiator_init_t *this,message_t *msg);
|
||||
|
||||
/**
|
||||
* Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
|
||||
* Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg message_t object to add the Notify payloads
|
||||
*/
|
||||
void (*build_natd_payload) (private_initiator_init_t *this, message_t *msg, notify_message_type_t type, host_t *host);
|
||||
|
||||
/**
|
||||
* Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
|
||||
* Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg message_t object to add the Notify payloads
|
||||
*/
|
||||
void (*build_natd_payloads) (private_initiator_init_t *this, message_t *msg);
|
||||
|
||||
/**
|
||||
* Destroy function called internally of this class after state change to state
|
||||
* IKE_SA_INIT_REQUESTED succeeded.
|
||||
*
|
||||
* This destroy function does not destroy objects which were passed to the new state.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*destroy_after_state_change) (private_initiator_init_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of initiator_init_t.initiate_connection.
|
||||
*/
|
||||
static status_t initiate_connection (private_initiator_init_t *this, connection_t *connection)
|
||||
{
|
||||
policy_t *policy;
|
||||
diffie_hellman_group_t dh_group;
|
||||
host_t *my_host, *other_host;
|
||||
identification_t *my_id, *other_id;
|
||||
char *name;
|
||||
|
||||
name = connection->get_name(connection);
|
||||
this->ike_sa->set_connection(this->ike_sa, connection);
|
||||
|
||||
/* get policy */
|
||||
policy = charon->policies->get_policy_by_name(charon->policies, name);
|
||||
if (policy == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1,
|
||||
"could not get a policy named '%s', aborting", name);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
this->ike_sa->set_policy(this->ike_sa, policy);
|
||||
|
||||
my_host = connection->get_my_host(connection);
|
||||
other_host = connection->get_other_host(connection);
|
||||
my_id = policy->get_my_id(policy);
|
||||
other_id = policy->get_other_id(policy);
|
||||
|
||||
this->logger->log(this->logger, CONTROL, "initiating connection \"%s\": %s[%s]...%s[%s]",
|
||||
name,
|
||||
my_host->get_address(my_host),
|
||||
my_id->get_string(my_id),
|
||||
other_host->get_address(other_host),
|
||||
other_id->get_string(other_id));
|
||||
|
||||
/* we must guess now a DH group. For that we choose our most preferred group */
|
||||
dh_group = connection->get_dh_group(connection);
|
||||
|
||||
/* next step is done in retry_initiate_connection */
|
||||
return this->public.retry_initiate_connection(&this->public, dh_group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of initiator_init_t.retry_initiate_connection.
|
||||
*/
|
||||
status_t retry_initiate_connection (private_initiator_init_t *this, diffie_hellman_group_t dh_group)
|
||||
{
|
||||
ike_sa_init_requested_t *next_state;
|
||||
chunk_t ike_sa_init_request_data;
|
||||
connection_t *connection;
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
message_t *message;
|
||||
status_t status;
|
||||
|
||||
this->diffie_hellman = diffie_hellman_create(dh_group);
|
||||
if (this->diffie_hellman == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "DH group %s (%d) not supported, aborting",
|
||||
mapping_find(diffie_hellman_group_m, dh_group), dh_group);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public));
|
||||
ike_sa_id->set_responder_spi(ike_sa_id,0);
|
||||
|
||||
/* going to build message */
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "going to build message");
|
||||
this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, TRUE, &message);
|
||||
|
||||
/* build SA payload */
|
||||
this->build_sa_payload(this, message);
|
||||
/* build KE payload */
|
||||
this->build_ke_payload(this, message);
|
||||
/* build Nonce payload */
|
||||
status = this->build_nonce_payload(this, message);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "building nonce payload failed, aborting");
|
||||
message->destroy(message);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* build Notify(NAT-D) payloads */
|
||||
this->build_natd_payloads(this, message);
|
||||
|
||||
/* message can now be sent (must not be destroyed) */
|
||||
status = this->ike_sa->send_request(this->ike_sa, message);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "unable to initiate connection, could not send message, aborting");
|
||||
message->destroy(message);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
message = this->ike_sa->get_last_requested_message(this->ike_sa);
|
||||
|
||||
ike_sa_init_request_data = message->get_packet_data(message);
|
||||
|
||||
/* state can now be changed */
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "create next state object");
|
||||
next_state = ike_sa_init_requested_create(this->ike_sa, this->diffie_hellman, this->sent_nonce,ike_sa_init_request_data);
|
||||
this->ike_sa->set_new_state(this->ike_sa,(state_t *) next_state);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "destroy old state object");
|
||||
this->destroy_after_state_change(this);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_initiator_init_t.build_sa_payload.
|
||||
*/
|
||||
static void build_sa_payload(private_initiator_init_t *this, message_t *msg)
|
||||
{
|
||||
sa_payload_t* sa_payload;
|
||||
linked_list_t *proposal_list;
|
||||
connection_t *connection;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "building SA payload");
|
||||
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
|
||||
proposal_list = connection->get_proposals(connection);
|
||||
|
||||
sa_payload = sa_payload_create_from_proposal_list(proposal_list);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add SA payload to message");
|
||||
msg->add_payload(msg, (payload_t *) sa_payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_initiator_init_t.build_ke_payload.
|
||||
*/
|
||||
static void build_ke_payload(private_initiator_init_t *this, message_t *msg)
|
||||
{
|
||||
ke_payload_t *ke_payload;
|
||||
chunk_t key_data;
|
||||
diffie_hellman_group_t dh_group;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "building KE payload");
|
||||
|
||||
this->diffie_hellman->get_my_public_value(this->diffie_hellman, &key_data);
|
||||
dh_group = this->diffie_hellman->get_dh_group(this->diffie_hellman);
|
||||
|
||||
ke_payload = ke_payload_create();
|
||||
ke_payload->set_dh_group_number(ke_payload, dh_group);
|
||||
ke_payload->set_key_exchange_data(ke_payload, key_data);
|
||||
|
||||
chunk_free(&key_data);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add KE payload to message");
|
||||
msg->add_payload(msg, (payload_t *) ke_payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_initiator_init_t.build_nonce_payload.
|
||||
*/
|
||||
static status_t build_nonce_payload(private_initiator_init_t *this, message_t *msg)
|
||||
{
|
||||
nonce_payload_t *nonce_payload;
|
||||
randomizer_t *randomizer;
|
||||
status_t status;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "building NONCE payload");
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "get pseudo random bytes for NONCE");
|
||||
randomizer = this->ike_sa->get_randomizer(this->ike_sa);
|
||||
|
||||
status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce));
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
this->logger->log(this->logger, RAW|LEVEL2, "initiator NONCE",&(this->sent_nonce));
|
||||
|
||||
nonce_payload = nonce_payload_create();
|
||||
|
||||
nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add NONCE payload to message");
|
||||
msg->add_payload(msg, (payload_t *) nonce_payload);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_initiator_init_t.build_natd_payload.
|
||||
*/
|
||||
static void build_natd_payload(private_initiator_init_t *this, message_t *msg, notify_message_type_t type, host_t *host)
|
||||
{
|
||||
chunk_t hash;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "building Notify(NAT-D) payload");
|
||||
notify_payload_t *notify_payload;
|
||||
notify_payload = notify_payload_create();
|
||||
/*notify_payload->set_protocol_id(notify_payload, NULL);*/
|
||||
/*notify_payload->set_spi(notify_payload, NULL);*/
|
||||
notify_payload->set_notify_message_type(notify_payload, type);
|
||||
hash = this->ike_sa->generate_natd_hash(this->ike_sa,
|
||||
msg->get_initiator_spi(msg),
|
||||
msg->get_responder_spi(msg),
|
||||
host);
|
||||
notify_payload->set_notification_data(notify_payload, hash);
|
||||
chunk_free(&hash);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add Notify(NAT-D) payload to message");
|
||||
msg->add_payload(msg, (payload_t *) notify_payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_initiator_init_t.build_natd_payloads.
|
||||
*/
|
||||
static void build_natd_payloads(private_initiator_init_t *this, message_t *msg)
|
||||
{
|
||||
connection_t *connection;
|
||||
linked_list_t *hostlist;
|
||||
iterator_t *hostiter;
|
||||
host_t *host;
|
||||
|
||||
/*
|
||||
* N(NAT_DETECTION_SOURCE_IP)+
|
||||
*/
|
||||
hostlist = charon->interfaces->get_addresses(charon->interfaces);
|
||||
hostiter = hostlist->create_iterator(hostlist, TRUE);
|
||||
while(hostiter->iterate(hostiter, (void**)&host)) {
|
||||
this->build_natd_payload(this, msg, NAT_DETECTION_SOURCE_IP,
|
||||
host);
|
||||
}
|
||||
hostiter->destroy(hostiter);
|
||||
|
||||
/*
|
||||
* N(NAT_DETECTION_DESTINATION_IP)
|
||||
*/
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
this->build_natd_payload(this, msg, NAT_DETECTION_DESTINATION_IP,
|
||||
connection->get_other_host(connection));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.process_message.
|
||||
*/
|
||||
static status_t process_message(private_initiator_init_t *this, message_t *message)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "in state INITIATOR_INIT, no message is processed");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.get_state.
|
||||
*/
|
||||
static ike_sa_state_t get_state(private_initiator_init_t *this)
|
||||
{
|
||||
return INITIATOR_INIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.destroy.
|
||||
*/
|
||||
static void destroy(private_initiator_init_t *this)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL | LEVEL3, "going to destroy initiator_init_t state object");
|
||||
|
||||
/* destroy diffie hellman object */
|
||||
if (this->diffie_hellman != NULL)
|
||||
{
|
||||
this->diffie_hellman->destroy(this->diffie_hellman);
|
||||
}
|
||||
if (this->sent_nonce.ptr != NULL)
|
||||
{
|
||||
free(this->sent_nonce.ptr);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_initiator_init_t.destroy_after_state_change
|
||||
*/
|
||||
static void destroy_after_state_change (private_initiator_init_t *this)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL | LEVEL3, "going to destroy initiator_init_t state object");
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa)
|
||||
{
|
||||
private_initiator_init_t *this = malloc_thing(private_initiator_init_t);
|
||||
|
||||
/* interface functions */
|
||||
this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
|
||||
this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
|
||||
this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
|
||||
|
||||
/* public functions */
|
||||
this->public.initiate_connection = (status_t (*)(initiator_init_t *, connection_t*)) initiate_connection;
|
||||
this->public.retry_initiate_connection = (status_t (*)(initiator_init_t *, int )) retry_initiate_connection;
|
||||
|
||||
/* private functions */
|
||||
this->destroy_after_state_change = destroy_after_state_change;
|
||||
this->build_nonce_payload = build_nonce_payload;
|
||||
this->build_sa_payload = build_sa_payload;
|
||||
this->build_ke_payload = build_ke_payload;
|
||||
this->build_natd_payload = build_natd_payload;
|
||||
this->build_natd_payloads = build_natd_payloads;
|
||||
|
||||
/* private data */
|
||||
this->ike_sa = ike_sa;
|
||||
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
|
||||
this->sent_nonce = CHUNK_INITIALIZER;
|
||||
this->diffie_hellman = NULL;
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/**
|
||||
* @file initiator_init.h
|
||||
*
|
||||
* @brief Interface of initiator_init_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INITIATOR_INIT_H_
|
||||
#define INITIATOR_INIT_H_
|
||||
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/states/state.h>
|
||||
|
||||
|
||||
typedef struct initiator_init_t initiator_init_t;
|
||||
|
||||
/**
|
||||
* @brief This class represents an IKE_SA state when
|
||||
* initializing a connection as initiator.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - initiator_init_create()
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
struct initiator_init_t {
|
||||
/**
|
||||
* The state_t interface.
|
||||
*/
|
||||
state_t state_interface;
|
||||
|
||||
/**
|
||||
* Initiate a new connection with given connection_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param connection connection to initiate
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - DESTROY_ME if something failed
|
||||
*/
|
||||
status_t (*initiate_connection) (initiator_init_t *this, connection_t *connection);
|
||||
|
||||
/**
|
||||
* Retry to initiate a new connection with a specific dh_group_priority.
|
||||
*
|
||||
* The dh_group_priority is starting at 1.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param dh_group_priority dh group priority to try with
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - DESTROY_ME if something failed (see log for error)
|
||||
*/
|
||||
status_t (*retry_initiate_connection) (initiator_init_t *this, int dh_group_priority);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor of class initiator_init_t.
|
||||
*
|
||||
* @param ike_sa assigned IKE_SA
|
||||
* @return created initiator_init_t object
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa);
|
||||
|
||||
|
||||
#endif /*INITIATOR_INIT_H_*/
|
||||
@@ -1,798 +0,0 @@
|
||||
/**
|
||||
* @file responder_init.c
|
||||
*
|
||||
* @brief Implementation of responder_init_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "responder_init.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/states/state.h>
|
||||
#include <sa/states/ike_sa_init_responded.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/ke_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
#include <encoding/payloads/certreq_payload.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <queues/jobs/send_keepalive_job.h>
|
||||
|
||||
|
||||
typedef struct private_responder_init_t private_responder_init_t;
|
||||
|
||||
/**
|
||||
* Private data of a responder_init_t object.
|
||||
*
|
||||
*/
|
||||
struct private_responder_init_t {
|
||||
/**
|
||||
* Methods of the state_t interface.
|
||||
*/
|
||||
responder_init_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
protected_ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Diffie Hellman object used to compute shared secret.
|
||||
*/
|
||||
diffie_hellman_t *diffie_hellman;
|
||||
|
||||
/**
|
||||
* Diffie Hellman group number from selected IKE proposal.
|
||||
*/
|
||||
u_int16_t dh_group_number;
|
||||
|
||||
/**
|
||||
* Priority used to get matching dh_group number.
|
||||
*/
|
||||
u_int16_t dh_group_priority;
|
||||
|
||||
/**
|
||||
* Sent nonce value.
|
||||
*
|
||||
* This value is passed to the next state of type IKE_SA_INIT_RESPONDED.
|
||||
*/
|
||||
chunk_t sent_nonce;
|
||||
|
||||
/**
|
||||
* Received nonce value
|
||||
*
|
||||
* This value is passed to the next state of type IKE_SA_INIT_RESPONDED.
|
||||
*/
|
||||
chunk_t received_nonce;
|
||||
|
||||
/**
|
||||
* Selected proposal
|
||||
*/
|
||||
proposal_t *proposal;
|
||||
|
||||
/**
|
||||
* Logger used to log data .
|
||||
*
|
||||
* Is logger of ike_sa!
|
||||
*/
|
||||
logger_t *logger;
|
||||
|
||||
/**
|
||||
* Precomputed NAT-D hash for initiator.
|
||||
*/
|
||||
chunk_t natd_hash_i;
|
||||
|
||||
/**
|
||||
* Flag indicating that an initiator NAT-D hash matched.
|
||||
*/
|
||||
bool natd_hash_i_matched;
|
||||
|
||||
/**
|
||||
* NAT-D payload count for NAT_DETECTION_SOURCE_IP.
|
||||
*/
|
||||
int natd_seen_i;
|
||||
|
||||
/**
|
||||
* Precomputed NAT-D hash of responder.
|
||||
*/
|
||||
chunk_t natd_hash_r;
|
||||
|
||||
/**
|
||||
* Flag indicating that a responder NAT-D hash matched.
|
||||
*/
|
||||
bool natd_hash_r_matched;
|
||||
|
||||
/**
|
||||
* NAT-D payload count for NAT_DETECTION_DESTINATION_IP.
|
||||
*/
|
||||
int natd_seen_r;
|
||||
|
||||
|
||||
/**
|
||||
* Handles received SA payload and builds the SA payload for the response.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param sa_request The received SA payload
|
||||
* @param msg the SA payload is added to this message_t object.
|
||||
* @return
|
||||
* - DESTROY_ME
|
||||
* - SUCCESS
|
||||
*/
|
||||
status_t (*build_sa_payload) (private_responder_init_t *this,sa_payload_t *sa_request, message_t *msg);
|
||||
|
||||
/**
|
||||
* Handles received KE payload and builds the KE payload for the response.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param ke_request The received KE payload
|
||||
* @param msg the KE payload is added to this message_t object.
|
||||
* @return
|
||||
* - DESTROY_ME
|
||||
* - SUCCESS
|
||||
*/
|
||||
status_t (*build_ke_payload) (private_responder_init_t *this,ke_payload_t *ke_request, message_t *msg);
|
||||
|
||||
/**
|
||||
* Handles received NONCE payload and builds the NONCE payload for the response.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param nonce_request The received NONCE payload
|
||||
* @param msg the NONCE payload is added to this message_t object.
|
||||
* @return
|
||||
* - DESTROY_ME
|
||||
* - SUCCESS
|
||||
*/
|
||||
status_t (*build_nonce_payload) (private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *msg);
|
||||
|
||||
/**
|
||||
* Build CERTREQ payload for the response.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg the CERTREQ payload is added to this message_t object
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
*/
|
||||
status_t (*build_certreq_payload) (private_responder_init_t *this, message_t *msg);
|
||||
|
||||
|
||||
/**
|
||||
* Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
|
||||
* Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg message_t object to add the Notify payloads
|
||||
*/
|
||||
void (*build_natd_payload) (private_responder_init_t *this, message_t *msg, notify_message_type_t type, host_t *host);
|
||||
|
||||
/**
|
||||
* Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
|
||||
* Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param msg message_t object to add the Notify payloads
|
||||
*/
|
||||
void (*build_natd_payloads) (private_responder_init_t *this, message_t *msg);
|
||||
|
||||
/**
|
||||
* Sends a IKE_SA_INIT reply containing a notify payload.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param notify_payload notify_payload to process
|
||||
*/
|
||||
status_t (*process_notify_payload) (private_responder_init_t *this, notify_payload_t *notify_payload);
|
||||
|
||||
/**
|
||||
* Destroy function called internally of this class after change
|
||||
* to state IKE_SA_INIT_RESPONDED succeeded.
|
||||
*
|
||||
* This destroy function does not destroy objects which were passed to the new state.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*destroy_after_state_change) (private_responder_init_t *this);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of state_t.process_message.
|
||||
*/
|
||||
static status_t process_message(private_responder_init_t *this, message_t *message)
|
||||
{
|
||||
ike_sa_init_responded_t *next_state;
|
||||
chunk_t ike_sa_init_response_data;
|
||||
chunk_t ike_sa_init_request_data;
|
||||
sa_payload_t *sa_request = NULL;
|
||||
ke_payload_t *ke_request = NULL;
|
||||
nonce_payload_t *nonce_request = NULL;
|
||||
host_t *source, *destination;
|
||||
connection_t *connection;
|
||||
iterator_t *payloads;
|
||||
message_t *response;
|
||||
status_t status;
|
||||
|
||||
if (message->get_exchange_type(message) != IKE_SA_INIT)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "message of type %s not supported in state responder_init",
|
||||
mapping_find(exchange_type_m,message->get_exchange_type(message)));
|
||||
return DESTROY_ME;
|
||||
}
|
||||
if (!message->get_request(message))
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT responses not allowed in state ike_sa_init_responded");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* this is the first message to process, so get host infos */
|
||||
source = message->get_source(message);
|
||||
destination = message->get_destination(message);
|
||||
|
||||
connection = charon->connections->get_connection_by_hosts(charon->connections, destination, source);
|
||||
if (connection == NULL)
|
||||
{
|
||||
/* no configuration matches given hosts */
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request does not match any available connection, deleting IKE_SA");
|
||||
/* TODO: inform requestor */
|
||||
return DESTROY_ME;
|
||||
}
|
||||
this->ike_sa->set_connection(this->ike_sa, connection);
|
||||
status = this->ike_sa->update_connection_hosts(this->ike_sa,
|
||||
destination, source);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
/* parse incoming message */
|
||||
status = message->parse_body(message, NULL, NULL);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
if (status == NOT_SUPPORTED)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request contains unsupported payload with critical flag set, "
|
||||
"deleting IKE_SA");
|
||||
this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, UNSUPPORTED_CRITICAL_PAYLOAD, CHUNK_INITIALIZER);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "unable to parse IKE_SA_INIT request, deleting IKE_SA");
|
||||
}
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/*
|
||||
* Precompute NAT-D hashes.
|
||||
* Even though there SHOULD only be a single payload of Notify type
|
||||
* NAT_DETECTION_DESTINATION_IP we precompute both hashes.
|
||||
*/
|
||||
this->natd_hash_i = this->ike_sa->generate_natd_hash(this->ike_sa,
|
||||
message->get_initiator_spi(message),
|
||||
message->get_responder_spi(message),
|
||||
message->get_source(message));
|
||||
this->natd_hash_i_matched = FALSE;
|
||||
this->natd_seen_i = 0;
|
||||
this->natd_hash_r = this->ike_sa->generate_natd_hash(this->ike_sa,
|
||||
message->get_initiator_spi(message),
|
||||
message->get_responder_spi(message),
|
||||
message->get_destination(message));
|
||||
this->natd_hash_r_matched = FALSE;
|
||||
this->natd_seen_r = 0;
|
||||
this->ike_sa->set_my_host_behind_nat(this->ike_sa, FALSE);
|
||||
this->ike_sa->set_other_host_behind_nat(this->ike_sa, FALSE);
|
||||
|
||||
/* Iterate over all payloads.
|
||||
*
|
||||
* The message is already checked for the right payload types.
|
||||
*/
|
||||
payloads = message->get_payload_iterator(message);
|
||||
while (payloads->has_next(payloads))
|
||||
{
|
||||
payload_t *payload;
|
||||
|
||||
payloads->current(payloads, (void**)&payload);
|
||||
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case SECURITY_ASSOCIATION:
|
||||
{
|
||||
sa_request = (sa_payload_t*)payload;
|
||||
break;
|
||||
}
|
||||
case KEY_EXCHANGE:
|
||||
{
|
||||
ke_request = (ke_payload_t*)payload;
|
||||
break;
|
||||
}
|
||||
case NONCE:
|
||||
{
|
||||
nonce_request = (nonce_payload_t*)payload;
|
||||
break;
|
||||
}
|
||||
case NOTIFY:
|
||||
{
|
||||
notify_payload_t *notify_payload = (notify_payload_t *) payload;
|
||||
status = this->process_notify_payload(this, notify_payload);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
payloads->destroy(payloads);
|
||||
return status;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "ignoring payload %s (%d)",
|
||||
mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
payloads->destroy(payloads);
|
||||
|
||||
/* check if we have all payloads */
|
||||
if (!(sa_request && ke_request && nonce_request))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain all required payloads. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* NAT-D */
|
||||
if ((!this->natd_seen_i && this->natd_seen_r > 0)
|
||||
|| (this->natd_seen_i > 0 && !this->natd_seen_r))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request contained wrong number of NAT-D payloads. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
if (this->natd_seen_r > 1)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "warning: IKE_SA_INIT request contained multiple Notify(NAT_DETECTION_DESTINATION_IP) payloads.");
|
||||
}
|
||||
if (this->natd_seen_i > 0 && !this->natd_hash_i_matched)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "remote host is behind NAT, using NAT-Traversal");
|
||||
this->ike_sa->set_other_host_behind_nat(this->ike_sa, TRUE);
|
||||
}
|
||||
if (this->natd_seen_r > 0 && !this->natd_hash_r_matched)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "local host is behind NAT, using NAT-Traversal");
|
||||
this->ike_sa->set_my_host_behind_nat(this->ike_sa, TRUE);
|
||||
charon->event_queue->add_relative(charon->event_queue,
|
||||
(job_t*)send_keepalive_job_create(this->ike_sa->public.get_id((ike_sa_t*)this->ike_sa)),
|
||||
charon->configuration->get_keepalive_interval(charon->configuration));
|
||||
}
|
||||
if (!this->ike_sa->public.is_any_host_behind_nat((ike_sa_t*)this->ike_sa))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "no NAT detected, not using NAT-Traversal");
|
||||
}
|
||||
|
||||
this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response);
|
||||
|
||||
status = this->build_sa_payload(this, sa_request, response);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_response;
|
||||
|
||||
status = this->build_ke_payload(this, ke_request, response);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_response;
|
||||
|
||||
status = this->build_nonce_payload(this, nonce_request, response);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_response;
|
||||
|
||||
status = this->build_certreq_payload(this, response);
|
||||
if (status != SUCCESS)
|
||||
goto destroy_response;
|
||||
|
||||
/* build Notify(NAT-D) payloads */
|
||||
this->build_natd_payloads(this, response);
|
||||
|
||||
/* derive all the keys used in the IKE_SA */
|
||||
status = this->ike_sa->build_transforms(this->ike_sa, this->proposal, this->diffie_hellman, this->received_nonce, this->sent_nonce);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "transform objects could not be created from selected proposal, deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* message can now be sent (must not be destroyed) */
|
||||
status = this->ike_sa->send_response(this->ike_sa, response);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "unable to send IKE_SA_INIT response, deleting IKE_SA");
|
||||
response->destroy(response);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* state can now be changed */
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "create next state object of type IKE_SA_INIT_RESPONDED");
|
||||
|
||||
response = this->ike_sa->get_last_responded_message(this->ike_sa);
|
||||
ike_sa_init_response_data = response->get_packet_data(response);
|
||||
ike_sa_init_request_data = message->get_packet_data(message);
|
||||
|
||||
next_state = ike_sa_init_responded_create(this->ike_sa, this->received_nonce, this->sent_nonce,ike_sa_init_request_data,
|
||||
ike_sa_init_response_data);
|
||||
|
||||
/* state can now be changed */
|
||||
this->ike_sa->set_new_state(this->ike_sa, (state_t *) next_state);
|
||||
this->destroy_after_state_change(this);
|
||||
return SUCCESS;
|
||||
|
||||
destroy_response:
|
||||
response->destroy(response);
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_initiator_init_t.build_sa_payload.
|
||||
*/
|
||||
static status_t build_sa_payload(private_responder_init_t *this,sa_payload_t *sa_request, message_t *msg)
|
||||
{
|
||||
proposal_t *proposal;
|
||||
linked_list_t *proposal_list;
|
||||
connection_t *connection;
|
||||
sa_payload_t* sa_payload;
|
||||
algorithm_t *algo;
|
||||
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "process received SA payload");
|
||||
|
||||
/* get the list of suggested proposals */
|
||||
proposal_list = sa_request->get_proposals (sa_request);
|
||||
|
||||
/* select proposal */
|
||||
this->proposal = connection->select_proposal(connection, proposal_list);
|
||||
while(proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
|
||||
{
|
||||
proposal->destroy(proposal);
|
||||
}
|
||||
proposal_list->destroy(proposal_list);
|
||||
if (this->proposal == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain any acceptable proposals, deleting IKE_SA");
|
||||
this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
/* get selected DH group to force policy, this is very restrictive!? */
|
||||
if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, &algo))
|
||||
{
|
||||
this->dh_group_number = algo->algorithm;
|
||||
}
|
||||
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "SA Payload processed");
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "building SA payload");
|
||||
sa_payload = sa_payload_create_from_proposal(this->proposal);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add SA payload to message");
|
||||
msg->add_payload(msg, (payload_t *) sa_payload);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_initiator_init_t.build_ke_payload.
|
||||
*/
|
||||
static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke_request, message_t *msg)
|
||||
{
|
||||
diffie_hellman_group_t group;
|
||||
ke_payload_t *ke_payload;
|
||||
diffie_hellman_t *dh;
|
||||
chunk_t key_data;
|
||||
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "process received KE payload");
|
||||
group = ke_request->get_dh_group_number(ke_request);
|
||||
|
||||
if (group == MODP_NONE)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "no Diffie-Hellman group to select, deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
if (this->dh_group_number != group)
|
||||
{
|
||||
u_int16_t accepted_group;
|
||||
chunk_t accepted_group_chunk;
|
||||
/* group not same as selected one
|
||||
* Maybe key exchange payload is before SA payload */
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain an acceptable Diffie-Hellman group, deleting IKE_SA");
|
||||
|
||||
accepted_group = htons(this->dh_group_number);
|
||||
accepted_group_chunk.ptr = (u_int8_t*) &(accepted_group);
|
||||
accepted_group_chunk.len = 2;
|
||||
this->ike_sa->send_notify(this->ike_sa,IKE_SA_INIT,INVALID_KE_PAYLOAD,accepted_group_chunk);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* create diffie hellman object to handle DH exchange */
|
||||
dh = diffie_hellman_create(group);
|
||||
if (dh == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "could not generate DH object with group %d, deleting IKE_SA",
|
||||
mapping_find(diffie_hellman_group_m,group) );
|
||||
return DESTROY_ME;
|
||||
}
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "set other DH public value");
|
||||
|
||||
dh->set_other_public_value(dh, ke_request->get_key_exchange_data(ke_request));
|
||||
|
||||
this->diffie_hellman = dh;
|
||||
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "KE payload processed.");
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "building KE payload");
|
||||
this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data);
|
||||
|
||||
ke_payload = ke_payload_create();
|
||||
ke_payload->set_key_exchange_data(ke_payload,key_data);
|
||||
ke_payload->set_dh_group_number(ke_payload, this->dh_group_number);
|
||||
chunk_free(&key_data);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add KE payload to message");
|
||||
msg->add_payload(msg, (payload_t *) ke_payload);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_responder_init_t.build_nonce_payload.
|
||||
*/
|
||||
static status_t build_nonce_payload(private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *msg)
|
||||
{
|
||||
nonce_payload_t *nonce_payload;
|
||||
randomizer_t *randomizer;
|
||||
status_t status;
|
||||
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "process received NONCE payload");
|
||||
free(this->received_nonce.ptr);
|
||||
this->received_nonce = CHUNK_INITIALIZER;
|
||||
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "get NONCE value and store it");
|
||||
this->received_nonce = nonce_request->get_nonce(nonce_request);
|
||||
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "create new NONCE value.");
|
||||
|
||||
randomizer = this->ike_sa->get_randomizer(this->ike_sa);
|
||||
status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce));
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "building NONCE payload");
|
||||
nonce_payload = nonce_payload_create();
|
||||
nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add NONCE payload to message");
|
||||
msg->add_payload(msg, (payload_t *) nonce_payload);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_responder_init_t.build_certreq_payload.
|
||||
*/
|
||||
static status_t build_certreq_payload (private_responder_init_t *this, message_t *msg)
|
||||
{
|
||||
if (FALSE)
|
||||
{
|
||||
certreq_payload_t *certreq_payload;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add CERTREQ payload to message");
|
||||
msg->add_payload(msg, (payload_t *) certreq_payload);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_initiator_init_t.build_natd_payload.
|
||||
*/
|
||||
static void build_natd_payload(private_responder_init_t *this, message_t *msg, notify_message_type_t type, host_t *host)
|
||||
{
|
||||
chunk_t hash;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "building Notify(NAT-D) payload");
|
||||
notify_payload_t *notify_payload;
|
||||
notify_payload = notify_payload_create();
|
||||
/*notify_payload->set_protocol_id(notify_payload, NULL);*/
|
||||
/*notify_payload->set_spi(notify_payload, NULL);*/
|
||||
notify_payload->set_notify_message_type(notify_payload, type);
|
||||
hash = this->ike_sa->generate_natd_hash(this->ike_sa,
|
||||
msg->get_initiator_spi(msg),
|
||||
msg->get_responder_spi(msg),
|
||||
host);
|
||||
notify_payload->set_notification_data(notify_payload, hash);
|
||||
chunk_free(&hash);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "add Notify(NAT-D) payload to message");
|
||||
msg->add_payload(msg, (payload_t *) notify_payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_initiator_init_t.build_natd_payloads.
|
||||
*/
|
||||
static void build_natd_payloads(private_responder_init_t *this, message_t *msg)
|
||||
{
|
||||
connection_t *connection;
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
this->build_natd_payload(this, msg, NAT_DETECTION_SOURCE_IP,
|
||||
connection->get_my_host(connection));
|
||||
this->build_natd_payload(this, msg, NAT_DETECTION_DESTINATION_IP,
|
||||
connection->get_other_host(connection));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_responder_init_t.process_notify_payload.
|
||||
*/
|
||||
static status_t process_notify_payload(private_responder_init_t *this, notify_payload_t *notify_payload)
|
||||
{
|
||||
chunk_t notification_data;
|
||||
notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s",
|
||||
mapping_find(notify_message_type_m, notify_message_type));
|
||||
|
||||
switch (notify_message_type)
|
||||
{
|
||||
case NAT_DETECTION_DESTINATION_IP:
|
||||
{
|
||||
this->natd_seen_r++;
|
||||
if (this->natd_hash_r_matched)
|
||||
return SUCCESS;
|
||||
|
||||
notification_data = notify_payload->get_notification_data(notify_payload);
|
||||
if (chunk_equals(notification_data, this->natd_hash_r))
|
||||
{
|
||||
this->natd_hash_r_matched = TRUE;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash match");
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash mismatch");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
case NAT_DETECTION_SOURCE_IP:
|
||||
{
|
||||
this->natd_seen_i++;
|
||||
if (this->natd_hash_i_matched)
|
||||
return SUCCESS;
|
||||
|
||||
notification_data = notify_payload->get_notification_data(notify_payload);
|
||||
if (chunk_equals(notification_data, this->natd_hash_i))
|
||||
{
|
||||
this->natd_hash_i_matched = TRUE;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash match");
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash mismatch");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
default:
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "IKE_SA_INIT request contained a notify (%d), ignored.",
|
||||
notify_message_type);
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.get_state.
|
||||
*/
|
||||
static ike_sa_state_t get_state(private_responder_init_t *this)
|
||||
{
|
||||
return RESPONDER_INIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.destroy.
|
||||
*/
|
||||
static void destroy(private_responder_init_t *this)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL | LEVEL1, "going to destroy responder init state object");
|
||||
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "destroy nonces");
|
||||
chunk_free(&(this->sent_nonce));
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "destroy received nonce");
|
||||
chunk_free(&(this->received_nonce));
|
||||
|
||||
chunk_free(&(this->natd_hash_i));
|
||||
chunk_free(&(this->natd_hash_r));
|
||||
|
||||
if (this->diffie_hellman != NULL)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "destroy diffie_hellman_t hellman object");
|
||||
this->diffie_hellman->destroy(this->diffie_hellman);
|
||||
}
|
||||
if (this->proposal)
|
||||
{
|
||||
this->proposal->destroy(this->proposal);
|
||||
}
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "destroy object");
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_responder_init_t.destroy_after_state_change
|
||||
*/
|
||||
static void destroy_after_state_change (private_responder_init_t *this)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL | LEVEL1, "Going to destroy responder_init_t state object");
|
||||
|
||||
chunk_free(&(this->natd_hash_i));
|
||||
chunk_free(&(this->natd_hash_r));
|
||||
|
||||
/* destroy diffie hellman object */
|
||||
if (this->diffie_hellman != NULL)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "destroy diffie_hellman_t object");
|
||||
this->diffie_hellman->destroy(this->diffie_hellman);
|
||||
}
|
||||
if (this->proposal)
|
||||
{
|
||||
this->proposal->destroy(this->proposal);
|
||||
}
|
||||
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "destroy object");
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa)
|
||||
{
|
||||
private_responder_init_t *this = malloc_thing(private_responder_init_t);
|
||||
|
||||
/* interface functions */
|
||||
this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
|
||||
this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
|
||||
this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
|
||||
|
||||
/* private functions */
|
||||
this->build_sa_payload = build_sa_payload;
|
||||
this->build_ke_payload = build_ke_payload;
|
||||
this->build_nonce_payload = build_nonce_payload;
|
||||
this->build_certreq_payload = build_certreq_payload;
|
||||
this->destroy_after_state_change = destroy_after_state_change;
|
||||
this->process_notify_payload = process_notify_payload;
|
||||
this->build_natd_payload = build_natd_payload;
|
||||
this->build_natd_payloads = build_natd_payloads;
|
||||
|
||||
/* private data */
|
||||
this->ike_sa = ike_sa;
|
||||
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
|
||||
this->sent_nonce = CHUNK_INITIALIZER;
|
||||
this->received_nonce = CHUNK_INITIALIZER;
|
||||
this->dh_group_number = MODP_NONE;
|
||||
this->diffie_hellman = NULL;
|
||||
this->proposal = NULL;
|
||||
this->natd_hash_i = CHUNK_INITIALIZER;
|
||||
this->natd_hash_i_matched = FALSE;
|
||||
this->natd_seen_i = 0;
|
||||
this->natd_hash_r = CHUNK_INITIALIZER;
|
||||
this->natd_hash_r_matched = FALSE;
|
||||
this->natd_seen_r = 0;
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/**
|
||||
* @file responder_init.h
|
||||
*
|
||||
* @brief Interface of responder_init_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef RESPONDER_INIT_H_
|
||||
#define RESPONDER_INIT_H_
|
||||
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/states/state.h>
|
||||
|
||||
|
||||
typedef struct responder_init_t responder_init_t;
|
||||
|
||||
/**
|
||||
* @brief This class represents an IKE_SA state when
|
||||
* initializing a connection as responder.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - responder_init_create()
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
struct responder_init_t {
|
||||
/**
|
||||
* The state_t interface.
|
||||
*/
|
||||
state_t state_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor of class responder_init_t.
|
||||
*
|
||||
* The following functions of the assigned protected_ike_sa_t object are being called with
|
||||
* valid values after successfully processing a received message and before changing
|
||||
* to next state IKE_SA_INIT_RESPONDED:
|
||||
* - protected_ike_sa_t.set_connection()
|
||||
* - protected_ike_sa_t.set_my_host()
|
||||
* - protected_ike_sa_t.set_other_host()
|
||||
* - protected_ike_sa_t.compute_secrets()
|
||||
* - protected_ike_sa_t.create_transforms_from_proposal()
|
||||
*
|
||||
* @param ike_sa assigned IKE_SA
|
||||
*
|
||||
* @return responder_init_t object
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa);
|
||||
|
||||
#endif /*RESPONDER_INIT_H_*/
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* @file state.c
|
||||
*
|
||||
* @brief Interface state_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "state.h"
|
||||
|
||||
|
||||
/**
|
||||
* String mappings for ike_sa_state_t.
|
||||
*/
|
||||
mapping_t ike_sa_state_m[] = {
|
||||
{INITIATOR_INIT, "INITIATOR_INIT"},
|
||||
{RESPONDER_INIT, "RESPONDER_INIT"},
|
||||
{IKE_SA_INIT_REQUESTED, "IKE_SA_INIT_REQUESTED"},
|
||||
{IKE_SA_INIT_RESPONDED, "IKE_SA_INIT_RESPONDED"},
|
||||
{IKE_AUTH_REQUESTED, "IKE_AUTH_REQUESTED"},
|
||||
{IKE_SA_ESTABLISHED, "IKE_SA_ESTABLISHED"},
|
||||
{DELETE_IKE_SA_REQUESTED, "DELETE_IKE_SA_REQUESTED"},
|
||||
{CREATE_CHILD_SA_REQUESTED, "CREATE_CHILD_SA_REQUESTED"},
|
||||
{DELETE_CHILD_SA_REQUESTED, "DELETE_CHILD_SA_REQUESTED"},
|
||||
{MAPPING_END, NULL}
|
||||
};
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
/**
|
||||
* @file state.h
|
||||
*
|
||||
* @brief Interface state_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef STATE_H_
|
||||
#define STATE_H_
|
||||
|
||||
#include <definitions.h>
|
||||
#include <types.h>
|
||||
#include <encoding/message.h>
|
||||
|
||||
typedef enum ike_sa_state_t ike_sa_state_t;
|
||||
|
||||
/**
|
||||
* States in which a IKE_SA can be.
|
||||
*
|
||||
* @todo Support of more states (CHILD_SA_REQUESTED, etc...)
|
||||
*
|
||||
* @see state_t for state diagram
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
enum ike_sa_state_t {
|
||||
|
||||
/**
|
||||
* @brief IKE_SA is in initial state as initiator and is going to initiate a new connection.
|
||||
*
|
||||
* Next state following this state is IKE_SA_INIT_REQUESTED.
|
||||
*
|
||||
* Implemented in class initiator_init_t.
|
||||
*/
|
||||
INITIATOR_INIT = 1,
|
||||
|
||||
/**
|
||||
* @brief IKE_SA is in initial state as responder and is going to respond to a initiated connection.
|
||||
*
|
||||
* Next state following this state is IKE_SA_INIT_RESPONDED.
|
||||
*
|
||||
* Implemented in class responder_init_t.
|
||||
*/
|
||||
RESPONDER_INIT,
|
||||
|
||||
/**
|
||||
* @brief A IKE_SA_INIT request was sent. In this state a reply of type IKE_SA_INIT is expected.
|
||||
*
|
||||
* Two states are possible as next states:
|
||||
* - IKE_AUTH_REQUESTED if IKE_SA_INIT reply could successfully processed and IKE_AUTH request could be sent.
|
||||
* - INITIATOR_INIT if selected DH group was not the one selected by other peer.
|
||||
*
|
||||
* Implemented in class ike_sa_init_requested_t.
|
||||
*/
|
||||
IKE_SA_INIT_REQUESTED,
|
||||
|
||||
/**
|
||||
* @brief A IKE_SA_INIT response was sent. In this state a request of type IKE_AUTH is expected.
|
||||
*
|
||||
* Next state following this state is IKE_SA_ESTABLISHED.
|
||||
*
|
||||
* Implemented in class ike_sa_init_responded_t.
|
||||
*/
|
||||
IKE_SA_INIT_RESPONDED,
|
||||
|
||||
/**
|
||||
* @brief An IKE_AUTH request was sent after a successful IKE_SA_INIT-exchange.
|
||||
*
|
||||
* Next state following this state is IKE_SA_ESTABLISHED.
|
||||
*
|
||||
* Implemented in class ike_auth_requested_t.
|
||||
*/
|
||||
IKE_AUTH_REQUESTED,
|
||||
|
||||
/**
|
||||
* @brief An IKE_AUTH exchange was successfuly handled either as initiator or responder.
|
||||
*
|
||||
* In this state, all the informations for an IKE_SA and one CHILD_SA are known.
|
||||
*
|
||||
* Implemented in class ike_sa_established_t.
|
||||
*/
|
||||
IKE_SA_ESTABLISHED,
|
||||
|
||||
/**
|
||||
* @brief A rekeying/create CHILD_SA request was sent.
|
||||
*
|
||||
* Implemented in class create_child_sa_requested.
|
||||
*/
|
||||
CREATE_CHILD_SA_REQUESTED,
|
||||
|
||||
/**
|
||||
* @brief A delete CHILD_SA request was sent.
|
||||
*
|
||||
* Implemented in class delete_child_sa_requested.
|
||||
*/
|
||||
DELETE_CHILD_SA_REQUESTED,
|
||||
|
||||
/**
|
||||
* @brief An IKE SA has sent a DELETE IKE_SA to the other peer.
|
||||
*
|
||||
* After a call to ike_sa.close(), the IKE_SA sends a delete message
|
||||
* to the remote peer and switches to this state. It waits until the
|
||||
* message is aknowledged, or a certain timout occurs.
|
||||
*
|
||||
* Implemented in class delete_requested.
|
||||
*/
|
||||
DELETE_IKE_SA_REQUESTED,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* String mappings for ike_sa_state_t.
|
||||
*/
|
||||
extern mapping_t ike_sa_state_m[];
|
||||
|
||||
|
||||
typedef struct state_t state_t;
|
||||
|
||||
/**
|
||||
* @brief This interface represents an IKE_SA state.
|
||||
*
|
||||
* A state_t object is responsible to handle incoming messages. States
|
||||
* are exclusive, an IKE_SA is exactly in one state. They are used on IKE_SA
|
||||
* setup, as there is a strict scheme message exchange follow. This can be
|
||||
* mapped in a state machine. Every state is represented in a single class,
|
||||
* and the IKE_SA may switch these states by replacing the owned state.
|
||||
@verbatim
|
||||
initiator responder
|
||||
--------- ---------
|
||||
|
||||
¦ ¦
|
||||
V ¦
|
||||
+-----------------------+ ¦
|
||||
¦ initiator_init ¦ msg1 V
|
||||
+-----------------------+ -----> +-----------------------+
|
||||
¦ msg2 ¦ responder_init ¦
|
||||
V <----- +-----------------------+
|
||||
+-----------------------+ ¦
|
||||
¦ ike_sa_init_requested ¦ msg3 V
|
||||
+-----------------------+ -----> +-----------------------+
|
||||
¦ msg4 ¦ ike_sa_init_requested ¦
|
||||
V <----- +-----------------------+
|
||||
+-----------------------+ ¦
|
||||
¦ ike_auth_requested ¦ ¦
|
||||
+-----------------------+ ¦
|
||||
¦ ¦
|
||||
V V
|
||||
+---------------------------+
|
||||
¦ ike_sa_established ¦
|
||||
+---------------------------+
|
||||
¦
|
||||
V
|
||||
+---------------------------+
|
||||
¦ delete_requested ¦
|
||||
+---------------------------+
|
||||
|
||||
msg1 = IKE_SA_INIT request
|
||||
msg2 = IKE_SA_INIT response
|
||||
msg3 = IKE_AUTH request
|
||||
msg4 = IKE_AUTH response
|
||||
@endverbatim
|
||||
* Every state can be left by deleting the IKE_SA, except the state
|
||||
* ike_sa_established: it must switch to the delete_requested state first,
|
||||
* as the peer must be informed about the delete.
|
||||
*
|
||||
* For the handling of message in a established IKE_SA, another concept is used.
|
||||
* The state-concept is good if a single state is possible. But in a established
|
||||
* IKE_SA, there is no strict message order, and if a window size > 1 is used,
|
||||
* multiple "states" would be possible. We call this transactions, better
|
||||
* descripted in the transaction_t interface.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - initiator_init_create()
|
||||
* - responder_init_create()
|
||||
* - ike_sa_init_requested_create()
|
||||
* - ike_sa_init_responded_create()
|
||||
* - ike_auth_requested_create()
|
||||
* - ike_sa_established_create()
|
||||
* - delete_requested_create()
|
||||
*
|
||||
* @ingroup states
|
||||
*/
|
||||
struct state_t {
|
||||
|
||||
/**
|
||||
* @brief Processes a incoming IKEv2-Message of type message_t.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param[in] message message_t object to process
|
||||
* @return
|
||||
* - SUCCESSFUL
|
||||
* - FAILED
|
||||
* - DESTROY_ME if belonging IKE_SA should be deleted
|
||||
*/
|
||||
status_t (*process_message) (state_t *this,message_t *message);
|
||||
|
||||
/**
|
||||
* @brief Get the current state representing by this state_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return state
|
||||
*/
|
||||
ike_sa_state_t (*get_state) (state_t *this);
|
||||
|
||||
/**
|
||||
* @brief Destroys a state_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*destroy) (state_t *this);
|
||||
};
|
||||
|
||||
#endif /* STATE_H_ */
|
||||
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* @file dead_peer_detection.c
|
||||
*
|
||||
* @brief Implementation of the dead_peer_detection transaction.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "dead_peer_detection.h"
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
|
||||
typedef struct private_dead_peer_detection_t private_dead_peer_detection_t;
|
||||
|
||||
/**
|
||||
* Private members of a dead_peer_detection_t object..
|
||||
*/
|
||||
struct private_dead_peer_detection_t {
|
||||
|
||||
/**
|
||||
* Public methods and transaction_t interface.
|
||||
*/
|
||||
dead_peer_detection_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Message sent by our peer, if already generated
|
||||
*/
|
||||
message_t *message;
|
||||
|
||||
/**
|
||||
* Message ID this transaction uses
|
||||
*/
|
||||
u_int32_t message_id;
|
||||
|
||||
/**
|
||||
* Times we did send the request
|
||||
*/
|
||||
u_int32_t requested;
|
||||
|
||||
/**
|
||||
* Assigned logger.
|
||||
*/
|
||||
logger_t *logger;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of transaction_t.get_message_id.
|
||||
*/
|
||||
static u_int32_t get_message_id(private_dead_peer_detection_t *this)
|
||||
{
|
||||
return this->message_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of transaction_t.requested.
|
||||
*/
|
||||
static u_int32_t requested(private_dead_peer_detection_t *this)
|
||||
{
|
||||
return this->requested++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of transaction_t.get_request.
|
||||
*/
|
||||
static status_t get_request(private_dead_peer_detection_t *this, message_t **result)
|
||||
{
|
||||
message_t *request;
|
||||
connection_t *connection;
|
||||
host_t *me, *other;
|
||||
|
||||
/* check if we already have built a message (retransmission) */
|
||||
if (this->message)
|
||||
{
|
||||
*result = this->message;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
me = connection->get_my_host(connection);
|
||||
other = connection->get_other_host(connection);
|
||||
|
||||
/* build the request */
|
||||
request = message_create();
|
||||
request->set_source(request, me->clone(me));
|
||||
request->set_destination(request, other->clone(other));
|
||||
request->set_exchange_type(request, INFORMATIONAL);
|
||||
request->set_request(request, TRUE);
|
||||
request->set_message_id(request, this->message_id);
|
||||
request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
|
||||
/* apply for caller */
|
||||
*result = request;
|
||||
/* store for retransmission */
|
||||
this->message = request;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of transaction_t.get_response.
|
||||
*/
|
||||
static status_t get_response(private_dead_peer_detection_t *this, message_t *request,
|
||||
message_t **result, transaction_t **next)
|
||||
{
|
||||
host_t *me, *other;
|
||||
message_t *response;
|
||||
connection_t *connection;
|
||||
|
||||
/* check if we already have built a response (retransmission) */
|
||||
if (this->message)
|
||||
{
|
||||
*result = this->message;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
me = connection->get_my_host(connection);
|
||||
other = connection->get_other_host(connection);
|
||||
|
||||
/* set up response */
|
||||
response = message_create();
|
||||
response->set_source(response, me->clone(me));
|
||||
response->set_destination(response, other->clone(other));
|
||||
response->set_exchange_type(response, INFORMATIONAL);
|
||||
response->set_request(response, FALSE);
|
||||
response->set_message_id(response, this->message_id);
|
||||
response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
|
||||
this->message = response;
|
||||
*result = response;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of transaction_t.conclude
|
||||
*/
|
||||
static status_t conclude(private_dead_peer_detection_t *this, message_t *response,
|
||||
transaction_t **transaction)
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* implements transaction_t.destroy
|
||||
*/
|
||||
static void destroy(private_dead_peer_detection_t *this)
|
||||
{
|
||||
if (this->message)
|
||||
{
|
||||
this->message->destroy(this->message);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
dead_peer_detection_t *dead_peer_detection_create(ike_sa_t *ike_sa, u_int32_t message_id)
|
||||
{
|
||||
private_dead_peer_detection_t *this = malloc_thing(private_dead_peer_detection_t);
|
||||
|
||||
/* transaction interface functions */
|
||||
this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
|
||||
this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
|
||||
this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
|
||||
this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
|
||||
this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
|
||||
this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
|
||||
|
||||
/* private data */
|
||||
this->ike_sa = ike_sa;
|
||||
this->message_id = message_id;
|
||||
this->message = NULL;
|
||||
this->requested = 0;
|
||||
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @file dead_peer_detection.h
|
||||
*
|
||||
* @brief Interface of transaction dead_peer_detection.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DEAD_PEER_DETECTION_H_
|
||||
#define DEAD_PEER_DETECTION_H_
|
||||
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/transactions/transaction.h>
|
||||
|
||||
|
||||
typedef struct dead_peer_detection_t dead_peer_detection_t;
|
||||
|
||||
/**
|
||||
* @brief A transaction used to detect dead peers.
|
||||
*
|
||||
* In IKEv2, dead peer detection is done using empty
|
||||
* informational messages. These must be acknowledged.
|
||||
*
|
||||
* @ingroup transactions
|
||||
*/
|
||||
struct dead_peer_detection_t {
|
||||
|
||||
/**
|
||||
* The transaction_t interface.
|
||||
*/
|
||||
transaction_t transaction;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new transaction which detects dead peers.
|
||||
*
|
||||
* @param ike_sa assigned IKE_SA
|
||||
* @param message_id message ids used in this transaction
|
||||
* @return created dead_peer_detection transaction
|
||||
*
|
||||
* @ingroup transactions
|
||||
*/
|
||||
dead_peer_detection_t *dead_peer_detection_create(ike_sa_t *ike_sa, u_int32_t message_id);
|
||||
|
||||
#endif /* DEAD_PEER_DETECTION_H_ */
|
||||
@@ -0,0 +1,271 @@
|
||||
/**
|
||||
* @file delete_ike_sa.c
|
||||
*
|
||||
* @brief Implementation of the delete_ike_sa transaction.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "delete_ike_sa.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/delete_payload.h>
|
||||
|
||||
|
||||
typedef struct private_delete_ike_sa_t private_delete_ike_sa_t;
|
||||
|
||||
/**
|
||||
* Private members of a delete_ike_sa_t object..
|
||||
*/
|
||||
struct private_delete_ike_sa_t {
|
||||
|
||||
/**
|
||||
* Public methods and transaction_t interface.
|
||||
*/
|
||||
delete_ike_sa_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Message sent by our peer, if already generated
|
||||
*/
|
||||
message_t *message;
|
||||
|
||||
/**
|
||||
* Message ID this transaction uses
|
||||
*/
|
||||
u_int32_t message_id;
|
||||
|
||||
/**
|
||||
* Times we did send the request
|
||||
*/
|
||||
u_int32_t requested;
|
||||
|
||||
/**
|
||||
* Assigned logger.
|
||||
*/
|
||||
logger_t *logger;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of transaction_t.get_message_id.
|
||||
*/
|
||||
static u_int32_t get_message_id(private_delete_ike_sa_t *this)
|
||||
{
|
||||
return this->message_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of transaction_t.requested.
|
||||
*/
|
||||
static u_int32_t requested(private_delete_ike_sa_t *this)
|
||||
{
|
||||
return this->requested++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of transaction_t.get_request.
|
||||
*/
|
||||
static status_t get_request(private_delete_ike_sa_t *this, message_t **result)
|
||||
{
|
||||
message_t *request;
|
||||
connection_t *connection;
|
||||
host_t *me, *other;
|
||||
delete_payload_t *delete_payload;
|
||||
|
||||
/* check if we already have built a message (retransmission) */
|
||||
if (this->message)
|
||||
{
|
||||
*result = this->message;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
me = connection->get_my_host(connection);
|
||||
other = connection->get_other_host(connection);
|
||||
|
||||
/* build the request */
|
||||
request = message_create();
|
||||
request->set_source(request, me->clone(me));
|
||||
request->set_destination(request, other->clone(other));
|
||||
request->set_exchange_type(request, INFORMATIONAL);
|
||||
request->set_request(request, TRUE);
|
||||
request->set_message_id(request, this->message_id);
|
||||
request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
|
||||
/* apply for caller */
|
||||
*result = request;
|
||||
/* store for retransmission */
|
||||
this->message = request;
|
||||
|
||||
delete_payload = delete_payload_create(PROTO_IKE);
|
||||
request->add_payload(request, (payload_t*)delete_payload);
|
||||
|
||||
/* transit to state SA_DELETING */
|
||||
this->ike_sa->set_state(this->ike_sa, SA_DELETING);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of transaction_t.get_response.
|
||||
*/
|
||||
static status_t get_response(private_delete_ike_sa_t *this, message_t *request,
|
||||
message_t **result, transaction_t **next)
|
||||
{
|
||||
host_t *me, *other;
|
||||
message_t *response;
|
||||
iterator_t *payloads;
|
||||
delete_payload_t *delete_request = NULL;
|
||||
connection_t *connection;
|
||||
|
||||
/* check message type */
|
||||
if (request->get_exchange_type(request) != INFORMATIONAL)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR,
|
||||
"INFORMATIONAL response of invalid type, deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* check if we already have built a response (retransmission)
|
||||
* this only happens in special simultanous transaction cases,
|
||||
* as we delete the IKE_SA after the response is sent. */
|
||||
if (this->message)
|
||||
{
|
||||
*result = this->message;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
me = connection->get_my_host(connection);
|
||||
other = connection->get_other_host(connection);
|
||||
|
||||
/* set up response */
|
||||
response = message_create();
|
||||
response->set_source(response, me->clone(me));
|
||||
response->set_destination(response, other->clone(other));
|
||||
response->set_exchange_type(response, INFORMATIONAL);
|
||||
response->set_request(response, FALSE);
|
||||
response->set_message_id(response, this->message_id);
|
||||
response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
|
||||
this->message = response;
|
||||
*result = response;
|
||||
|
||||
/* iterate over all payloads */
|
||||
payloads = request->get_payload_iterator(request);
|
||||
while (payloads->has_next(payloads))
|
||||
{
|
||||
payload_t *payload;
|
||||
payloads->current(payloads, (void**)&payload);
|
||||
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case DELETE:
|
||||
{
|
||||
delete_request = (delete_payload_t *)payload;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "ignoring payload %s (%d)",
|
||||
mapping_find(payload_type_m, payload->get_type(payload)),
|
||||
payload->get_type(payload));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
payloads->destroy(payloads);
|
||||
|
||||
if (delete_request &&
|
||||
delete_request->get_protocol_id(delete_request) == PROTO_IKE)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL,
|
||||
"DELETE request for IKE_SA received, deleting IKE_SA");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* should not happen, as we preparsed this at transaction construction */
|
||||
this->logger->log(this->logger, CONTROL,
|
||||
"received a weird DELETE request for IKE_SA, deleting anyway");
|
||||
}
|
||||
if (this->ike_sa->get_state(this->ike_sa) == SA_DELETING)
|
||||
{
|
||||
/* if we are already deleting an IKE_SA, we do not destroy. We wait
|
||||
* until we get the response for our initiated delete. */
|
||||
return SUCCESS;
|
||||
}
|
||||
this->ike_sa->set_state(this->ike_sa, SA_DELETING);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of transaction_t.conclude
|
||||
*/
|
||||
static status_t conclude(private_delete_ike_sa_t *this, message_t *response,
|
||||
transaction_t **transaction)
|
||||
{
|
||||
/* check message type */
|
||||
if (response->get_exchange_type(response) != INFORMATIONAL)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR,
|
||||
"INFORMATIONAL response of invalid type, deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
/* this is only an acknowledge. We can't do anything here, but delete
|
||||
* the IKE_SA. */
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/**
|
||||
* implements transaction_t.destroy
|
||||
*/
|
||||
static void destroy(private_delete_ike_sa_t *this)
|
||||
{
|
||||
if (this->message)
|
||||
{
|
||||
this->message->destroy(this->message);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
delete_ike_sa_t *delete_ike_sa_create(ike_sa_t *ike_sa, u_int32_t message_id)
|
||||
{
|
||||
private_delete_ike_sa_t *this = malloc_thing(private_delete_ike_sa_t);
|
||||
|
||||
/* transaction interface functions */
|
||||
this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
|
||||
this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
|
||||
this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
|
||||
this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
|
||||
this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
|
||||
this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
|
||||
|
||||
/* private data */
|
||||
this->ike_sa = ike_sa;
|
||||
this->message_id = message_id;
|
||||
this->message = NULL;
|
||||
this->requested = 0;
|
||||
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @file delete_ike_sa.h
|
||||
*
|
||||
* @brief Interface of transaction delete_ike_sa.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DELETE_IKE_SA_H_
|
||||
#define DELETE_IKE_SA_H_
|
||||
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/transactions/transaction.h>
|
||||
|
||||
|
||||
typedef struct delete_ike_sa_t delete_ike_sa_t;
|
||||
|
||||
/**
|
||||
* @brief A transaction used to delete the IKE_SA.
|
||||
*
|
||||
* Notation as follows:
|
||||
* Mx{D} means: Message, with message ID "x", containing a Delete payload
|
||||
*
|
||||
* The clarifcation Document says in 5.8, that a IKE_SA delete should not
|
||||
* be acknowledged with the same delete. This only makes sense for CHILD_SAs,
|
||||
* as they are paired. IKE_SAs are not, there is only one for both ends.
|
||||
*
|
||||
* Normal case:
|
||||
* ----------------
|
||||
* Mx{D} -->
|
||||
* <-- Mx{}
|
||||
* Delete request is sent, and we wait for the acknowledge.
|
||||
*
|
||||
* Special case 1:
|
||||
* ---------------
|
||||
* Mx{D} -->
|
||||
* <-- My{D}
|
||||
* My{} -->
|
||||
* <-- Mx{}
|
||||
* Both initate a delete at the same time. We ack the delete, but wait for
|
||||
* our delete to be acknowledged.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - delete_ike_sa_create()
|
||||
* - transaction_create() with the appropriate message
|
||||
*
|
||||
* @ingroup transactions
|
||||
*/
|
||||
struct delete_ike_sa_t {
|
||||
|
||||
/**
|
||||
* The transaction_t interface.
|
||||
*/
|
||||
transaction_t transaction;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new transaction which deletes the IKE_SA.
|
||||
*
|
||||
* @param ike_sa assigned IKE_SA
|
||||
* @param message_id message ids used in this transaction
|
||||
* @return created delete_ike_sa transaction
|
||||
*
|
||||
* @ingroup transactions
|
||||
*/
|
||||
delete_ike_sa_t *delete_ike_sa_create(ike_sa_t *ike_sa, u_int32_t message_id);
|
||||
|
||||
#endif /* DELETE_IKE_SA_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @file ike_auth.h
|
||||
*
|
||||
* @brief Interface of transaction ike_auth.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef IKE_AUTH_H_
|
||||
#define IKE_AUTH_H_
|
||||
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/transactions/transaction.h>
|
||||
|
||||
|
||||
typedef struct ike_auth_t ike_auth_t;
|
||||
|
||||
/**
|
||||
* @brief A transaction for the second message exchange to authenticate an IKE_SA.
|
||||
*
|
||||
* The second transaction is encrypted and authenticates the peers. It also
|
||||
* sets up a first CHILD_SA.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - ike_auth_create()
|
||||
* - transaction_create() with the appropriate message
|
||||
*
|
||||
* @ingroup transactions
|
||||
*/
|
||||
struct ike_auth_t {
|
||||
|
||||
/**
|
||||
* The transaction_t interface.
|
||||
*/
|
||||
transaction_t transaction;
|
||||
|
||||
/**
|
||||
* @brief Set the nonces used in the previous ike_sa_init transaction.
|
||||
*
|
||||
* The nonces are used to create the authentication data.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param nonce_i initiator chosen nonce
|
||||
* @param nonce_r responder chosen nonce
|
||||
*/
|
||||
void (*set_nonces) (ike_auth_t* this, chunk_t nonce_i, chunk_t nonce_r);
|
||||
|
||||
/**
|
||||
* @brief Set the messages used in the previous ike_sa_init transaction.
|
||||
*
|
||||
* The messages are used to create the authentication data.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param request encoded request message as a chunk
|
||||
* @param response encoded response message as a chunk
|
||||
*/
|
||||
void (*set_init_messages) (ike_auth_t* this, chunk_t request, chunk_t response);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new transaction which processes IKE_AUTH exchanges.
|
||||
*
|
||||
* @param ike_sa assigned IKE_SA
|
||||
* @param message_id message ids used in this transaction
|
||||
* @return created ike_auth transaction
|
||||
*
|
||||
* @ingroup transactions
|
||||
*/
|
||||
ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, u_int32_t message_id);
|
||||
|
||||
#endif /* IKE_AUTH_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @file ike_sa_init.h
|
||||
*
|
||||
* @brief Interface of transaction ike_sa_init.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef IKE_SA_INIT_H_
|
||||
#define IKE_SA_INIT_H_
|
||||
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/transactions/transaction.h>
|
||||
|
||||
|
||||
typedef struct ike_sa_init_t ike_sa_init_t;
|
||||
|
||||
/**
|
||||
* @brief A transaction for the first message exchange to set up an IKE_SA.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - ike_sa_init_create()
|
||||
* - transaction_create() with the appropriate message
|
||||
*
|
||||
* @ingroup transactions
|
||||
*/
|
||||
struct ike_sa_init_t {
|
||||
|
||||
/**
|
||||
* The transaction_t interface.
|
||||
*/
|
||||
transaction_t transaction;
|
||||
|
||||
/**
|
||||
* @brief Set the Diffie Hellman group to use for initiating.
|
||||
*
|
||||
* If a first exchange fails with a INVALID_KE_PAYLOAD, the second
|
||||
* try uses the DH group proposed by the responder.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param dh_group diffie hellman group to use
|
||||
* @return FALSE, if DH group not allowed/supported
|
||||
*/
|
||||
bool (*use_dh_group) (ike_sa_init_t* this, diffie_hellman_group_t dh_group);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new transaction which processes IKE_SA_INIT exchanges.
|
||||
*
|
||||
* @param ike_sa assigned IKE_SA
|
||||
* @param message_id message ids used in this transaction
|
||||
* @return created ike_sa_init transaction
|
||||
*
|
||||
* @ingroup transactions
|
||||
*/
|
||||
ike_sa_init_t *ike_sa_init_create(ike_sa_t *ike_sa, u_int32_t message_id);
|
||||
|
||||
#endif /* IKE_SA_INIT_H_ */
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* @file transaction.c
|
||||
*
|
||||
* @brief Generic contstructor for the different transaction types.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "transaction.h"
|
||||
|
||||
#include <sa/child_sa.h>
|
||||
#include <sa/transactions/ike_sa_init.h>
|
||||
#include <sa/transactions/ike_auth.h>
|
||||
#include <sa/transactions/delete_ike_sa.h>
|
||||
#include <sa/transactions/dead_peer_detection.h>
|
||||
#include <encoding/payloads/ts_payload.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <encoding/payloads/delete_payload.h>
|
||||
#include <utils/logger_manager.h>
|
||||
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
transaction_t *transaction_create(ike_sa_t *ike_sa, message_t *request)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
payload_t *current;
|
||||
notify_payload_t *notify;
|
||||
transaction_t *transaction = NULL;
|
||||
u_int32_t message_id;
|
||||
|
||||
if (!request->get_request(request))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
message_id = request->get_message_id(request);
|
||||
|
||||
switch (request->get_exchange_type(request))
|
||||
{
|
||||
case IKE_SA_INIT:
|
||||
{
|
||||
transaction = (transaction_t*)ike_sa_init_create(ike_sa, message_id);
|
||||
break;
|
||||
}
|
||||
case IKE_AUTH:
|
||||
{
|
||||
/* IKE_AUTH is always created in IKE_SA_INIT, it never should
|
||||
* appear alone */
|
||||
break;
|
||||
}
|
||||
case CREATE_CHILD_SA:
|
||||
{
|
||||
/* look for a REKEY_SA notify */
|
||||
iterator = request->get_payload_iterator(request);
|
||||
while (iterator->has_next(iterator))
|
||||
{
|
||||
iterator->current(iterator, (void**)¤t);
|
||||
if (current->get_type(current) != NOTIFY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
notify = (notify_payload_t*)current;
|
||||
if (notify->get_notify_type(notify) != REKEY_SA)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
switch (notify->get_protocol_id(notify))
|
||||
{
|
||||
case PROTO_IKE:
|
||||
/* TODO: transaction = rekey_ike_sa_create(ike_sa, message_id); */
|
||||
break;
|
||||
case PROTO_AH:
|
||||
case PROTO_ESP:
|
||||
{
|
||||
/* TODO: transaction = rekey_child_sa_create(ike_sa, message_id); */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (transaction)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
break;
|
||||
}
|
||||
case INFORMATIONAL:
|
||||
{
|
||||
u_int payload_count = 0;
|
||||
iterator = request->get_payload_iterator(request);
|
||||
while (iterator->has_next(iterator))
|
||||
{
|
||||
payload_count++;
|
||||
iterator->current(iterator, (void**)¤t);
|
||||
switch (current->get_type(current))
|
||||
{
|
||||
case DELETE:
|
||||
{
|
||||
delete_payload_t *delete_payload;
|
||||
delete_payload = (delete_payload_t*)current;
|
||||
if (delete_payload->get_protocol_id(delete_payload) == PROTO_IKE)
|
||||
{
|
||||
transaction = (transaction_t*)
|
||||
delete_ike_sa_create(ike_sa, message_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (transaction)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
if (payload_count == 0)
|
||||
{
|
||||
transaction = (transaction_t*)
|
||||
dead_peer_detection_create(ike_sa, message_id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/**
|
||||
* @file transaction.h
|
||||
*
|
||||
* @brief Interface transaction_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef TRANSACTION_H_
|
||||
#define TRANSACTION_H_
|
||||
|
||||
#include <types.h>
|
||||
#include <encoding/message.h>
|
||||
#include <sa/ike_sa.h>
|
||||
|
||||
|
||||
typedef struct transaction_t transaction_t;
|
||||
|
||||
/**
|
||||
* @brief This interface represents a transaction an established IKE_SA can do.
|
||||
*
|
||||
* To every transaction, a message ID is associated. IKEv2 uses strict message
|
||||
* IDs, which are equal for a request/response pair in a transaction.
|
||||
* An initiator of a transaction does the following:
|
||||
* - create the transaction using a specific constructor
|
||||
* - call request() to get the message for initiaton
|
||||
* - call conclude() to process received reply
|
||||
* The other peer does the following:
|
||||
* - create a transanction using the generic transaction constructor
|
||||
* - call respond() to get a reply to send
|
||||
*
|
||||
* The responder must not destroy the transaction, until the
|
||||
* initiator initiates another transaction (or a number of transactions
|
||||
* > window size). This allows us to redo a transaction in case of a
|
||||
* message loss. The initiator can destroy the the transaction once
|
||||
* the conclude() function is called.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - transaction_create()
|
||||
* - ike_sa_init_create()
|
||||
* - ike_auth_create()
|
||||
*
|
||||
* @ingroup transactions
|
||||
*/
|
||||
struct transaction_t {
|
||||
|
||||
/**
|
||||
* @brief Get the request to use for initiating the transaction.
|
||||
*
|
||||
* A transaction creates a request only once. The request is stored
|
||||
* internally and may be queried multiple times for retransmission.
|
||||
* The transaction is not responsible for generating/encrypting the
|
||||
* message, this is the job of the caller. But it MAY be already
|
||||
* generated when calling get_request() the second time.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param[out] request resultin request
|
||||
* @return
|
||||
* - FAILED if transaction failed
|
||||
* - DESTROY_ME if transaction failed and IKE SA
|
||||
* must be deleted
|
||||
* - SUCCESS
|
||||
*/
|
||||
status_t (*get_request) (transaction_t *this, message_t **request);
|
||||
|
||||
/**
|
||||
* @brief Build the response for a received request.
|
||||
*
|
||||
* A transaction creates a response only once for a unique request.
|
||||
* This allows the use of get_response multiple times for retransmission
|
||||
* purposes.
|
||||
* The transaction is not responsible for generating/encrypting the
|
||||
* response, nor is it responsible for decrypting/parsing the request.
|
||||
* This is the job of the caller. But the response MAY be already
|
||||
* generated when calling get_request() the second time.
|
||||
* The initiator waits for a response, so we send one in every case. This
|
||||
* means response points always to a valid message. This message
|
||||
* may not be modified or destroyed, it gets destroyed along with the
|
||||
* transaction.
|
||||
* The get_response() function may return a next transaction. This allows
|
||||
* passing of informations from one transaction to a next one.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param request received request
|
||||
* @param[out] response resulting response
|
||||
* @param[out] next transaction expected as next, or NULL
|
||||
* @return
|
||||
* - FAILED if transaction failed
|
||||
* - DESTROY_ME if transaction failed and IKE SA
|
||||
* must be deleted
|
||||
* - SUCCESS
|
||||
*/
|
||||
status_t (*get_response) (transaction_t *this, message_t *request,
|
||||
message_t **response, transaction_t **next);
|
||||
|
||||
/**
|
||||
* @brief Conclude an initiated transaction with a received response.
|
||||
*
|
||||
* The response must be decrypted and parsed. The conclude function
|
||||
* may return a new transaction. This transaction has to be executed
|
||||
* next to complete a multi-exchange scenario. It allows a clean
|
||||
* transaction mechanism, as the transaction knows best whats to do
|
||||
* after it completes. It must only be executed if conclude returns
|
||||
* SUCCESS.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param response received response
|
||||
* @param[out] next transaction to execute as next, or NULL
|
||||
* @return
|
||||
* - FAILED if transaction failed
|
||||
* - DESTROY_ME if transaction failed and IKE SA
|
||||
* must be deleted
|
||||
* - SUCCESS
|
||||
*/
|
||||
status_t (*conclude) (transaction_t *this, message_t *response,
|
||||
transaction_t **next);
|
||||
|
||||
/**
|
||||
* @brief Get the message ID associated with this transaction.
|
||||
*
|
||||
* Every transaction consists of a message pair with the same
|
||||
* message ID. This ID can be queried with get_message_id().
|
||||
*
|
||||
* @param this calling object
|
||||
* @return message id
|
||||
*/
|
||||
u_int32_t (*get_message_id) (transaction_t *this);
|
||||
|
||||
/**
|
||||
* @brief Times we already sent the request (retransmitted).
|
||||
*
|
||||
* The transaction stores an internal counter to see how
|
||||
* many times we sent the request. This counter is incremented
|
||||
* each time after a call to requested().
|
||||
*
|
||||
* @param this calling object
|
||||
* @return message id
|
||||
*/
|
||||
u_int32_t (*requested) (transaction_t *this);
|
||||
|
||||
/**
|
||||
* @brief Destroys a transaction_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*destroy) (transaction_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a transaction instance based on a received request.
|
||||
*
|
||||
* Incoming requests are handled by a transaction. But as we don't
|
||||
* know what kind of transaction we use for a specific request, we use
|
||||
* a generic constructor. This constructor decides which instance will
|
||||
* handle the transaction, and creates it.
|
||||
*
|
||||
* @param ike_sa ike_sa associated with this transaction
|
||||
* @param request received request
|
||||
* @return
|
||||
* - created transaction, or
|
||||
* - NULL no transaction needed
|
||||
*
|
||||
* @ingroup transactions
|
||||
*/
|
||||
transaction_t *transaction_create(ike_sa_t *ike_sa, message_t* request);
|
||||
|
||||
#endif /* TRANSACTION_H_ */
|
||||
Reference in New Issue
Block a user