Merge branch 'ikev1'
Conflicts: configure.in man/ipsec.conf.5.in src/libcharon/encoding/generator.c src/libcharon/encoding/payloads/notify_payload.c src/libcharon/encoding/payloads/notify_payload.h src/libcharon/encoding/payloads/payload.c src/libcharon/network/receiver.c src/libcharon/sa/authenticator.c src/libcharon/sa/authenticator.h src/libcharon/sa/ikev2/tasks/ike_init.c src/libcharon/sa/task_manager.c src/libstrongswan/credentials/auth_cfg.c
This commit is contained in:
@@ -18,9 +18,12 @@
|
||||
|
||||
#include "authenticator.h"
|
||||
|
||||
#include <sa/authenticators/pubkey_authenticator.h>
|
||||
#include <sa/authenticators/psk_authenticator.h>
|
||||
#include <sa/authenticators/eap_authenticator.h>
|
||||
#include <sa/ikev2/authenticators/pubkey_authenticator.h>
|
||||
#include <sa/ikev2/authenticators/psk_authenticator.h>
|
||||
#include <sa/ikev2/authenticators/eap_authenticator.h>
|
||||
#include <sa/ikev1/authenticators/psk_v1_authenticator.h>
|
||||
#include <sa/ikev1/authenticators/pubkey_v1_authenticator.h>
|
||||
#include <sa/ikev1/authenticators/hybrid_authenticator.h>
|
||||
#include <encoding/payloads/auth_payload.h>
|
||||
|
||||
|
||||
@@ -33,7 +36,17 @@ ENUM_NEXT(auth_method_names, AUTH_ECDSA_256, AUTH_GSPM, AUTH_DSS,
|
||||
"ECDSA-384 signature",
|
||||
"ECDSA-521 signature",
|
||||
"secure password method");
|
||||
ENUM_END(auth_method_names, AUTH_GSPM);
|
||||
ENUM_NEXT(auth_method_names, AUTH_XAUTH_INIT_PSK, AUTH_HYBRID_RESP_RSA, AUTH_GSPM,
|
||||
"XAuthInitPSK",
|
||||
"XAuthRespPSK",
|
||||
"XAuthInitRSA",
|
||||
"XauthRespRSA",
|
||||
"HybridInitRSA",
|
||||
"HybridRespRSA",
|
||||
);
|
||||
ENUM_END(auth_method_names, AUTH_HYBRID_RESP_RSA);
|
||||
|
||||
#ifdef USE_IKEV2
|
||||
|
||||
/**
|
||||
* Described in header.
|
||||
@@ -96,3 +109,46 @@ authenticator_t *authenticator_create_verifier(
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* USE_IKEV2 */
|
||||
|
||||
#ifdef USE_IKEV1
|
||||
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
authenticator_t *authenticator_create_v1(ike_sa_t *ike_sa, bool initiator,
|
||||
auth_method_t auth_method, diffie_hellman_t *dh,
|
||||
chunk_t dh_value, chunk_t sa_payload,
|
||||
chunk_t id_payload)
|
||||
{
|
||||
switch (auth_method)
|
||||
{
|
||||
case AUTH_PSK:
|
||||
case AUTH_XAUTH_INIT_PSK:
|
||||
case AUTH_XAUTH_RESP_PSK:
|
||||
return (authenticator_t*)psk_v1_authenticator_create(ike_sa,
|
||||
initiator, dh, dh_value, sa_payload,
|
||||
id_payload, FALSE);
|
||||
case AUTH_RSA:
|
||||
case AUTH_XAUTH_INIT_RSA:
|
||||
case AUTH_XAUTH_RESP_RSA:
|
||||
return (authenticator_t*)pubkey_v1_authenticator_create(ike_sa,
|
||||
initiator, dh, dh_value, sa_payload,
|
||||
id_payload, KEY_RSA);
|
||||
case AUTH_ECDSA_256:
|
||||
case AUTH_ECDSA_384:
|
||||
case AUTH_ECDSA_521:
|
||||
return (authenticator_t*)pubkey_v1_authenticator_create(ike_sa,
|
||||
initiator, dh, dh_value, sa_payload,
|
||||
id_payload, KEY_ECDSA);
|
||||
case AUTH_HYBRID_INIT_RSA:
|
||||
case AUTH_HYBRID_RESP_RSA:
|
||||
return (authenticator_t*)hybrid_authenticator_create(ike_sa,
|
||||
initiator, dh, dh_value, sa_payload,
|
||||
id_payload);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* USE_IKEV1 */
|
||||
@@ -34,6 +34,12 @@ typedef struct authenticator_t authenticator_t;
|
||||
* Method to use for authentication, as defined in IKEv2.
|
||||
*/
|
||||
enum auth_method_t {
|
||||
|
||||
/**
|
||||
* No authentication used.
|
||||
*/
|
||||
AUTH_NONE = 0,
|
||||
|
||||
/**
|
||||
* Computed as specified in section 2.15 of RFC using
|
||||
* an RSA private key over a PKCS#1 padded hash.
|
||||
@@ -73,6 +79,35 @@ enum auth_method_t {
|
||||
*/
|
||||
AUTH_GSPM = 12,
|
||||
|
||||
/**
|
||||
* IKEv1 initiator XAUTH with PSK, outside of IANA range
|
||||
*/
|
||||
AUTH_XAUTH_INIT_PSK = 256,
|
||||
|
||||
/**
|
||||
* IKEv1 responder XAUTH with PSK, outside of IANA range
|
||||
*/
|
||||
AUTH_XAUTH_RESP_PSK,
|
||||
|
||||
/**
|
||||
* IKEv1 initiator XAUTH with RSA, outside of IANA range
|
||||
*/
|
||||
AUTH_XAUTH_INIT_RSA,
|
||||
|
||||
/**
|
||||
* IKEv1 responder XAUTH with RSA, outside of IANA range
|
||||
*/
|
||||
AUTH_XAUTH_RESP_RSA,
|
||||
|
||||
/**
|
||||
* IKEv1 initiator XAUTH, responder RSA, outside of IANA range
|
||||
*/
|
||||
AUTH_HYBRID_INIT_RSA,
|
||||
|
||||
/**
|
||||
* IKEv1 responder XAUTH, initiator RSA, outside of IANA range
|
||||
*/
|
||||
AUTH_HYBRID_RESP_RSA,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -128,7 +163,7 @@ struct authenticator_t {
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an authenticator to build signatures.
|
||||
* Create an IKEv2 authenticator to build signatures.
|
||||
*
|
||||
* @param ike_sa associated ike_sa
|
||||
* @param cfg authentication configuration
|
||||
@@ -146,7 +181,7 @@ authenticator_t *authenticator_create_builder(
|
||||
char reserved[3]);
|
||||
|
||||
/**
|
||||
* Create an authenticator to verify signatures.
|
||||
* Create an IKEv2 authenticator to verify signatures.
|
||||
*
|
||||
* @param ike_sa associated ike_sa
|
||||
* @param message message containing authentication data
|
||||
@@ -163,4 +198,26 @@ authenticator_t *authenticator_create_verifier(
|
||||
chunk_t received_init, chunk_t sent_init,
|
||||
char reserved[3]);
|
||||
|
||||
/**
|
||||
* Create an IKEv1 authenticator to build and verify signatures or hash
|
||||
* payloads.
|
||||
*
|
||||
* @note Due to the fixed ID, these authenticators can only be used in one
|
||||
* direction at a time.
|
||||
*
|
||||
* @param ike_sa associated IKE_SA
|
||||
* @param initiator TRUE if we are the IKE_SA initiator
|
||||
* @param auth_method negotiated authentication method to use
|
||||
* @param dh diffie hellman key exchange
|
||||
* @param dh_value others public diffie hellman value
|
||||
* @param sa_payload generated SA payload data, without payload header
|
||||
* @param id_payload encoded ID payload of peer to authenticate or verify
|
||||
* without payload header (gets owned)
|
||||
* @return authenticator, NULL if not supported
|
||||
*/
|
||||
authenticator_t *authenticator_create_v1(ike_sa_t *ike_sa, bool initiator,
|
||||
auth_method_t auth_method, diffie_hellman_t *dh,
|
||||
chunk_t dh_value, chunk_t sa_payload,
|
||||
chunk_t id_payload);
|
||||
|
||||
#endif /** AUTHENTICATOR_H_ @}*/
|
||||
@@ -526,6 +526,16 @@ METHOD(child_sa_t, get_usestats, void,
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(child_sa_t, get_mark, mark_t,
|
||||
private_child_sa_t *this, bool inbound)
|
||||
{
|
||||
if (inbound)
|
||||
{
|
||||
return this->mark_in;
|
||||
}
|
||||
return this->mark_out;
|
||||
}
|
||||
|
||||
METHOD(child_sa_t, get_lifetime, time_t,
|
||||
private_child_sa_t *this, bool hard)
|
||||
{
|
||||
@@ -1038,6 +1048,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
|
||||
.set_proposal = _set_proposal,
|
||||
.get_lifetime = _get_lifetime,
|
||||
.get_usestats = _get_usestats,
|
||||
.get_mark = _get_mark,
|
||||
.has_encap = _has_encap,
|
||||
.get_ipcomp = _get_ipcomp,
|
||||
.set_ipcomp = _set_ipcomp,
|
||||
@@ -1079,6 +1090,15 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
|
||||
this->reqid = rekey ? rekey : ++reqid;
|
||||
}
|
||||
|
||||
if (this->mark_in.value == MARK_REQID)
|
||||
{
|
||||
this->mark_in.value = this->reqid;
|
||||
}
|
||||
if (this->mark_out.value == MARK_REQID)
|
||||
{
|
||||
this->mark_out.value = this->reqid;
|
||||
}
|
||||
|
||||
/* MIPv6 proxy transport mode sets SA endpoints to TS hosts */
|
||||
if (config->get_mode(config) == MODE_TRANSPORT &&
|
||||
config->use_proxy_mode(config))
|
||||
|
||||
@@ -274,6 +274,14 @@ struct child_sa_t {
|
||||
void (*get_usestats)(child_sa_t *this, bool inbound, time_t *time,
|
||||
u_int64_t *bytes);
|
||||
|
||||
/**
|
||||
* Get the mark used with this CHILD_SA.
|
||||
*
|
||||
* @param inbound TRUE to get inbound mark, FALSE for outbound
|
||||
* @return mark used with this CHILD_SA
|
||||
*/
|
||||
mark_t (*get_mark)(child_sa_t *this, bool inbound);
|
||||
|
||||
/**
|
||||
* Get the traffic selectors list added for one side.
|
||||
*
|
||||
|
||||
@@ -159,4 +159,3 @@ eap_manager_t *eap_manager_create()
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
#ifndef EAP_MANAGER_H_
|
||||
#define EAP_MANAGER_H_
|
||||
|
||||
#include <sa/authenticators/eap/eap_method.h>
|
||||
#include <sa/eap/eap_method.h>
|
||||
|
||||
typedef struct eap_manager_t eap_manager_t;
|
||||
|
||||
+142
-309
@@ -28,32 +28,15 @@
|
||||
#include <daemon.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <utils/lexparser.h>
|
||||
#include <sa/task_manager.h>
|
||||
#include <sa/tasks/ike_init.h>
|
||||
#include <sa/tasks/ike_natd.h>
|
||||
#include <sa/tasks/ike_mobike.h>
|
||||
#include <sa/tasks/ike_auth.h>
|
||||
#include <sa/tasks/ike_auth_lifetime.h>
|
||||
#include <sa/tasks/ike_config.h>
|
||||
#include <sa/tasks/ike_cert_pre.h>
|
||||
#include <sa/tasks/ike_cert_post.h>
|
||||
#include <sa/tasks/ike_rekey.h>
|
||||
#include <sa/tasks/ike_reauth.h>
|
||||
#include <sa/tasks/ike_delete.h>
|
||||
#include <sa/tasks/ike_dpd.h>
|
||||
#include <sa/tasks/ike_vendor.h>
|
||||
#include <sa/tasks/child_create.h>
|
||||
#include <sa/tasks/child_delete.h>
|
||||
#include <sa/tasks/child_rekey.h>
|
||||
#include <processing/jobs/retransmit_job.h>
|
||||
#include <processing/jobs/delete_ike_sa_job.h>
|
||||
#include <processing/jobs/send_dpd_job.h>
|
||||
#include <processing/jobs/send_keepalive_job.h>
|
||||
#include <processing/jobs/rekey_ike_sa_job.h>
|
||||
#include <encoding/payloads/unknown_payload.h>
|
||||
#include <sa/ikev2/tasks/ike_auth_lifetime.h>
|
||||
|
||||
#ifdef ME
|
||||
#include <sa/tasks/ike_me.h>
|
||||
#include <sa/ikev2/tasks/ike_me.h>
|
||||
#include <processing/jobs/initiate_mediation_job.h>
|
||||
#endif
|
||||
|
||||
@@ -85,6 +68,11 @@ struct private_ike_sa_t {
|
||||
*/
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
|
||||
/**
|
||||
* IKE version of this SA.
|
||||
*/
|
||||
ike_version_t version;
|
||||
|
||||
/**
|
||||
* unique numerical ID for this IKE_SA.
|
||||
*/
|
||||
@@ -246,6 +234,11 @@ struct private_ike_sa_t {
|
||||
* remote host address to be used for IKE, set via MIGRATE kernel message
|
||||
*/
|
||||
host_t *remote_host;
|
||||
|
||||
/**
|
||||
* Flush auth configs once established?
|
||||
*/
|
||||
bool flush_auth_cfg;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -314,6 +307,15 @@ METHOD(ike_sa_t, get_statistic, u_int32_t,
|
||||
return 0;
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, set_statistic, void,
|
||||
private_ike_sa_t *this, statistic_t kind, u_int32_t value)
|
||||
{
|
||||
if (kind < STAT_MAX)
|
||||
{
|
||||
this->stats[kind] = value;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, get_my_host, host_t*,
|
||||
private_ike_sa_t *this)
|
||||
{
|
||||
@@ -400,6 +402,9 @@ static void flush_auth_cfgs(private_ike_sa_t *this)
|
||||
{
|
||||
auth_cfg_t *cfg;
|
||||
|
||||
this->my_auth->purge(this->my_auth, FALSE);
|
||||
this->other_auth->purge(this->other_auth, FALSE);
|
||||
|
||||
while (this->my_auths->remove_last(this->my_auths,
|
||||
(void**)&cfg) == SUCCESS)
|
||||
{
|
||||
@@ -579,26 +584,9 @@ METHOD(ike_sa_t, send_dpd, status_t,
|
||||
if (!delay || diff >= delay)
|
||||
{
|
||||
/* to long ago, initiate dead peer detection */
|
||||
task_t *task;
|
||||
ike_mobike_t *mobike;
|
||||
|
||||
if (supports_extension(this, EXT_MOBIKE) &&
|
||||
has_condition(this, COND_NAT_HERE))
|
||||
{
|
||||
/* use mobike enabled DPD to detect NAT mapping changes */
|
||||
mobike = ike_mobike_create(&this->public, TRUE);
|
||||
mobike->dpd(mobike);
|
||||
task = &mobike->task;
|
||||
}
|
||||
else
|
||||
{
|
||||
task = (task_t*)ike_dpd_create(TRUE);
|
||||
}
|
||||
diff = 0;
|
||||
DBG1(DBG_IKE, "sending DPD request");
|
||||
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
this->task_manager->initiate(this->task_manager);
|
||||
this->task_manager->queue_dpd(this->task_manager);
|
||||
diff = 0;
|
||||
}
|
||||
}
|
||||
/* recheck in "interval" seconds */
|
||||
@@ -607,7 +595,7 @@ METHOD(ike_sa_t, send_dpd, status_t,
|
||||
job = (job_t*)send_dpd_job_create(this->ike_sa_id);
|
||||
lib->scheduler->schedule_job(lib->scheduler, job, delay - diff);
|
||||
}
|
||||
return SUCCESS;
|
||||
return this->task_manager->initiate(this->task_manager);
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, get_state, ike_sa_state_t,
|
||||
@@ -641,7 +629,7 @@ METHOD(ike_sa_t, set_state, void,
|
||||
|
||||
/* schedule rekeying if we have a time which is smaller than
|
||||
* an already scheduled rekeying */
|
||||
t = this->peer_cfg->get_rekey_time(this->peer_cfg);
|
||||
t = this->peer_cfg->get_rekey_time(this->peer_cfg, TRUE);
|
||||
if (t && (this->stats[STAT_REKEY] == 0 ||
|
||||
(this->stats[STAT_REKEY] > t + this->stats[STAT_ESTABLISHED])))
|
||||
{
|
||||
@@ -650,7 +638,7 @@ METHOD(ike_sa_t, set_state, void,
|
||||
lib->scheduler->schedule_job(lib->scheduler, job, t);
|
||||
DBG1(DBG_IKE, "scheduling rekeying in %ds", t);
|
||||
}
|
||||
t = this->peer_cfg->get_reauth_time(this->peer_cfg);
|
||||
t = this->peer_cfg->get_reauth_time(this->peer_cfg, TRUE);
|
||||
if (t && (this->stats[STAT_REAUTH] == 0 ||
|
||||
(this->stats[STAT_REAUTH] > t + this->stats[STAT_ESTABLISHED])))
|
||||
{
|
||||
@@ -701,7 +689,14 @@ METHOD(ike_sa_t, set_state, void,
|
||||
|
||||
if (trigger_dpd)
|
||||
{
|
||||
send_dpd(this);
|
||||
if (supports_extension(this, EXT_DPD))
|
||||
{
|
||||
send_dpd(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "DPD not supported by peer, disabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -719,7 +714,8 @@ METHOD(ike_sa_t, reset, void,
|
||||
flush_auth_cfgs(this);
|
||||
|
||||
this->keymat->destroy(this->keymat);
|
||||
this->keymat = keymat_create(this->ike_sa_id->is_initiator(this->ike_sa_id));
|
||||
this->keymat = keymat_create(this->version,
|
||||
this->ike_sa_id->is_initiator(this->ike_sa_id));
|
||||
|
||||
this->task_manager->reset(this->task_manager, 0, 0);
|
||||
}
|
||||
@@ -911,6 +907,8 @@ METHOD(ike_sa_t, update_hosts, void,
|
||||
METHOD(ike_sa_t, generate_message, status_t,
|
||||
private_ike_sa_t *this, message_t *message, packet_t **packet)
|
||||
{
|
||||
status_t status;
|
||||
|
||||
if (message->is_encoded(message))
|
||||
{ /* already done */
|
||||
*packet = message->get_packet(message);
|
||||
@@ -918,44 +916,13 @@ METHOD(ike_sa_t, generate_message, status_t,
|
||||
}
|
||||
this->stats[STAT_OUTBOUND] = time_monotonic(NULL);
|
||||
message->set_ike_sa_id(message, this->ike_sa_id);
|
||||
charon->bus->message(charon->bus, message, FALSE);
|
||||
return message->generate(message,
|
||||
this->keymat->get_aead(this->keymat, FALSE), packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* send a notify back to the sender
|
||||
*/
|
||||
static void send_notify_response(private_ike_sa_t *this, message_t *request,
|
||||
notify_type_t type, chunk_t data)
|
||||
{
|
||||
message_t *response;
|
||||
packet_t *packet;
|
||||
|
||||
response = message_create();
|
||||
response->set_exchange_type(response, request->get_exchange_type(request));
|
||||
response->set_request(response, FALSE);
|
||||
response->set_message_id(response, request->get_message_id(request));
|
||||
response->add_notify(response, FALSE, type, data);
|
||||
if (this->my_host->is_anyaddr(this->my_host))
|
||||
charon->bus->message(charon->bus, message, FALSE, TRUE);
|
||||
status = message->generate(message, this->keymat, packet);
|
||||
if (status == SUCCESS)
|
||||
{
|
||||
this->my_host->destroy(this->my_host);
|
||||
this->my_host = request->get_destination(request);
|
||||
this->my_host = this->my_host->clone(this->my_host);
|
||||
charon->bus->message(charon->bus, message, FALSE, FALSE);
|
||||
}
|
||||
if (this->other_host->is_anyaddr(this->other_host))
|
||||
{
|
||||
this->other_host->destroy(this->other_host);
|
||||
this->other_host = request->get_source(request);
|
||||
this->other_host = this->other_host->clone(this->other_host);
|
||||
}
|
||||
response->set_source(response, this->my_host->clone(this->my_host));
|
||||
response->set_destination(response, this->other_host->clone(this->other_host));
|
||||
if (generate_message(this, response, &packet) == SUCCESS)
|
||||
{
|
||||
charon->sender->send(charon->sender, packet);
|
||||
}
|
||||
response->destroy(response);
|
||||
return status;
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, set_kmaddress, void,
|
||||
@@ -1110,11 +1077,13 @@ METHOD(ike_sa_t, initiate, status_t,
|
||||
private_ike_sa_t *this, child_cfg_t *child_cfg, u_int32_t reqid,
|
||||
traffic_selector_t *tsi, traffic_selector_t *tsr)
|
||||
{
|
||||
task_t *task;
|
||||
|
||||
if (this->state == IKE_CREATED)
|
||||
{
|
||||
resolve_hosts(this);
|
||||
if (this->my_host->is_anyaddr(this->my_host) ||
|
||||
this->other_host->is_anyaddr(this->other_host))
|
||||
{
|
||||
resolve_hosts(this);
|
||||
}
|
||||
|
||||
if (this->other_host->is_anyaddr(this->other_host)
|
||||
#ifdef ME
|
||||
@@ -1122,39 +1091,14 @@ METHOD(ike_sa_t, initiate, status_t,
|
||||
#endif /* ME */
|
||||
)
|
||||
{
|
||||
child_cfg->destroy(child_cfg);
|
||||
DESTROY_IF(child_cfg);
|
||||
DBG1(DBG_IKE, "unable to initiate to %%any");
|
||||
charon->bus->alert(charon->bus, ALERT_PEER_ADDR_FAILED);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
set_condition(this, COND_ORIGINAL_INITIATOR, TRUE);
|
||||
|
||||
task = (task_t*)ike_vendor_create(&this->public, TRUE);
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
task = (task_t*)ike_init_create(&this->public, TRUE, NULL);
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
task = (task_t*)ike_natd_create(&this->public, TRUE);
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
task = (task_t*)ike_cert_pre_create(&this->public, TRUE);
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
task = (task_t*)ike_auth_create(&this->public, TRUE);
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
task = (task_t*)ike_cert_post_create(&this->public, TRUE);
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
task = (task_t*)ike_config_create(&this->public, TRUE);
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
task = (task_t*)ike_auth_lifetime_create(&this->public, TRUE);
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
if (this->peer_cfg->use_mobike(this->peer_cfg))
|
||||
{
|
||||
task = (task_t*)ike_mobike_create(&this->public, TRUE);
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
}
|
||||
#ifdef ME
|
||||
task = (task_t*)ike_me_create(&this->public, TRUE);
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
#endif /* ME */
|
||||
this->task_manager->queue_ike(this->task_manager);
|
||||
}
|
||||
|
||||
#ifdef ME
|
||||
@@ -1171,18 +1115,11 @@ METHOD(ike_sa_t, initiate, status_t,
|
||||
}
|
||||
else
|
||||
#endif /* ME */
|
||||
if (child_cfg)
|
||||
{
|
||||
/* normal IKE_SA with CHILD_SA */
|
||||
task = (task_t*)child_create_create(&this->public, child_cfg, FALSE,
|
||||
tsi, tsr);
|
||||
child_cfg->destroy(child_cfg);
|
||||
if (reqid)
|
||||
{
|
||||
child_create_t *child_create = (child_create_t*)task;
|
||||
child_create->use_reqid(child_create, reqid);
|
||||
}
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
|
||||
this->task_manager->queue_child(this->task_manager, child_cfg, reqid,
|
||||
tsi, tsr);
|
||||
#ifdef ME
|
||||
if (this->peer_cfg->get_mediated_by(this->peer_cfg))
|
||||
{
|
||||
@@ -1201,128 +1138,27 @@ METHOD(ike_sa_t, process_message, status_t,
|
||||
private_ike_sa_t *this, message_t *message)
|
||||
{
|
||||
status_t status;
|
||||
bool is_request;
|
||||
u_int8_t type = 0;
|
||||
|
||||
if (this->state == IKE_PASSIVE)
|
||||
{ /* do not handle messages in passive state */
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
is_request = message->get_request(message);
|
||||
|
||||
status = message->parse_body(message,
|
||||
this->keymat->get_aead(this->keymat, TRUE));
|
||||
if (status == SUCCESS)
|
||||
{ /* check for unsupported critical payloads */
|
||||
enumerator_t *enumerator;
|
||||
unknown_payload_t *unknown;
|
||||
payload_t *payload;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
unknown = (unknown_payload_t*)payload;
|
||||
type = payload->get_type(payload);
|
||||
if (!payload_is_known(type) &&
|
||||
unknown->is_critical(unknown))
|
||||
{
|
||||
DBG1(DBG_ENC, "payload type %N is not supported, "
|
||||
"but its critical!", payload_type_names, type);
|
||||
status = NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
if (status != SUCCESS)
|
||||
if (message->get_major_version(message) != this->version)
|
||||
{
|
||||
if (is_request)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case NOT_SUPPORTED:
|
||||
DBG1(DBG_IKE, "critical unknown payloads found");
|
||||
if (is_request)
|
||||
{
|
||||
send_notify_response(this, message,
|
||||
UNSUPPORTED_CRITICAL_PAYLOAD,
|
||||
chunk_from_thing(type));
|
||||
this->task_manager->incr_mid(this->task_manager, FALSE);
|
||||
}
|
||||
break;
|
||||
case PARSE_ERROR:
|
||||
DBG1(DBG_IKE, "message parsing failed");
|
||||
if (is_request)
|
||||
{
|
||||
send_notify_response(this, message,
|
||||
INVALID_SYNTAX, chunk_empty);
|
||||
this->task_manager->incr_mid(this->task_manager, FALSE);
|
||||
}
|
||||
break;
|
||||
case VERIFY_ERROR:
|
||||
DBG1(DBG_IKE, "message verification failed");
|
||||
if (is_request)
|
||||
{
|
||||
send_notify_response(this, message,
|
||||
INVALID_SYNTAX, chunk_empty);
|
||||
this->task_manager->incr_mid(this->task_manager, FALSE);
|
||||
}
|
||||
break;
|
||||
case FAILED:
|
||||
DBG1(DBG_IKE, "integrity check failed");
|
||||
/* ignored */
|
||||
break;
|
||||
case INVALID_STATE:
|
||||
DBG1(DBG_IKE, "found encrypted message, but no keys available");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
DBG1(DBG_IKE, "%N %s with message ID %d processing failed",
|
||||
DBG1(DBG_IKE, "ignoring %N IKEv%u exchange on %N SA",
|
||||
exchange_type_names, message->get_exchange_type(message),
|
||||
message->get_request(message) ? "request" : "response",
|
||||
message->get_message_id(message));
|
||||
|
||||
if (this->state == IKE_CREATED)
|
||||
{ /* invalid initiation attempt, close SA */
|
||||
return DESTROY_ME;
|
||||
}
|
||||
message->get_major_version(message),
|
||||
ike_version_names, this->version);
|
||||
/* TODO-IKEv1: fall back to IKEv1 if we receive an IKEv1
|
||||
* INVALID_MAJOR_VERSION on an IKEv2 SA. */
|
||||
return FAILED;
|
||||
}
|
||||
else
|
||||
status = this->task_manager->process_message(this->task_manager, message);
|
||||
if (this->flush_auth_cfg && this->state == IKE_ESTABLISHED)
|
||||
{
|
||||
/* if this IKE_SA is virgin, we check for a config */
|
||||
if (this->ike_cfg == NULL)
|
||||
{
|
||||
job_t *job;
|
||||
host_t *me = message->get_destination(message),
|
||||
*other = message->get_source(message);
|
||||
this->ike_cfg = charon->backends->get_ike_cfg(charon->backends,
|
||||
me, other);
|
||||
if (this->ike_cfg == NULL)
|
||||
{
|
||||
/* no config found for these hosts, destroy */
|
||||
DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N",
|
||||
me, other, notify_type_names, NO_PROPOSAL_CHOSEN);
|
||||
send_notify_response(this, message,
|
||||
NO_PROPOSAL_CHOSEN, chunk_empty);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
/* add a timeout if peer does not establish it completely */
|
||||
job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE);
|
||||
lib->scheduler->schedule_job(lib->scheduler, job,
|
||||
lib->settings->get_int(lib->settings,
|
||||
"charon.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT));
|
||||
}
|
||||
this->stats[STAT_INBOUND] = time_monotonic(NULL);
|
||||
status = this->task_manager->process_message(this->task_manager,
|
||||
message);
|
||||
if (message->get_exchange_type(message) == IKE_AUTH &&
|
||||
this->state == IKE_ESTABLISHED &&
|
||||
lib->settings->get_bool(lib->settings,
|
||||
"charon.flush_auth_cfg", FALSE))
|
||||
{ /* authentication completed */
|
||||
flush_auth_cfgs(this);
|
||||
}
|
||||
/* authentication completed */
|
||||
this->flush_auth_cfg = FALSE;
|
||||
flush_auth_cfgs(this);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -1333,6 +1169,12 @@ METHOD(ike_sa_t, get_id, ike_sa_id_t*,
|
||||
return this->ike_sa_id;
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, get_version, ike_version_t,
|
||||
private_ike_sa_t *this)
|
||||
{
|
||||
return this->version;
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, get_my_id, identification_t*,
|
||||
private_ike_sa_t *this)
|
||||
{
|
||||
@@ -1365,6 +1207,10 @@ METHOD(ike_sa_t, get_other_eap_id, identification_t*,
|
||||
/* prefer EAP-Identity of last round */
|
||||
current = cfg->get(cfg, AUTH_RULE_EAP_IDENTITY);
|
||||
if (!current || current->get_type(current) == ID_ANY)
|
||||
{
|
||||
current = cfg->get(cfg, AUTH_RULE_XAUTH_IDENTITY);
|
||||
}
|
||||
if (!current || current->get_type(current) == ID_ANY)
|
||||
{
|
||||
current = cfg->get(cfg, AUTH_RULE_IDENTITY);
|
||||
}
|
||||
@@ -1435,30 +1281,23 @@ METHOD(ike_sa_t, remove_child_sa, void,
|
||||
METHOD(ike_sa_t, rekey_child_sa, status_t,
|
||||
private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi)
|
||||
{
|
||||
child_rekey_t *child_rekey;
|
||||
|
||||
if (this->state == IKE_PASSIVE)
|
||||
{
|
||||
return INVALID_STATE;
|
||||
}
|
||||
|
||||
child_rekey = child_rekey_create(&this->public, protocol, spi);
|
||||
this->task_manager->queue_task(this->task_manager, &child_rekey->task);
|
||||
this->task_manager->queue_child_rekey(this->task_manager, protocol, spi);
|
||||
return this->task_manager->initiate(this->task_manager);
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, delete_child_sa, status_t,
|
||||
private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi)
|
||||
private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi, bool expired)
|
||||
{
|
||||
child_delete_t *child_delete;
|
||||
|
||||
if (this->state == IKE_PASSIVE)
|
||||
{
|
||||
return INVALID_STATE;
|
||||
}
|
||||
|
||||
child_delete = child_delete_create(&this->public, protocol, spi);
|
||||
this->task_manager->queue_task(this->task_manager, &child_delete->task);
|
||||
this->task_manager->queue_child_delete(this->task_manager,
|
||||
protocol, spi, expired);
|
||||
return this->task_manager->initiate(this->task_manager);
|
||||
}
|
||||
|
||||
@@ -1488,14 +1327,17 @@ METHOD(ike_sa_t, destroy_child_sa, status_t,
|
||||
METHOD(ike_sa_t, delete_, status_t,
|
||||
private_ike_sa_t *this)
|
||||
{
|
||||
ike_delete_t *ike_delete;
|
||||
|
||||
switch (this->state)
|
||||
{
|
||||
case IKE_ESTABLISHED:
|
||||
case IKE_REKEYING:
|
||||
ike_delete = ike_delete_create(&this->public, TRUE);
|
||||
this->task_manager->queue_task(this->task_manager, &ike_delete->task);
|
||||
if (this->version == IKEV1)
|
||||
{ /* SA has been reauthenticated, delete */
|
||||
charon->bus->ike_updown(charon->bus, &this->public, FALSE);
|
||||
break;
|
||||
}
|
||||
/* FALL */
|
||||
case IKE_ESTABLISHED:
|
||||
this->task_manager->queue_ike_delete(this->task_manager);
|
||||
return this->task_manager->initiate(this->task_manager);
|
||||
case IKE_CREATED:
|
||||
DBG1(DBG_IKE, "deleting unestablished IKE_SA");
|
||||
@@ -1514,23 +1356,17 @@ METHOD(ike_sa_t, delete_, status_t,
|
||||
METHOD(ike_sa_t, rekey, status_t,
|
||||
private_ike_sa_t *this)
|
||||
{
|
||||
ike_rekey_t *ike_rekey;
|
||||
|
||||
if (this->state == IKE_PASSIVE)
|
||||
{
|
||||
return INVALID_STATE;
|
||||
}
|
||||
ike_rekey = ike_rekey_create(&this->public, TRUE);
|
||||
|
||||
this->task_manager->queue_task(this->task_manager, &ike_rekey->task);
|
||||
this->task_manager->queue_ike_rekey(this->task_manager);
|
||||
return this->task_manager->initiate(this->task_manager);
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, reauth, status_t,
|
||||
private_ike_sa_t *this)
|
||||
{
|
||||
task_t *task;
|
||||
|
||||
if (this->state == IKE_PASSIVE)
|
||||
{
|
||||
return INVALID_STATE;
|
||||
@@ -1542,6 +1378,7 @@ METHOD(ike_sa_t, reauth, status_t,
|
||||
{
|
||||
DBG1(DBG_IKE, "initiator did not reauthenticate as requested");
|
||||
if (this->other_virtual_ip != NULL ||
|
||||
has_condition(this, COND_XAUTH_AUTHENTICATED) ||
|
||||
has_condition(this, COND_EAP_AUTHENTICATED)
|
||||
#ifdef ME
|
||||
/* as mediation server we too cannot reauth the IKE_SA */
|
||||
@@ -1568,9 +1405,7 @@ METHOD(ike_sa_t, reauth, status_t,
|
||||
DBG0(DBG_IKE, "reauthenticating IKE_SA %s[%d]",
|
||||
get_name(this), this->unique_id);
|
||||
}
|
||||
task = (task_t*)ike_reauth_create(&this->public);
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
|
||||
this->task_manager->queue_ike_reauth(this->task_manager);
|
||||
return this->task_manager->initiate(this->task_manager);
|
||||
}
|
||||
|
||||
@@ -1637,7 +1472,12 @@ METHOD(ike_sa_t, reestablish, status_t,
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE);
|
||||
new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
|
||||
this->version, TRUE);
|
||||
if (!new)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
new->set_peer_cfg(new, this->peer_cfg);
|
||||
host = this->other_host;
|
||||
new->set_other_host(new, host->clone(host));
|
||||
@@ -1703,40 +1543,6 @@ METHOD(ike_sa_t, reestablish, status_t,
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requeue the IKE_SA_INIT tasks for initiation, if required
|
||||
*/
|
||||
static void requeue_init_tasks(private_ike_sa_t *this)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
bool has_init = FALSE;
|
||||
task_t *task;
|
||||
|
||||
/* if we have advanced to IKE_AUTH, the IKE_INIT and related tasks
|
||||
* have already completed. Recreate them if necessary. */
|
||||
enumerator = this->task_manager->create_task_enumerator(
|
||||
this->task_manager, TASK_QUEUE_QUEUED);
|
||||
while (enumerator->enumerate(enumerator, &task))
|
||||
{
|
||||
if (task->get_type(task) == IKE_INIT)
|
||||
{
|
||||
has_init = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
if (!has_init)
|
||||
{
|
||||
task = (task_t*)ike_vendor_create(&this->public, TRUE);
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
task = (task_t*)ike_natd_create(&this->public, TRUE);
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
task = (task_t*)ike_init_create(&this->public, TRUE, NULL);
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, retransmit, status_t,
|
||||
private_ike_sa_t *this, u_int32_t message_id)
|
||||
{
|
||||
@@ -1752,7 +1558,7 @@ METHOD(ike_sa_t, retransmit, status_t,
|
||||
{
|
||||
case IKE_CONNECTING:
|
||||
{
|
||||
/* retry IKE_SA_INIT if we have multiple keyingtries */
|
||||
/* retry IKE_SA_INIT/Main Mode if we have multiple keyingtries */
|
||||
u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg);
|
||||
this->keyingtry++;
|
||||
if (tries == 0 || tries > this->keyingtry)
|
||||
@@ -1761,7 +1567,7 @@ METHOD(ike_sa_t, retransmit, status_t,
|
||||
this->keyingtry + 1, tries);
|
||||
reset(this);
|
||||
resolve_hosts(this);
|
||||
requeue_init_tasks(this);
|
||||
this->task_manager->queue_ike(this->task_manager);
|
||||
return this->task_manager->initiate(this->task_manager);
|
||||
}
|
||||
DBG1(DBG_IKE, "establishing IKE_SA failed, peer not responding");
|
||||
@@ -1796,7 +1602,7 @@ METHOD(ike_sa_t, set_auth_lifetime, status_t,
|
||||
|
||||
/* check if we have to send an AUTH_LIFETIME to enforce the new lifetime.
|
||||
* We send the notify in IKE_AUTH if not yet ESTABLISHED. */
|
||||
send_update = this->state == IKE_ESTABLISHED &&
|
||||
send_update = this->state == IKE_ESTABLISHED && this->version == IKEV2 &&
|
||||
!has_condition(this, COND_ORIGINAL_INITIATOR) &&
|
||||
(this->other_virtual_ip != NULL ||
|
||||
has_condition(this, COND_EAP_AUTHENTICATED));
|
||||
@@ -1899,8 +1705,6 @@ static bool is_any_path_valid(private_ike_sa_t *this)
|
||||
METHOD(ike_sa_t, roam, status_t,
|
||||
private_ike_sa_t *this, bool address)
|
||||
{
|
||||
ike_mobike_t *mobike;
|
||||
|
||||
switch (this->state)
|
||||
{
|
||||
case IKE_CREATED:
|
||||
@@ -1922,10 +1726,7 @@ METHOD(ike_sa_t, roam, status_t,
|
||||
if (supports_extension(this, EXT_MOBIKE) && address)
|
||||
{ /* if any addresses changed, send an updated list */
|
||||
DBG1(DBG_IKE, "sending address list update using MOBIKE");
|
||||
mobike = ike_mobike_create(&this->public, TRUE);
|
||||
mobike->addresses(mobike);
|
||||
this->task_manager->queue_task(this->task_manager,
|
||||
(task_t*)mobike);
|
||||
this->task_manager->queue_mobike(this->task_manager, FALSE, TRUE);
|
||||
return this->task_manager->initiate(this->task_manager);
|
||||
}
|
||||
return SUCCESS;
|
||||
@@ -1953,9 +1754,7 @@ METHOD(ike_sa_t, roam, status_t,
|
||||
{
|
||||
DBG1(DBG_IKE, "requesting address change using MOBIKE");
|
||||
}
|
||||
mobike = ike_mobike_create(&this->public, TRUE);
|
||||
mobike->roam(mobike, address);
|
||||
this->task_manager->queue_task(this->task_manager, (task_t*)mobike);
|
||||
this->task_manager->queue_mobike(this->task_manager, TRUE, address);
|
||||
return this->task_manager->initiate(this->task_manager);
|
||||
}
|
||||
|
||||
@@ -1988,6 +1787,12 @@ METHOD(ike_sa_t, create_task_enumerator, enumerator_t*,
|
||||
return this->task_manager->create_task_enumerator(this->task_manager, queue);
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, queue_task, void,
|
||||
private_ike_sa_t *this, task_t *task)
|
||||
{
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, inherit, void,
|
||||
private_ike_sa_t *this, ike_sa_t *other_public)
|
||||
{
|
||||
@@ -2095,7 +1900,7 @@ METHOD(ike_sa_t, destroy, void,
|
||||
charon->bus->set_sa(charon->bus, &this->public);
|
||||
|
||||
set_state(this, IKE_DESTROYING);
|
||||
this->task_manager->destroy(this->task_manager);
|
||||
DESTROY_IF(this->task_manager);
|
||||
|
||||
/* remove attributes first, as we pass the IKE_SA to the handler */
|
||||
while (this->attributes->remove_last(this->attributes,
|
||||
@@ -2113,7 +1918,7 @@ METHOD(ike_sa_t, destroy, void,
|
||||
/* unset SA after here to avoid usage by the listeners */
|
||||
charon->bus->set_sa(charon->bus, NULL);
|
||||
|
||||
this->keymat->destroy(this->keymat);
|
||||
DESTROY_IF(this->keymat);
|
||||
|
||||
if (this->my_virtual_ip)
|
||||
{
|
||||
@@ -2168,17 +1973,29 @@ METHOD(ike_sa_t, destroy, void,
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
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, bool initiator,
|
||||
ike_version_t version)
|
||||
{
|
||||
private_ike_sa_t *this;
|
||||
static u_int32_t unique_id = 0;
|
||||
|
||||
if (version == IKE_ANY)
|
||||
{ /* prefer IKEv2 if protocol not specified */
|
||||
#ifdef USE_IKEV2
|
||||
version = IKEV2;
|
||||
#else
|
||||
version = IKEV1;
|
||||
#endif
|
||||
}
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.get_version = _get_version,
|
||||
.get_state = _get_state,
|
||||
.set_state = _set_state,
|
||||
.get_name = _get_name,
|
||||
.get_statistic = _get_statistic,
|
||||
.set_statistic = _set_statistic,
|
||||
.process_message = _process_message,
|
||||
.initiate = _initiate,
|
||||
.get_ike_cfg = _get_ike_cfg,
|
||||
@@ -2241,6 +2058,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
|
||||
.add_configuration_attribute = _add_configuration_attribute,
|
||||
.set_kmaddress = _set_kmaddress,
|
||||
.create_task_enumerator = _create_task_enumerator,
|
||||
.queue_task = _queue_task,
|
||||
#ifdef ME
|
||||
.act_as_mediation_server = _act_as_mediation_server,
|
||||
.get_server_reflexive_host = _get_server_reflexive_host,
|
||||
@@ -2254,12 +2072,13 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
|
||||
#endif /* ME */
|
||||
},
|
||||
.ike_sa_id = ike_sa_id->clone(ike_sa_id),
|
||||
.version = version,
|
||||
.child_sas = linked_list_create(),
|
||||
.my_host = host_create_any(AF_INET),
|
||||
.other_host = host_create_any(AF_INET),
|
||||
.my_id = identification_create_from_encoding(ID_ANY, chunk_empty),
|
||||
.other_id = identification_create_from_encoding(ID_ANY, chunk_empty),
|
||||
.keymat = keymat_create(ike_sa_id->is_initiator(ike_sa_id)),
|
||||
.keymat = keymat_create(version, initiator),
|
||||
.state = IKE_CREATED,
|
||||
.stats[STAT_INBOUND] = time_monotonic(NULL),
|
||||
.stats[STAT_OUTBOUND] = time_monotonic(NULL),
|
||||
@@ -2272,9 +2091,23 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
|
||||
.attributes = linked_list_create(),
|
||||
.keepalive_interval = lib->settings->get_time(lib->settings,
|
||||
"charon.keep_alive", KEEPALIVE_INTERVAL),
|
||||
.flush_auth_cfg = lib->settings->get_bool(lib->settings,
|
||||
"charon.flush_auth_cfg", FALSE),
|
||||
);
|
||||
|
||||
if (version == IKEV2)
|
||||
{ /* always supported with IKEv2 */
|
||||
enable_extension(this, EXT_DPD);
|
||||
}
|
||||
|
||||
this->task_manager = task_manager_create(&this->public);
|
||||
this->my_host->set_port(this->my_host, IKEV2_UDP_PORT);
|
||||
|
||||
if (!this->task_manager || !this->keymat)
|
||||
{
|
||||
DBG1(DBG_IKE, "IKE version %d not supported", this->version);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ typedef struct ike_sa_t ike_sa_t;
|
||||
#include <encoding/payloads/configuration_attribute.h>
|
||||
#include <sa/ike_sa_id.h>
|
||||
#include <sa/child_sa.h>
|
||||
#include <sa/task.h>
|
||||
#include <sa/task_manager.h>
|
||||
#include <sa/keymat.h>
|
||||
#include <config/peer_cfg.h>
|
||||
@@ -69,7 +70,7 @@ typedef struct ike_sa_t ike_sa_t;
|
||||
enum ike_extension_t {
|
||||
|
||||
/**
|
||||
* peer supports NAT traversal as specified in RFC4306
|
||||
* peer supports NAT traversal as specified in RFC4306 or RFC3947
|
||||
*/
|
||||
EXT_NATT = (1<<0),
|
||||
|
||||
@@ -102,6 +103,16 @@ enum ike_extension_t {
|
||||
* peer is probably a Windows 7 RAS client
|
||||
*/
|
||||
EXT_MS_WINDOWS = (1<<6),
|
||||
|
||||
/**
|
||||
* peer supports XAuth authentication, draft-ietf-ipsec-isakmp-xauth-06
|
||||
*/
|
||||
EXT_XAUTH = (1<<7),
|
||||
|
||||
/**
|
||||
* peer supports DPD detection, RFC 3706 (or IKEv2)
|
||||
*/
|
||||
EXT_DPD = (1<<8),
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -148,6 +159,16 @@ enum ike_condition_t {
|
||||
* IKE_SA is stale, the peer is currently unreachable (MOBIKE)
|
||||
*/
|
||||
COND_STALE = (1<<7),
|
||||
|
||||
/**
|
||||
* Initial contact received
|
||||
*/
|
||||
COND_INIT_CONTACT_SEEN = (1<<8),
|
||||
|
||||
/**
|
||||
* Peer has been authenticated using XAuth
|
||||
*/
|
||||
COND_XAUTH_AUTHENTICATED = (1<<9),
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -269,6 +290,11 @@ struct ike_sa_t {
|
||||
*/
|
||||
ike_sa_id_t* (*get_id) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* Gets the IKE version of the SA
|
||||
*/
|
||||
ike_version_t (*get_version)(ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* Get the numerical ID uniquely defining this IKE_SA.
|
||||
*
|
||||
@@ -288,7 +314,7 @@ struct ike_sa_t {
|
||||
*
|
||||
* @param state state to set for the IKE_SA
|
||||
*/
|
||||
void (*set_state) (ike_sa_t *this, ike_sa_state_t ike_sa);
|
||||
void (*set_state) (ike_sa_t *this, ike_sa_state_t state);
|
||||
|
||||
/**
|
||||
* Get the name of the connection this IKE_SA uses.
|
||||
@@ -305,6 +331,14 @@ struct ike_sa_t {
|
||||
*/
|
||||
u_int32_t (*get_statistic)(ike_sa_t *this, statistic_t kind);
|
||||
|
||||
/**
|
||||
* Set statistic value of the IKE_SA.
|
||||
*
|
||||
* @param kind kind of value to update
|
||||
* @param value value as integer
|
||||
*/
|
||||
void (*set_statistic)(ike_sa_t *this, statistic_t kind, u_int32_t value);
|
||||
|
||||
/**
|
||||
* Get the own host address.
|
||||
*
|
||||
@@ -821,11 +855,13 @@ struct ike_sa_t {
|
||||
*
|
||||
* @param protocol protocol of the SA
|
||||
* @param spi inbound SPI of the CHILD_SA
|
||||
* @param expired TRUE if CHILD_SA is expired
|
||||
* @return
|
||||
* - NOT_FOUND, if IKE_SA has no such CHILD_SA
|
||||
* - SUCCESS, if delete message sent
|
||||
*/
|
||||
status_t (*delete_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi);
|
||||
status_t (*delete_child_sa)(ike_sa_t *this, protocol_id_t protocol,
|
||||
u_int32_t spi, bool expired);
|
||||
|
||||
/**
|
||||
* Destroy a CHILD SA with the specified protocol/SPI.
|
||||
@@ -932,6 +968,13 @@ struct ike_sa_t {
|
||||
*/
|
||||
enumerator_t* (*create_task_enumerator)(ike_sa_t *this, task_queue_t queue);
|
||||
|
||||
/**
|
||||
* Queue a task for initiaton to the task manager.
|
||||
*
|
||||
* @param task task to queue
|
||||
*/
|
||||
void (*queue_task)(ike_sa_t *this, task_t *task);
|
||||
|
||||
/**
|
||||
* Inherit all attributes of other to this after rekeying.
|
||||
*
|
||||
@@ -955,11 +998,14 @@ struct ike_sa_t {
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an ike_sa_t object with a specific ID.
|
||||
* Creates an ike_sa_t object with a specific ID and IKE version.
|
||||
*
|
||||
* @param ike_sa_id ike_sa_id_t object to associate with new IKE_SA
|
||||
* @param ike_sa_id ike_sa_id_t to associate with new IKE_SA/ISAKMP_SA
|
||||
* @param initiator TRUE to create this IKE_SA as initiator
|
||||
* @param version IKE version of this SA
|
||||
* @return ike_sa_t object
|
||||
*/
|
||||
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, bool initiator,
|
||||
ike_version_t version);
|
||||
|
||||
#endif /** IKE_SA_H_ @}*/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Tobias Brunner
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
@@ -30,13 +31,18 @@ struct private_ike_sa_id_t {
|
||||
*/
|
||||
ike_sa_id_t public;
|
||||
|
||||
/**
|
||||
* Major IKE version of IKE_SA.
|
||||
*/
|
||||
u_int8_t ike_version;
|
||||
|
||||
/**
|
||||
* SPI of Initiator.
|
||||
* SPI of initiator.
|
||||
*/
|
||||
u_int64_t initiator_spi;
|
||||
|
||||
/**
|
||||
* SPI of Responder.
|
||||
* SPI of responder.
|
||||
*/
|
||||
u_int64_t responder_spi;
|
||||
|
||||
@@ -46,6 +52,12 @@ struct private_ike_sa_id_t {
|
||||
bool is_initiator_flag;
|
||||
};
|
||||
|
||||
METHOD(ike_sa_id_t, get_ike_version, u_int8_t,
|
||||
private_ike_sa_id_t *this)
|
||||
{
|
||||
return this->ike_version;
|
||||
}
|
||||
|
||||
METHOD(ike_sa_id_t, set_responder_spi, void,
|
||||
private_ike_sa_id_t *this, u_int64_t responder_spi)
|
||||
{
|
||||
@@ -77,23 +89,15 @@ METHOD(ike_sa_id_t, equals, bool,
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if ((this->is_initiator_flag == other->is_initiator_flag) &&
|
||||
(this->initiator_spi == other->initiator_spi) &&
|
||||
(this->responder_spi == other->responder_spi))
|
||||
{
|
||||
/* private_ike_sa_id's are equal */
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* private_ike_sa_id's are not equal */
|
||||
return FALSE;
|
||||
}
|
||||
return this->ike_version == other->ike_version &&
|
||||
this->initiator_spi == other->initiator_spi &&
|
||||
this->responder_spi == other->responder_spi;
|
||||
}
|
||||
|
||||
METHOD(ike_sa_id_t, replace_values, void,
|
||||
private_ike_sa_id_t *this, private_ike_sa_id_t *other)
|
||||
{
|
||||
this->ike_version = other->ike_version;
|
||||
this->initiator_spi = other->initiator_spi;
|
||||
this->responder_spi = other->responder_spi;
|
||||
this->is_initiator_flag = other->is_initiator_flag;
|
||||
@@ -108,22 +112,15 @@ METHOD(ike_sa_id_t, is_initiator, bool,
|
||||
METHOD(ike_sa_id_t, switch_initiator, bool,
|
||||
private_ike_sa_id_t *this)
|
||||
{
|
||||
if (this->is_initiator_flag)
|
||||
{
|
||||
this->is_initiator_flag = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->is_initiator_flag = TRUE;
|
||||
}
|
||||
this->is_initiator_flag = !this->is_initiator_flag;
|
||||
return this->is_initiator_flag;
|
||||
}
|
||||
|
||||
METHOD(ike_sa_id_t, clone_, ike_sa_id_t*,
|
||||
private_ike_sa_id_t *this)
|
||||
{
|
||||
return ike_sa_id_create(this->initiator_spi, this->responder_spi,
|
||||
this->is_initiator_flag);
|
||||
return ike_sa_id_create(this->ike_version, this->initiator_spi,
|
||||
this->responder_spi, this->is_initiator_flag);
|
||||
}
|
||||
|
||||
METHOD(ike_sa_id_t, destroy, void,
|
||||
@@ -135,13 +132,14 @@ METHOD(ike_sa_id_t, destroy, void,
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi,
|
||||
bool is_initiator_flag)
|
||||
ike_sa_id_t * ike_sa_id_create(u_int8_t ike_version, u_int64_t initiator_spi,
|
||||
u_int64_t responder_spi, bool is_initiator_flag)
|
||||
{
|
||||
private_ike_sa_id_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.get_ike_version = _get_ike_version,
|
||||
.set_responder_spi = _set_responder_spi,
|
||||
.set_initiator_spi = _set_initiator_spi,
|
||||
.get_responder_spi = _get_responder_spi,
|
||||
@@ -153,6 +151,7 @@ ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi,
|
||||
.clone = _clone_,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.ike_version = ike_version,
|
||||
.initiator_spi = initiator_spi,
|
||||
.responder_spi = responder_spi,
|
||||
.is_initiator_flag = is_initiator_flag,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Tobias Brunner
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
@@ -29,12 +30,19 @@ typedef struct ike_sa_id_t ike_sa_id_t;
|
||||
/**
|
||||
* An object of type ike_sa_id_t is used to identify an IKE_SA.
|
||||
*
|
||||
* An IKE_SA is identified by its initiator and responder spi's.
|
||||
* Additionally it contains the role of the actual running IKEv2 daemon
|
||||
* for the specific IKE_SA (original initiator or responder).
|
||||
* An IKE_SA is identified by its initiator and responder SPIs.
|
||||
* Additionally, it contains the major IKE version of the IKE_SA and, for IKEv2,
|
||||
* the role of the daemon (original initiator or responder).
|
||||
*/
|
||||
struct ike_sa_id_t {
|
||||
|
||||
/**
|
||||
* Get the major IKE version of this IKE_SA.
|
||||
*
|
||||
* @return IKE version
|
||||
*/
|
||||
u_int8_t (*get_ike_version) (ike_sa_id_t *this);
|
||||
|
||||
/**
|
||||
* Set the SPI of the responder.
|
||||
*
|
||||
@@ -68,10 +76,12 @@ struct ike_sa_id_t {
|
||||
/**
|
||||
* Check if two ike_sa_id_t objects are equal.
|
||||
*
|
||||
* Two ike_sa_id_t objects are equal if both SPI values and the role matches.
|
||||
* Two ike_sa_id_t objects are equal if version and both SPI values match.
|
||||
* The role is not compared.
|
||||
*
|
||||
* @param other ike_sa_id_t object to check if equal
|
||||
* @return TRUE if given ike_sa_id_t are equal, FALSE otherwise
|
||||
* @return TRUE if given ike_sa_id_t are equal,
|
||||
* FALSE otherwise
|
||||
*/
|
||||
bool (*equals) (ike_sa_id_t *this, ike_sa_id_t *other);
|
||||
|
||||
@@ -93,9 +103,9 @@ struct ike_sa_id_t {
|
||||
bool (*is_initiator) (ike_sa_id_t *this);
|
||||
|
||||
/**
|
||||
* Switche the original initiator flag.
|
||||
* Switch the original initiator flag.
|
||||
*
|
||||
* @return TRUE if we are the original initiator after switch, FALSE otherwise
|
||||
* @return new value if initiator flag.
|
||||
*/
|
||||
bool (*switch_initiator) (ike_sa_id_t *this);
|
||||
|
||||
@@ -113,14 +123,15 @@ struct ike_sa_id_t {
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an ike_sa_id_t object with specific SPI's and defined role.
|
||||
* Creates an ike_sa_id_t object.
|
||||
*
|
||||
* @param ike_version major IKE version
|
||||
* @param initiator_spi initiators SPI
|
||||
* @param responder_spi responders SPI
|
||||
* @param is_initiaor TRUE if we are the original initiator
|
||||
* @return ike_sa_id_t object
|
||||
*/
|
||||
ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi,
|
||||
bool is_initiaor);
|
||||
ike_sa_id_t * ike_sa_id_create(u_int8_t ike_version, u_int64_t initiator_spi,
|
||||
u_int64_t responder_spi, bool is_initiaor);
|
||||
|
||||
#endif /** IKE_SA_ID_H_ @}*/
|
||||
|
||||
+511
-302
File diff suppressed because it is too large
Load Diff
@@ -52,10 +52,12 @@ struct ike_sa_manager_t {
|
||||
/**
|
||||
* Create and check out a new IKE_SA.
|
||||
*
|
||||
* @param version IKE version of this SA
|
||||
* @param initiator TRUE for initiator, FALSE otherwise
|
||||
* @returns created and checked out IKE_SA
|
||||
*/
|
||||
ike_sa_t* (*checkout_new) (ike_sa_manager_t* this, bool initiator);
|
||||
ike_sa_t* (*checkout_new) (ike_sa_manager_t* this, ike_version_t version,
|
||||
bool initiator);
|
||||
|
||||
/**
|
||||
* Checkout an IKE_SA by a message.
|
||||
@@ -167,6 +169,18 @@ struct ike_sa_manager_t {
|
||||
*/
|
||||
enumerator_t *(*create_enumerator) (ike_sa_manager_t* this, bool wait);
|
||||
|
||||
/**
|
||||
* Create an enumerator over ike_sa_id_t*, matching peer identities.
|
||||
*
|
||||
* @param me local peer identity to match
|
||||
* @param other remote peer identity to match
|
||||
* @param family address family to match, 0 for any
|
||||
* @return enumerator over ike_sa_id_t*
|
||||
*/
|
||||
enumerator_t* (*create_id_enumerator)(ike_sa_manager_t *this,
|
||||
identification_t *me, identification_t *other,
|
||||
int family);
|
||||
|
||||
/**
|
||||
* Checkin the SA after usage.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "hybrid_authenticator.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev1/authenticators/psk_v1_authenticator.h>
|
||||
|
||||
typedef struct private_hybrid_authenticator_t private_hybrid_authenticator_t;
|
||||
|
||||
/**
|
||||
* Private data of an hybrid_authenticator_t object.
|
||||
*/
|
||||
struct private_hybrid_authenticator_t {
|
||||
|
||||
/**
|
||||
* Public authenticator_t interface.
|
||||
*/
|
||||
hybrid_authenticator_t public;
|
||||
|
||||
/**
|
||||
* Public key authenticator
|
||||
*/
|
||||
authenticator_t *sig;
|
||||
|
||||
/**
|
||||
* HASH payload authenticator without credentials
|
||||
*/
|
||||
authenticator_t *hash;
|
||||
};
|
||||
|
||||
METHOD(authenticator_t, build_i, status_t,
|
||||
private_hybrid_authenticator_t *this, message_t *message)
|
||||
{
|
||||
return this->hash->build(this->hash, message);
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, process_r, status_t,
|
||||
private_hybrid_authenticator_t *this, message_t *message)
|
||||
{
|
||||
return this->hash->process(this->hash, message);
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, build_r, status_t,
|
||||
private_hybrid_authenticator_t *this, message_t *message)
|
||||
{
|
||||
return this->sig->build(this->sig, message);
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, process_i, status_t,
|
||||
private_hybrid_authenticator_t *this, message_t *message)
|
||||
{
|
||||
return this->sig->process(this->sig, message);
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, destroy, void,
|
||||
private_hybrid_authenticator_t *this)
|
||||
{
|
||||
DESTROY_IF(this->hash);
|
||||
DESTROY_IF(this->sig);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
hybrid_authenticator_t *hybrid_authenticator_create(ike_sa_t *ike_sa,
|
||||
bool initiator, diffie_hellman_t *dh,
|
||||
chunk_t dh_value, chunk_t sa_payload,
|
||||
chunk_t id_payload)
|
||||
{
|
||||
private_hybrid_authenticator_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.authenticator = {
|
||||
.is_mutual = (void*)return_false,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.hash = (authenticator_t*)psk_v1_authenticator_create(ike_sa, initiator,
|
||||
dh, dh_value, sa_payload, id_payload, TRUE),
|
||||
.sig = authenticator_create_v1(ike_sa, initiator, AUTH_RSA, dh,
|
||||
dh_value, sa_payload, chunk_clone(id_payload)),
|
||||
);
|
||||
if (!this->sig || !this->hash)
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
if (initiator)
|
||||
{
|
||||
this->public.authenticator.build = _build_i;
|
||||
this->public.authenticator.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.authenticator.build = _build_r;
|
||||
this->public.authenticator.process = _process_r;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup hybrid_authenticator hybrid_authenticator
|
||||
* @{ @ingroup authenticators
|
||||
*/
|
||||
|
||||
#ifndef HYBRID_AUTHENTICATOR_H_
|
||||
#define HYBRID_AUTHENTICATOR_H_
|
||||
|
||||
typedef struct hybrid_authenticator_t hybrid_authenticator_t;
|
||||
|
||||
#include <sa/authenticator.h>
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t using IKEv1 hybrid authentication.
|
||||
*/
|
||||
struct hybrid_authenticator_t {
|
||||
|
||||
/**
|
||||
* Implemented authenticator_t interface.
|
||||
*/
|
||||
authenticator_t authenticator;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an authenticator to build hybrid signatures.
|
||||
*
|
||||
* @param ike_sa associated IKE_SA
|
||||
* @param initiator TRUE if we are the IKE_SA initiator
|
||||
* @param dh diffie hellman key exchange
|
||||
* @param dh_value others public diffie hellman value
|
||||
* @param sa_payload generated SA payload data, without payload header
|
||||
* @param id_payload encoded ID payload of peer to authenticate or verify
|
||||
* without payload header (gets owned)
|
||||
* @return hybrid authenticator
|
||||
*/
|
||||
hybrid_authenticator_t *hybrid_authenticator_create(ike_sa_t *ike_sa,
|
||||
bool initiator, diffie_hellman_t *dh,
|
||||
chunk_t dh_value, chunk_t sa_payload,
|
||||
chunk_t id_payload);
|
||||
|
||||
#endif /** HYBRID_AUTHENTICATOR_H_ @}*/
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "psk_v1_authenticator.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev1/keymat_v1.h>
|
||||
#include <encoding/payloads/hash_payload.h>
|
||||
|
||||
typedef struct private_psk_v1_authenticator_t private_psk_v1_authenticator_t;
|
||||
|
||||
/**
|
||||
* Private data of an psk_v1_authenticator_t object.
|
||||
*/
|
||||
struct private_psk_v1_authenticator_t {
|
||||
|
||||
/**
|
||||
* Public authenticator_t interface.
|
||||
*/
|
||||
psk_v1_authenticator_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* TRUE if we are initiator
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* DH key exchange
|
||||
*/
|
||||
diffie_hellman_t *dh;
|
||||
|
||||
/**
|
||||
* Others DH public value
|
||||
*/
|
||||
chunk_t dh_value;
|
||||
|
||||
/**
|
||||
* Encoded SA payload, without fixed header
|
||||
*/
|
||||
chunk_t sa_payload;
|
||||
|
||||
/**
|
||||
* Encoded ID payload, without fixed header
|
||||
*/
|
||||
chunk_t id_payload;
|
||||
|
||||
/**
|
||||
* Used for Hybrid authentication to build hash without PSK?
|
||||
*/
|
||||
bool hybrid;
|
||||
};
|
||||
|
||||
METHOD(authenticator_t, build, status_t,
|
||||
private_psk_v1_authenticator_t *this, message_t *message)
|
||||
{
|
||||
hash_payload_t *hash_payload;
|
||||
keymat_v1_t *keymat;
|
||||
chunk_t hash, dh;
|
||||
|
||||
this->dh->get_my_public_value(this->dh, &dh);
|
||||
keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||
hash = keymat->get_hash(keymat, this->initiator, dh, this->dh_value,
|
||||
this->ike_sa->get_id(this->ike_sa), this->sa_payload,
|
||||
this->id_payload);
|
||||
free(dh.ptr);
|
||||
|
||||
hash_payload = hash_payload_create(HASH_V1);
|
||||
hash_payload->set_hash(hash_payload, hash);
|
||||
message->add_payload(message, &hash_payload->payload_interface);
|
||||
free(hash.ptr);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, process, status_t,
|
||||
private_psk_v1_authenticator_t *this, message_t *message)
|
||||
{
|
||||
hash_payload_t *hash_payload;
|
||||
keymat_v1_t *keymat;
|
||||
chunk_t hash, dh;
|
||||
auth_cfg_t *auth;
|
||||
|
||||
hash_payload = (hash_payload_t*)message->get_payload(message, HASH_V1);
|
||||
if (!hash_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "HASH payload missing in message");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
this->dh->get_my_public_value(this->dh, &dh);
|
||||
keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||
hash = keymat->get_hash(keymat, !this->initiator, this->dh_value, dh,
|
||||
this->ike_sa->get_id(this->ike_sa), this->sa_payload,
|
||||
this->id_payload);
|
||||
free(dh.ptr);
|
||||
if (chunk_equals(hash, hash_payload->get_hash(hash_payload)))
|
||||
{
|
||||
free(hash.ptr);
|
||||
if (!this->hybrid)
|
||||
{
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
|
||||
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
free(hash.ptr);
|
||||
DBG1(DBG_IKE, "calculated HASH does not match HASH payload");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, destroy, void,
|
||||
private_psk_v1_authenticator_t *this)
|
||||
{
|
||||
chunk_free(&this->id_payload);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
psk_v1_authenticator_t *psk_v1_authenticator_create(ike_sa_t *ike_sa,
|
||||
bool initiator, diffie_hellman_t *dh,
|
||||
chunk_t dh_value, chunk_t sa_payload,
|
||||
chunk_t id_payload, bool hybrid)
|
||||
{
|
||||
private_psk_v1_authenticator_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.authenticator = {
|
||||
.build = _build,
|
||||
.process = _process,
|
||||
.is_mutual = (void*)return_false,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.initiator = initiator,
|
||||
.dh = dh,
|
||||
.dh_value = dh_value,
|
||||
.sa_payload = sa_payload,
|
||||
.id_payload = id_payload,
|
||||
.hybrid = hybrid,
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup psk_v1_authenticator psk_v1_authenticator
|
||||
* @{ @ingroup authenticators
|
||||
*/
|
||||
|
||||
#ifndef PSK_V1_AUTHENTICATOR_H_
|
||||
#define PSK_V1_AUTHENTICATOR_H_
|
||||
|
||||
typedef struct psk_v1_authenticator_t psk_v1_authenticator_t;
|
||||
|
||||
#include <sa/authenticator.h>
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t using pre-shared keys for IKEv1.
|
||||
*/
|
||||
struct psk_v1_authenticator_t {
|
||||
|
||||
/**
|
||||
* Implemented authenticator_t interface.
|
||||
*/
|
||||
authenticator_t authenticator;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an authenticator to build PSK signatures.
|
||||
*
|
||||
* @param ike_sa associated IKE_SA
|
||||
* @param initiator TRUE if we are the IKE_SA initiator
|
||||
* @param dh diffie hellman key exchange
|
||||
* @param dh_value others public diffie hellman value
|
||||
* @param sa_payload generated SA payload data, without payload header
|
||||
* @param id_payload encoded ID payload of peer to authenticate or verify
|
||||
* without payload header (gets owned)
|
||||
* @param hybrid TRUE if used for hybrid authentication without PSK
|
||||
* @return PSK authenticator
|
||||
*/
|
||||
psk_v1_authenticator_t *psk_v1_authenticator_create(ike_sa_t *ike_sa,
|
||||
bool initiator, diffie_hellman_t *dh,
|
||||
chunk_t dh_value, chunk_t sa_payload,
|
||||
chunk_t id_payload, bool hybrid);
|
||||
|
||||
#endif /** PSK_V1_AUTHENTICATOR_H_ @}*/
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "pubkey_v1_authenticator.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev1/keymat_v1.h>
|
||||
#include <encoding/payloads/hash_payload.h>
|
||||
|
||||
typedef struct private_pubkey_v1_authenticator_t private_pubkey_v1_authenticator_t;
|
||||
|
||||
/**
|
||||
* Private data of an pubkey_v1_authenticator_t object.
|
||||
*/
|
||||
struct private_pubkey_v1_authenticator_t {
|
||||
|
||||
/**
|
||||
* Public authenticator_t interface.
|
||||
*/
|
||||
pubkey_v1_authenticator_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* TRUE if we are initiator
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* DH key exchange
|
||||
*/
|
||||
diffie_hellman_t *dh;
|
||||
|
||||
/**
|
||||
* Others DH public value
|
||||
*/
|
||||
chunk_t dh_value;
|
||||
|
||||
/**
|
||||
* Encoded SA payload, without fixed header
|
||||
*/
|
||||
chunk_t sa_payload;
|
||||
|
||||
/**
|
||||
* Encoded ID payload, without fixed header
|
||||
*/
|
||||
chunk_t id_payload;
|
||||
|
||||
/**
|
||||
* Key type to use
|
||||
*/
|
||||
key_type_t type;
|
||||
};
|
||||
|
||||
METHOD(authenticator_t, build, status_t,
|
||||
private_pubkey_v1_authenticator_t *this, message_t *message)
|
||||
{
|
||||
hash_payload_t *sig_payload;
|
||||
chunk_t hash, sig, dh;
|
||||
keymat_v1_t *keymat;
|
||||
status_t status;
|
||||
private_key_t *private;
|
||||
identification_t *id;
|
||||
auth_cfg_t *auth;
|
||||
signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_NULL;
|
||||
|
||||
if (this->type == KEY_ECDSA)
|
||||
{
|
||||
scheme = SIGN_ECDSA_WITH_NULL;
|
||||
}
|
||||
|
||||
id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
|
||||
private = lib->credmgr->get_private(lib->credmgr, this->type, id, auth);
|
||||
if (!private)
|
||||
{
|
||||
DBG1(DBG_IKE, "no %N private key found for '%Y'",
|
||||
key_type_names, this->type, id);
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
this->dh->get_my_public_value(this->dh, &dh);
|
||||
keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||
hash = keymat->get_hash(keymat, this->initiator, dh, this->dh_value,
|
||||
this->ike_sa->get_id(this->ike_sa), this->sa_payload,
|
||||
this->id_payload);
|
||||
free(dh.ptr);
|
||||
|
||||
if (private->sign(private, scheme, hash, &sig))
|
||||
{
|
||||
sig_payload = hash_payload_create(SIGNATURE_V1);
|
||||
sig_payload->set_hash(sig_payload, sig);
|
||||
free(sig.ptr);
|
||||
message->add_payload(message, &sig_payload->payload_interface);
|
||||
status = SUCCESS;
|
||||
DBG1(DBG_IKE, "authentication of '%Y' (myself) successful", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "authentication of '%Y' (myself) failed", id);
|
||||
status = FAILED;
|
||||
}
|
||||
private->destroy(private);
|
||||
free(hash.ptr);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, process, status_t,
|
||||
private_pubkey_v1_authenticator_t *this, message_t *message)
|
||||
{
|
||||
chunk_t hash, sig, dh;
|
||||
keymat_v1_t *keymat;
|
||||
public_key_t *public;
|
||||
hash_payload_t *sig_payload;
|
||||
auth_cfg_t *auth, *current_auth;
|
||||
enumerator_t *enumerator;
|
||||
status_t status = NOT_FOUND;
|
||||
identification_t *id;
|
||||
signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_NULL;
|
||||
|
||||
if (this->type == KEY_ECDSA)
|
||||
{
|
||||
scheme = SIGN_ECDSA_WITH_NULL;
|
||||
}
|
||||
|
||||
sig_payload = (hash_payload_t*)message->get_payload(message, SIGNATURE_V1);
|
||||
if (!sig_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "SIG payload missing in message");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
this->dh->get_my_public_value(this->dh, &dh);
|
||||
keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||
hash = keymat->get_hash(keymat, !this->initiator, this->dh_value, dh,
|
||||
this->ike_sa->get_id(this->ike_sa), this->sa_payload,
|
||||
this->id_payload);
|
||||
free(dh.ptr);
|
||||
|
||||
sig = sig_payload->get_hash(sig_payload);
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
|
||||
enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, this->type,
|
||||
id, auth);
|
||||
while (enumerator->enumerate(enumerator, &public, ¤t_auth))
|
||||
{
|
||||
if (public->verify(public, scheme, hash, sig))
|
||||
{
|
||||
DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
|
||||
id, key_type_names, this->type);
|
||||
status = SUCCESS;
|
||||
auth->merge(auth, current_auth, FALSE);
|
||||
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "signature validation failed, looking for another key");
|
||||
status = FAILED;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
free(hash.ptr);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "no trusted %N public key found for '%Y'",
|
||||
key_type_names, this->type, id);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, destroy, void,
|
||||
private_pubkey_v1_authenticator_t *this)
|
||||
{
|
||||
chunk_free(&this->id_payload);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa,
|
||||
bool initiator, diffie_hellman_t *dh,
|
||||
chunk_t dh_value, chunk_t sa_payload,
|
||||
chunk_t id_payload, key_type_t type)
|
||||
{
|
||||
private_pubkey_v1_authenticator_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.authenticator = {
|
||||
.build = _build,
|
||||
.process = _process,
|
||||
.is_mutual = (void*)return_false,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.initiator = initiator,
|
||||
.dh = dh,
|
||||
.dh_value = dh_value,
|
||||
.sa_payload = sa_payload,
|
||||
.id_payload = id_payload,
|
||||
.type = type,
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup pubkey_v1_authenticator pubkey_v1_authenticator
|
||||
* @{ @ingroup authenticators
|
||||
*/
|
||||
|
||||
#ifndef PUBKEY_V1_AUTHENTICATOR_H_
|
||||
#define PUBKEY_V1_AUTHENTICATOR_H_
|
||||
|
||||
typedef struct pubkey_v1_authenticator_t pubkey_v1_authenticator_t;
|
||||
|
||||
#include <sa/authenticator.h>
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t using public keys for IKEv1.
|
||||
*/
|
||||
struct pubkey_v1_authenticator_t {
|
||||
|
||||
/**
|
||||
* Implemented authenticator_t interface.
|
||||
*/
|
||||
authenticator_t authenticator;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an authenticator to build and verify public key signatures.
|
||||
*
|
||||
* @param ike_sa associated IKE_SA
|
||||
* @param initiator TRUE if we are IKE_SA initiator
|
||||
* @param dh diffie hellman key exchange
|
||||
* @param dh_value others public diffie hellman value
|
||||
* @param sa_payload generated SA payload data, without payload header
|
||||
* @param id_payload encoded ID payload of peer to authenticate or verify
|
||||
* without payload header (gets owned)
|
||||
* @param type key type to use, KEY_RSA or KEY_ECDSA
|
||||
* @return pubkey authenticator
|
||||
*/
|
||||
pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa,
|
||||
bool initiator, diffie_hellman_t *dh,
|
||||
chunk_t dh_value, chunk_t sa_payload,
|
||||
chunk_t id_payload, key_type_t type);
|
||||
|
||||
#endif /** PUBKEY_V1_AUTHENTICATOR_H_ @}*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Tobias Brunner
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup keymat_v1 keymat_v1
|
||||
* @{ @ingroup sa
|
||||
*/
|
||||
|
||||
#ifndef KEYMAT_V1_H_
|
||||
#define KEYMAT_V1_H_
|
||||
|
||||
#include <sa/keymat.h>
|
||||
#include <sa/authenticator.h>
|
||||
|
||||
typedef struct keymat_v1_t keymat_v1_t;
|
||||
|
||||
/**
|
||||
* Derivation and management of sensitive keying material, IKEv1 variant.
|
||||
*/
|
||||
struct keymat_v1_t {
|
||||
|
||||
/**
|
||||
* Implements keymat_t.
|
||||
*/
|
||||
keymat_t keymat;
|
||||
|
||||
/**
|
||||
* Derive keys for the IKE_SA.
|
||||
*
|
||||
* These keys are not handed out, but are used by the associated signers,
|
||||
* crypters and authentication functions.
|
||||
*
|
||||
* @param proposal selected algorithms
|
||||
* @param dh diffie hellman key allocated by create_dh()
|
||||
* @param dh_other public DH value from other peer
|
||||
* @param nonce_i initiators nonce value
|
||||
* @param nonce_r responders nonce value
|
||||
* @param id IKE_SA identifier
|
||||
* @param auth authentication method
|
||||
* @param shared_key PSK in case of AUTH_CLASS_PSK, NULL otherwise
|
||||
* @return TRUE on success
|
||||
*/
|
||||
bool (*derive_ike_keys)(keymat_v1_t *this, proposal_t *proposal,
|
||||
diffie_hellman_t *dh, chunk_t dh_other,
|
||||
chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id,
|
||||
auth_method_t auth, shared_key_t *shared_key);
|
||||
|
||||
/**
|
||||
* Derive keys for the CHILD_SA.
|
||||
*
|
||||
* @param proposal selected algorithms
|
||||
* @param dh diffie hellman key, NULL if none used
|
||||
* @param spi_i SPI chosen by initiatior
|
||||
* @param spi_r SPI chosen by responder
|
||||
* @param nonce_i quick mode initiator nonce
|
||||
* @param nonce_r quick mode responder nonce
|
||||
* @param encr_i allocated initiators encryption key
|
||||
* @param integ_i allocated initiators integrity key
|
||||
* @param encr_r allocated responders encryption key
|
||||
* @param integ_r allocated responders integrity key
|
||||
*/
|
||||
bool (*derive_child_keys)(keymat_v1_t *this, proposal_t *proposal,
|
||||
diffie_hellman_t *dh, u_int32_t spi_i, u_int32_t spi_r,
|
||||
chunk_t nonce_i, chunk_t nonce_r,
|
||||
chunk_t *encr_i, chunk_t *integ_i,
|
||||
chunk_t *encr_r, chunk_t *integ_r);
|
||||
|
||||
/**
|
||||
* Create the negotiated hasher.
|
||||
*
|
||||
* @param proposal selected algorithms
|
||||
* @return TRUE, if creation was successful
|
||||
*/
|
||||
bool (*create_hasher)(keymat_v1_t *this, proposal_t *proposal);
|
||||
|
||||
/**
|
||||
* Get the negotiated hasher.
|
||||
*
|
||||
* @return allocated hasher or NULL
|
||||
*/
|
||||
hasher_t *(*get_hasher)(keymat_v1_t *this);
|
||||
|
||||
/**
|
||||
* Get HASH data for authentication.
|
||||
*
|
||||
* @param initiatior TRUE to create HASH_I, FALSE for HASH_R
|
||||
* @param dh public DH value of peer to create HASH for
|
||||
* @param dh_other others public DH value
|
||||
* @param ike_sa_id IKE_SA identifier
|
||||
* @param sa_i encoded SA payload of initiator
|
||||
* @param id encoded IDii payload for HASH_I (IDir for HASH_R)
|
||||
* @return allocated HASH data
|
||||
*/
|
||||
chunk_t (*get_hash)(keymat_v1_t *this, bool initiator,
|
||||
chunk_t dh, chunk_t dh_other, ike_sa_id_t *ike_sa_id,
|
||||
chunk_t sa_i, chunk_t id);
|
||||
|
||||
/**
|
||||
* Get HASH data for integrity/authentication in Phase 2 exchanges.
|
||||
*
|
||||
* @param message message to generate the HASH data for
|
||||
* @return allocated HASH data
|
||||
*/
|
||||
chunk_t (*get_hash_phase2)(keymat_v1_t *this, message_t *message);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the IV for a message with the given message ID.
|
||||
*
|
||||
* @param mid message ID
|
||||
* @return IV (needs to be freed)
|
||||
*/
|
||||
chunk_t (*get_iv)(keymat_v1_t *this, u_int32_t mid);
|
||||
|
||||
/**
|
||||
* Updates the IV for the next message with the given message ID.
|
||||
*
|
||||
* A call of confirm_iv() is required in order to actually make the IV
|
||||
* available. This is needed for the inbound case where we store the last
|
||||
* block of the encrypted message but want to update the IV only after
|
||||
* verification of the decrypted message.
|
||||
*
|
||||
* @param mid message ID
|
||||
* @param last_block last block of encrypted message (gets cloned)
|
||||
*/
|
||||
void (*update_iv)(keymat_v1_t *this, u_int32_t mid, chunk_t last_block);
|
||||
|
||||
/**
|
||||
* Confirms the updated IV for the given message ID.
|
||||
*
|
||||
* To actually make the new IV available via get_iv this method has to
|
||||
* be called after update_iv.
|
||||
*
|
||||
* @param mid message ID
|
||||
*/
|
||||
void (*confirm_iv)(keymat_v1_t *this, u_int32_t mid);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a keymat instance.
|
||||
*
|
||||
* @param initiator TRUE if we are the initiator
|
||||
* @return keymat instance
|
||||
*/
|
||||
keymat_v1_t *keymat_v1_create(bool initiator);
|
||||
|
||||
#endif /** KEYMAT_V1_H_ @}*/
|
||||
@@ -0,0 +1,700 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Willi
|
||||
* Copyright (C) 2012 revosec AG
|
||||
*
|
||||
* 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 "phase1.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev1/keymat_v1.h>
|
||||
#include <encoding/payloads/ke_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
|
||||
typedef struct private_phase1_t private_phase1_t;
|
||||
|
||||
/**
|
||||
* Private data of an phase1_t object.
|
||||
*/
|
||||
struct private_phase1_t {
|
||||
|
||||
/**
|
||||
* Public phase1_t interface.
|
||||
*/
|
||||
phase1_t public;
|
||||
|
||||
/**
|
||||
* IKE_SA we negotiate
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Acting as initiator
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* Extracted SA payload bytes
|
||||
*/
|
||||
chunk_t sa_payload;
|
||||
|
||||
/**
|
||||
* DH exchange
|
||||
*/
|
||||
diffie_hellman_t *dh;
|
||||
|
||||
/**
|
||||
* Keymat derivation (from SA)
|
||||
*/
|
||||
keymat_v1_t *keymat;
|
||||
|
||||
/**
|
||||
* Received public DH value from peer
|
||||
*/
|
||||
chunk_t dh_value;
|
||||
|
||||
/**
|
||||
* Initiators nonce
|
||||
*/
|
||||
chunk_t nonce_i;
|
||||
|
||||
/**
|
||||
* Responder nonce
|
||||
*/
|
||||
chunk_t nonce_r;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the first authentcation config from peer config
|
||||
*/
|
||||
static auth_cfg_t *get_auth_cfg(peer_cfg_t *peer_cfg, bool local)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
auth_cfg_t *cfg = NULL;
|
||||
|
||||
enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local);
|
||||
enumerator->enumerate(enumerator, &cfg);
|
||||
enumerator->destroy(enumerator);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup a shared secret for this IKE_SA
|
||||
*/
|
||||
static shared_key_t *lookup_shared_key(private_phase1_t *this,
|
||||
peer_cfg_t *peer_cfg)
|
||||
{
|
||||
host_t *me, *other;
|
||||
identification_t *my_id, *other_id;
|
||||
shared_key_t *shared_key = NULL;
|
||||
auth_cfg_t *my_auth, *other_auth;
|
||||
enumerator_t *enumerator;
|
||||
|
||||
/* try to get a PSK for IP addresses */
|
||||
me = this->ike_sa->get_my_host(this->ike_sa);
|
||||
other = this->ike_sa->get_other_host(this->ike_sa);
|
||||
my_id = identification_create_from_sockaddr(me->get_sockaddr(me));
|
||||
other_id = identification_create_from_sockaddr(other->get_sockaddr(other));
|
||||
if (my_id && other_id)
|
||||
{
|
||||
shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE,
|
||||
my_id, other_id);
|
||||
}
|
||||
DESTROY_IF(my_id);
|
||||
DESTROY_IF(other_id);
|
||||
if (shared_key)
|
||||
{
|
||||
return shared_key;
|
||||
}
|
||||
|
||||
if (peer_cfg)
|
||||
{ /* as initiator, use identities from configuraiton */
|
||||
my_auth = get_auth_cfg(peer_cfg, TRUE);
|
||||
other_auth = get_auth_cfg(peer_cfg, FALSE);
|
||||
if (my_auth && other_auth)
|
||||
{
|
||||
my_id = my_auth->get(my_auth, AUTH_RULE_IDENTITY);
|
||||
other_id = other_auth->get(other_auth, AUTH_RULE_IDENTITY);
|
||||
if (my_id && other_id)
|
||||
{
|
||||
shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE,
|
||||
my_id, other_id);
|
||||
if (!shared_key)
|
||||
{
|
||||
DBG1(DBG_IKE, "no shared key found for '%Y'[%H] - '%Y'[%H]",
|
||||
my_id, me, other_id, other);
|
||||
}
|
||||
}
|
||||
}
|
||||
return shared_key;
|
||||
}
|
||||
/* as responder, we try to find a config by IP */
|
||||
enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
|
||||
me, other, NULL, NULL, IKEV1);
|
||||
while (enumerator->enumerate(enumerator, &peer_cfg))
|
||||
{
|
||||
my_auth = get_auth_cfg(peer_cfg, TRUE);
|
||||
other_auth = get_auth_cfg(peer_cfg, FALSE);
|
||||
if (my_auth && other_auth)
|
||||
{
|
||||
my_id = my_auth->get(my_auth, AUTH_RULE_IDENTITY);
|
||||
other_id = other_auth->get(other_auth, AUTH_RULE_IDENTITY);
|
||||
if (my_id && other_id)
|
||||
{
|
||||
shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE,
|
||||
my_id, other_id);
|
||||
if (shared_key)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "no shared key found for '%Y'[%H] - '%Y'[%H]",
|
||||
my_id, me, other_id, other);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
if (!peer_cfg)
|
||||
{
|
||||
DBG1(DBG_IKE, "no shared key found for %H - %H", me, other);
|
||||
}
|
||||
return shared_key;
|
||||
}
|
||||
|
||||
METHOD(phase1_t, create_hasher, bool,
|
||||
private_phase1_t *this)
|
||||
{
|
||||
return this->keymat->create_hasher(this->keymat,
|
||||
this->ike_sa->get_proposal(this->ike_sa));
|
||||
}
|
||||
|
||||
METHOD(phase1_t, create_dh, bool,
|
||||
private_phase1_t *this, diffie_hellman_group_t group)
|
||||
{
|
||||
this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, group);
|
||||
return this->dh != NULL;
|
||||
}
|
||||
|
||||
METHOD(phase1_t, derive_keys, bool,
|
||||
private_phase1_t *this, peer_cfg_t *peer_cfg, auth_method_t method)
|
||||
{
|
||||
shared_key_t *shared_key = NULL;
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case AUTH_PSK:
|
||||
case AUTH_XAUTH_INIT_PSK:
|
||||
case AUTH_XAUTH_RESP_PSK:
|
||||
shared_key = lookup_shared_key(this, peer_cfg);
|
||||
if (!shared_key)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!this->keymat->derive_ike_keys(this->keymat,
|
||||
this->ike_sa->get_proposal(this->ike_sa),
|
||||
this->dh, this->dh_value, this->nonce_i, this->nonce_r,
|
||||
this->ike_sa->get_id(this->ike_sa), method, shared_key))
|
||||
{
|
||||
DESTROY_IF(shared_key);
|
||||
DBG1(DBG_IKE, "key derivation for %N failed", auth_method_names, method);
|
||||
return FALSE;
|
||||
}
|
||||
charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, this->dh_value,
|
||||
this->nonce_i, this->nonce_r, NULL, shared_key);
|
||||
DESTROY_IF(shared_key);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a peer skipped authentication by using Hybrid authentication
|
||||
*/
|
||||
static bool skipped_auth(private_phase1_t *this,
|
||||
auth_method_t method, bool local)
|
||||
{
|
||||
bool initiator;
|
||||
|
||||
initiator = local == this->initiator;
|
||||
if (initiator && method == AUTH_HYBRID_INIT_RSA)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (!initiator && method == AUTH_HYBRID_RESP_RSA)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if remote authentication constraints fulfilled
|
||||
*/
|
||||
static bool check_constraints(private_phase1_t *this, auth_method_t method)
|
||||
{
|
||||
identification_t *id;
|
||||
auth_cfg_t *auth, *cfg;
|
||||
peer_cfg_t *peer_cfg;
|
||||
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
|
||||
/* auth identity to comply */
|
||||
id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
auth->add(auth, AUTH_RULE_IDENTITY, id->clone(id));
|
||||
if (skipped_auth(this, method, FALSE))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
cfg = get_auth_cfg(peer_cfg, FALSE);
|
||||
return cfg && auth->complies(auth, cfg, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save authentication information after authentication succeeded
|
||||
*/
|
||||
static void save_auth_cfg(private_phase1_t *this,
|
||||
auth_method_t method, bool local)
|
||||
{
|
||||
auth_cfg_t *auth;
|
||||
|
||||
if (skipped_auth(this, method, local))
|
||||
{
|
||||
return;
|
||||
}
|
||||
auth = auth_cfg_create();
|
||||
/* for local config, we _copy_ entires from the config, as it contains
|
||||
* certificates we must send later. */
|
||||
auth->merge(auth, this->ike_sa->get_auth_cfg(this->ike_sa, local), local);
|
||||
this->ike_sa->add_auth_cfg(this->ike_sa, local, auth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an authenticator instance
|
||||
*/
|
||||
static authenticator_t* create_authenticator(private_phase1_t *this,
|
||||
auth_method_t method, chunk_t id)
|
||||
{
|
||||
authenticator_t *authenticator;
|
||||
|
||||
authenticator = authenticator_create_v1(this->ike_sa, this->initiator,
|
||||
method, this->dh, this->dh_value, this->sa_payload, id);
|
||||
if (!authenticator)
|
||||
{
|
||||
DBG1(DBG_IKE, "negotiated authentication method %N not supported",
|
||||
auth_method_names, method);
|
||||
}
|
||||
return authenticator;
|
||||
}
|
||||
|
||||
METHOD(phase1_t, verify_auth, bool,
|
||||
private_phase1_t *this, auth_method_t method, message_t *message,
|
||||
chunk_t id_data)
|
||||
{
|
||||
authenticator_t *authenticator;
|
||||
status_t status;
|
||||
|
||||
authenticator = create_authenticator(this, method, id_data);
|
||||
if (authenticator)
|
||||
{
|
||||
status = authenticator->process(authenticator, message);
|
||||
authenticator->destroy(authenticator);
|
||||
if (status == SUCCESS && check_constraints(this, method))
|
||||
{
|
||||
save_auth_cfg(this, method, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
METHOD(phase1_t, build_auth, bool,
|
||||
private_phase1_t *this, auth_method_t method, message_t *message,
|
||||
chunk_t id_data)
|
||||
{
|
||||
authenticator_t *authenticator;
|
||||
status_t status;
|
||||
|
||||
authenticator = create_authenticator(this, method, id_data);
|
||||
if (authenticator)
|
||||
{
|
||||
status = authenticator->build(authenticator, message);
|
||||
authenticator->destroy(authenticator);
|
||||
if (status == SUCCESS)
|
||||
{
|
||||
save_auth_cfg(this, method, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the two auth classes from local or remote config
|
||||
*/
|
||||
static void get_auth_class(peer_cfg_t *peer_cfg, bool local,
|
||||
auth_class_t *c1, auth_class_t *c2)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
auth_cfg_t *auth;
|
||||
|
||||
*c1 = *c2 = AUTH_CLASS_ANY;
|
||||
|
||||
enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local);
|
||||
while (enumerator->enumerate(enumerator, &auth))
|
||||
{
|
||||
if (*c1 == AUTH_CLASS_ANY)
|
||||
{
|
||||
*c1 = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS);
|
||||
}
|
||||
else
|
||||
{
|
||||
*c2 = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select an auth method to use by checking what key we have
|
||||
*/
|
||||
static auth_method_t get_pubkey_method(private_phase1_t *this, auth_cfg_t *auth)
|
||||
{
|
||||
auth_method_t method = AUTH_NONE;
|
||||
identification_t *id;
|
||||
private_key_t *private;
|
||||
|
||||
if (auth)
|
||||
{
|
||||
id = (identification_t*)auth->get(auth, AUTH_RULE_IDENTITY);
|
||||
if (id)
|
||||
{
|
||||
private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, id, NULL);
|
||||
if (private)
|
||||
{
|
||||
switch (private->get_type(private))
|
||||
{
|
||||
case KEY_RSA:
|
||||
method = AUTH_RSA;
|
||||
break;
|
||||
case KEY_ECDSA:
|
||||
switch (private->get_keysize(private))
|
||||
{
|
||||
case 256:
|
||||
method = AUTH_ECDSA_256;
|
||||
break;
|
||||
case 384:
|
||||
method = AUTH_ECDSA_384;
|
||||
break;
|
||||
case 521:
|
||||
method = AUTH_ECDSA_521;
|
||||
break;
|
||||
default:
|
||||
DBG1(DBG_IKE, "%d bit ECDSA private key size not "
|
||||
"supported", private->get_keysize(private));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DBG1(DBG_IKE, "private key of type %N not supported",
|
||||
key_type_names, private->get_type(private));
|
||||
break;
|
||||
}
|
||||
private->destroy(private);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "no private key found for '%Y'", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate authentication method from a peer config
|
||||
*/
|
||||
static auth_method_t calc_auth_method(private_phase1_t *this,
|
||||
peer_cfg_t *peer_cfg)
|
||||
{
|
||||
auth_class_t i1, i2, r1, r2;
|
||||
|
||||
get_auth_class(peer_cfg, this->initiator, &i1, &i2);
|
||||
get_auth_class(peer_cfg, !this->initiator, &r1, &r2);
|
||||
|
||||
if (i1 == AUTH_CLASS_PUBKEY && r1 == AUTH_CLASS_PUBKEY)
|
||||
{
|
||||
if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY)
|
||||
{
|
||||
/* for any pubkey method, return RSA */
|
||||
return AUTH_RSA;
|
||||
}
|
||||
if (i2 == AUTH_CLASS_XAUTH)
|
||||
{
|
||||
return AUTH_XAUTH_INIT_RSA;
|
||||
}
|
||||
if (r2 == AUTH_CLASS_XAUTH)
|
||||
{
|
||||
return AUTH_XAUTH_RESP_RSA;
|
||||
}
|
||||
}
|
||||
if (i1 == AUTH_CLASS_PSK && r1 == AUTH_CLASS_PSK)
|
||||
{
|
||||
if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY)
|
||||
{
|
||||
return AUTH_PSK;
|
||||
}
|
||||
if (i2 == AUTH_CLASS_XAUTH)
|
||||
{
|
||||
return AUTH_XAUTH_INIT_PSK;
|
||||
}
|
||||
if (r2 == AUTH_CLASS_XAUTH)
|
||||
{
|
||||
return AUTH_XAUTH_RESP_PSK;
|
||||
}
|
||||
}
|
||||
if (i1 == AUTH_CLASS_XAUTH && r1 == AUTH_CLASS_PUBKEY &&
|
||||
i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY)
|
||||
{
|
||||
return AUTH_HYBRID_INIT_RSA;
|
||||
}
|
||||
return AUTH_NONE;
|
||||
}
|
||||
|
||||
METHOD(phase1_t, get_auth_method, auth_method_t,
|
||||
private_phase1_t *this, peer_cfg_t *peer_cfg)
|
||||
{
|
||||
auth_method_t method;
|
||||
|
||||
method = calc_auth_method(this, peer_cfg);
|
||||
if (method == AUTH_RSA)
|
||||
{
|
||||
return get_pubkey_method(this, get_auth_cfg(peer_cfg, TRUE));
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a peer config can be used with a given auth method
|
||||
*/
|
||||
static bool check_auth_method(private_phase1_t *this, peer_cfg_t *peer_cfg,
|
||||
auth_method_t given)
|
||||
{
|
||||
auth_method_t method;
|
||||
|
||||
method = calc_auth_method(this, peer_cfg);
|
||||
switch (given)
|
||||
{
|
||||
case AUTH_ECDSA_256:
|
||||
case AUTH_ECDSA_384:
|
||||
case AUTH_ECDSA_521:
|
||||
return method == AUTH_RSA;
|
||||
default:
|
||||
return method == given;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(phase1_t, select_config, peer_cfg_t*,
|
||||
private_phase1_t *this, auth_method_t method, bool aggressive,
|
||||
identification_t *id)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
peer_cfg_t *current, *found = NULL;
|
||||
host_t *me, *other;
|
||||
|
||||
me = this->ike_sa->get_my_host(this->ike_sa);
|
||||
other = this->ike_sa->get_other_host(this->ike_sa);
|
||||
DBG1(DBG_CFG, "looking for %N peer configs matching %H...%H[%Y]",
|
||||
auth_method_names, method, me, other, id);
|
||||
enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
|
||||
me, other, NULL, id, IKEV1);
|
||||
while (enumerator->enumerate(enumerator, ¤t))
|
||||
{
|
||||
if (check_auth_method(this, current, method) &&
|
||||
current->use_aggressive(current) == aggressive)
|
||||
{
|
||||
found = current->get_ref(current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
if (found)
|
||||
{
|
||||
DBG2(DBG_CFG, "selected peer config \"%s\"", found->get_name(found));
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
METHOD(phase1_t, get_id, identification_t*,
|
||||
private_phase1_t *this, peer_cfg_t *peer_cfg, bool local)
|
||||
{
|
||||
auth_cfg_t *auth;
|
||||
|
||||
auth = get_auth_cfg(peer_cfg, local);
|
||||
if (auth)
|
||||
{
|
||||
return auth->get(auth, AUTH_RULE_IDENTITY);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
METHOD(phase1_t, save_sa_payload, bool,
|
||||
private_phase1_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload, *sa = NULL;
|
||||
chunk_t data;
|
||||
size_t offset = IKE_HEADER_LENGTH;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1)
|
||||
{
|
||||
sa = payload;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset += payload->get_length(payload);
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
data = message->get_packet_data(message);
|
||||
if (sa && data.len >= offset + sa->get_length(sa))
|
||||
{
|
||||
/* Get SA payload without 4 byte fixed header */
|
||||
data = chunk_skip(data, offset);
|
||||
data.len = sa->get_length(sa);
|
||||
data = chunk_skip(data, 4);
|
||||
this->sa_payload = chunk_clone(data);
|
||||
return TRUE;
|
||||
}
|
||||
DBG1(DBG_IKE, "unable to extract SA payload encoding");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
METHOD(phase1_t, add_nonce_ke, bool,
|
||||
private_phase1_t *this, message_t *message)
|
||||
{
|
||||
nonce_payload_t *nonce_payload;
|
||||
ke_payload_t *ke_payload;
|
||||
chunk_t nonce;
|
||||
rng_t *rng;
|
||||
|
||||
ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1, this->dh);
|
||||
message->add_payload(message, &ke_payload->payload_interface);
|
||||
|
||||
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||
if (!rng)
|
||||
{
|
||||
DBG1(DBG_IKE, "no RNG found to create nonce");
|
||||
return FALSE;
|
||||
}
|
||||
rng->allocate_bytes(rng, NONCE_SIZE, &nonce);
|
||||
rng->destroy(rng);
|
||||
|
||||
nonce_payload = nonce_payload_create(NONCE_V1);
|
||||
nonce_payload->set_nonce(nonce_payload, nonce);
|
||||
message->add_payload(message, &nonce_payload->payload_interface);
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
this->nonce_i = nonce;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->nonce_r = nonce;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(phase1_t, get_nonce_ke, bool,
|
||||
private_phase1_t *this, message_t *message)
|
||||
{
|
||||
nonce_payload_t *nonce_payload;
|
||||
ke_payload_t *ke_payload;
|
||||
|
||||
ke_payload = (ke_payload_t*)message->get_payload(message, KEY_EXCHANGE_V1);
|
||||
if (!ke_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "KE payload missing in message");
|
||||
return FALSE;
|
||||
}
|
||||
this->dh_value = chunk_clone(ke_payload->get_key_exchange_data(ke_payload));
|
||||
this->dh->set_other_public_value(this->dh, this->dh_value);
|
||||
|
||||
nonce_payload = (nonce_payload_t*)message->get_payload(message, NONCE_V1);
|
||||
if (!nonce_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "NONCE payload missing in message");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
this->nonce_r = nonce_payload->get_nonce(nonce_payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->nonce_i = nonce_payload->get_nonce(nonce_payload);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(phase1_t, destroy, void,
|
||||
private_phase1_t *this)
|
||||
{
|
||||
chunk_free(&this->sa_payload);
|
||||
DESTROY_IF(this->dh);
|
||||
free(this->dh_value.ptr);
|
||||
free(this->nonce_i.ptr);
|
||||
free(this->nonce_r.ptr);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
phase1_t *phase1_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_phase1_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.create_hasher = _create_hasher,
|
||||
.create_dh = _create_dh,
|
||||
.derive_keys = _derive_keys,
|
||||
.get_auth_method = _get_auth_method,
|
||||
.get_id = _get_id,
|
||||
.select_config = _select_config,
|
||||
.verify_auth = _verify_auth,
|
||||
.build_auth = _build_auth,
|
||||
.save_sa_payload = _save_sa_payload,
|
||||
.add_nonce_ke = _add_nonce_ke,
|
||||
.get_nonce_ke = _get_nonce_ke,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.initiator = initiator,
|
||||
.keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Willi
|
||||
* Copyright (C) 2012 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup phase1 phase1
|
||||
* @{ @ingroup ikev1
|
||||
*/
|
||||
|
||||
#ifndef PHASE1_H_
|
||||
#define PHASE1_H_
|
||||
|
||||
typedef struct phase1_t phase1_t;
|
||||
|
||||
#include <sa/ike_sa.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
|
||||
/**
|
||||
* Common phase 1 helper for main and aggressive mode.
|
||||
*/
|
||||
struct phase1_t {
|
||||
|
||||
/**
|
||||
* Create keymat hasher.
|
||||
*
|
||||
* @return TRUE if hasher created
|
||||
*/
|
||||
bool (*create_hasher)(phase1_t *this);
|
||||
|
||||
/**
|
||||
* Create DH object using SA keymat.
|
||||
*
|
||||
* @param group negotiated DH group
|
||||
* @return TRUE if group supported
|
||||
*/
|
||||
bool (*create_dh)(phase1_t *this, diffie_hellman_group_t group);
|
||||
|
||||
/**
|
||||
* Derive key material.
|
||||
*
|
||||
* @param peer_cfg peer config to look up shared key for, or NULL
|
||||
* @param method negotiated authenticated method
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
bool (*derive_keys)(phase1_t *this, peer_cfg_t *peer_cfg,
|
||||
auth_method_t method);
|
||||
/**
|
||||
* Verify a HASH or SIG payload in message.
|
||||
*
|
||||
* @param method negotiated auth method
|
||||
* @param message message containing HASH or SIG payload
|
||||
* @param id_data encoded identity, including protocol/port fields
|
||||
* @return TRUE if verified successfully
|
||||
*/
|
||||
bool (*verify_auth)(phase1_t *this, auth_method_t method,
|
||||
message_t *message, chunk_t id_data);
|
||||
|
||||
/**
|
||||
* Build a HASH or SIG payload and add it to message.
|
||||
*
|
||||
* @param method negotiated auth method
|
||||
* @param message message to add payload to
|
||||
* @param id_data encoded identity, including protocol/port fields
|
||||
* @return TRUE if built successfully
|
||||
*/
|
||||
bool (*build_auth)(phase1_t *this, auth_method_t method,
|
||||
message_t *message, chunk_t id_data);
|
||||
|
||||
/**
|
||||
* Get the IKEv1 authentication method defined by peer config.
|
||||
*
|
||||
* @param peer_cfg peer config to get auth method from
|
||||
* @return auth method, or AUTH_NONE
|
||||
*/
|
||||
auth_method_t (*get_auth_method)(phase1_t *this, peer_cfg_t *peer_cfg);
|
||||
|
||||
/**
|
||||
* Select a peer config as responder.
|
||||
*
|
||||
* @param method used authentication method
|
||||
* @param aggressive TRUE to get an aggressive mode config
|
||||
* @param id initiator identity
|
||||
* @return selected peer config, NULL if none found
|
||||
*/
|
||||
peer_cfg_t* (*select_config)(phase1_t *this, auth_method_t method,
|
||||
bool aggressive, identification_t *id);
|
||||
|
||||
/**
|
||||
* Get configured identity from peer config.
|
||||
*
|
||||
* @param peer_cfg peer config to get identity from
|
||||
* @param local TRUE to get own identity, FALSE for remote
|
||||
* @return identity, pointing to internal config data
|
||||
*/
|
||||
identification_t* (*get_id)(phase1_t *this, peer_cfg_t *peer_cfg, bool local);
|
||||
|
||||
/**
|
||||
* Extract and store SA payload bytes from encoded message.
|
||||
*
|
||||
* @param message message to extract SA payload bytes from
|
||||
* @return TRUE if SA payload found
|
||||
*/
|
||||
bool (*save_sa_payload)(phase1_t *this, message_t *message);
|
||||
|
||||
/**
|
||||
* Add Nonce and KE payload to message.
|
||||
*
|
||||
* @param message message to add payloads
|
||||
* @return TRUE if payloads added successfully
|
||||
*/
|
||||
bool (*add_nonce_ke)(phase1_t *this, message_t *message);
|
||||
|
||||
/**
|
||||
* Extract Nonce and KE payload from message.
|
||||
*
|
||||
* @param message message to get payloads from
|
||||
* @return TRUE if payloads extracted successfully
|
||||
*/
|
||||
bool (*get_nonce_ke)(phase1_t *this, message_t *message);
|
||||
|
||||
/**
|
||||
* Destroy a phase1_t.
|
||||
*/
|
||||
void (*destroy)(phase1_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a phase1 instance.
|
||||
*
|
||||
* @param ike_sa IKE_SA to set up
|
||||
* @param initiator TRUE if initiating actively
|
||||
* @return Phase 1 helper
|
||||
*/
|
||||
phase1_t *phase1_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** PHASE1_H_ @}*/
|
||||
Executable
+1534
File diff suppressed because it is too large
Load Diff
Executable
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup task_manager_v1 task_manager_v1
|
||||
* @{ @ingroup sa
|
||||
*/
|
||||
|
||||
#ifndef TASK_MANAGER_V1_H_
|
||||
#define TASK_MANAGER_V1_H_
|
||||
|
||||
typedef struct task_manager_v1_t task_manager_v1_t;
|
||||
|
||||
#include <sa/task_manager.h>
|
||||
|
||||
/**
|
||||
* Task manager, IKEv1 variant.
|
||||
*/
|
||||
struct task_manager_v1_t {
|
||||
|
||||
/**
|
||||
* Implements task_manager_t.
|
||||
*/
|
||||
task_manager_t task_manager;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an instance of the task manager.
|
||||
*
|
||||
* @param ike_sa IKE_SA to manage.
|
||||
*/
|
||||
task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa);
|
||||
|
||||
#endif /** TASK_MANAGER_V1_H_ @}*/
|
||||
+657
@@ -0,0 +1,657 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Willi
|
||||
* Copyright (C) 2012 revosec AG
|
||||
*
|
||||
* 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 "aggressive_mode.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev1/phase1.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/id_payload.h>
|
||||
#include <encoding/payloads/hash_payload.h>
|
||||
#include <sa/ikev1/tasks/xauth.h>
|
||||
#include <sa/ikev1/tasks/mode_config.h>
|
||||
#include <sa/ikev1/tasks/informational.h>
|
||||
#include <sa/ikev1/tasks/isakmp_delete.h>
|
||||
#include <processing/jobs/adopt_children_job.h>
|
||||
|
||||
typedef struct private_aggressive_mode_t private_aggressive_mode_t;
|
||||
|
||||
/**
|
||||
* Private members of a aggressive_mode_t task.
|
||||
*/
|
||||
struct private_aggressive_mode_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
aggressive_mode_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* Common phase 1 helper class
|
||||
*/
|
||||
phase1_t *ph1;
|
||||
|
||||
/**
|
||||
* IKE config to establish
|
||||
*/
|
||||
ike_cfg_t *ike_cfg;
|
||||
|
||||
/**
|
||||
* Peer config to use
|
||||
*/
|
||||
peer_cfg_t *peer_cfg;
|
||||
|
||||
/**
|
||||
* selected IKE proposal
|
||||
*/
|
||||
proposal_t *proposal;
|
||||
|
||||
/**
|
||||
* Negotiated SA lifetime
|
||||
*/
|
||||
u_int32_t lifetime;
|
||||
|
||||
/**
|
||||
* Negotiated authentication method
|
||||
*/
|
||||
auth_method_t method;
|
||||
|
||||
/**
|
||||
* Encoded ID payload, without fixed header
|
||||
*/
|
||||
chunk_t id_data;
|
||||
|
||||
/** states of aggressive mode */
|
||||
enum {
|
||||
AM_INIT,
|
||||
AM_AUTH,
|
||||
} state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set IKE_SA to established state
|
||||
*/
|
||||
static bool establish(private_aggressive_mode_t *this)
|
||||
{
|
||||
if (!charon->bus->authorize(charon->bus, TRUE))
|
||||
{
|
||||
DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa),
|
||||
this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_my_id(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
|
||||
charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for notify errors, return TRUE if error found
|
||||
*/
|
||||
static bool has_notify_errors(private_aggressive_mode_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
bool err = FALSE;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == NOTIFY_V1)
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
notify_type_t type;
|
||||
|
||||
notify = (notify_payload_t*)payload;
|
||||
type = notify->get_notify_type(notify);
|
||||
if (type < 16384)
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N error notify",
|
||||
notify_type_names, type);
|
||||
err = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N notify", notify_type_names, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a task sending a notify in an INFORMATIONAL exchange
|
||||
*/
|
||||
static status_t send_notify(private_aggressive_mode_t *this, notify_type_t type)
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
u_int64_t spi_i, spi_r;
|
||||
chunk_t spi;
|
||||
|
||||
notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1,
|
||||
PROTO_IKE, type);
|
||||
ike_sa_id = this->ike_sa->get_id(this->ike_sa);
|
||||
spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
|
||||
spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
|
||||
spi = chunk_cata("cc", chunk_from_thing(spi_i), chunk_from_thing(spi_r));
|
||||
notify->set_spi_data(notify, spi);
|
||||
|
||||
this->ike_sa->queue_task(this->ike_sa,
|
||||
(task_t*)informational_create(this->ike_sa, notify));
|
||||
/* cancel all active/passive tasks in favour of informational */
|
||||
return ALREADY_DONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a delete task if authentication failed as initiator
|
||||
*/
|
||||
static status_t send_delete(private_aggressive_mode_t *this)
|
||||
{
|
||||
this->ike_sa->queue_task(this->ike_sa,
|
||||
(task_t*)isakmp_delete_create(this->ike_sa, TRUE));
|
||||
/* cancel all active tasks in favour of informational */
|
||||
return ALREADY_DONE;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_aggressive_mode_t *this, message_t *message)
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case AM_INIT:
|
||||
{
|
||||
sa_payload_t *sa_payload;
|
||||
id_payload_t *id_payload;
|
||||
linked_list_t *proposals;
|
||||
identification_t *id;
|
||||
packet_t *packet;
|
||||
u_int16_t group;
|
||||
|
||||
DBG0(DBG_IKE, "initiating Aggressive Mode IKE_SA %s[%d] to %H",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa));
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
|
||||
|
||||
this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
this->peer_cfg->get_ref(this->peer_cfg);
|
||||
|
||||
this->method = this->ph1->get_auth_method(this->ph1, this->peer_cfg);
|
||||
if (this->method == AUTH_NONE)
|
||||
{
|
||||
DBG1(DBG_CFG, "configuration uses unsupported authentication");
|
||||
return FAILED;
|
||||
}
|
||||
this->lifetime = this->peer_cfg->get_reauth_time(this->peer_cfg,
|
||||
FALSE);
|
||||
if (!this->lifetime)
|
||||
{ /* fall back to rekey time of no rekey time configured */
|
||||
this->lifetime = this->peer_cfg->get_rekey_time(this->peer_cfg,
|
||||
FALSE);
|
||||
}
|
||||
this->lifetime += this->peer_cfg->get_over_time(this->peer_cfg);
|
||||
proposals = this->ike_cfg->get_proposals(this->ike_cfg);
|
||||
sa_payload = sa_payload_create_from_proposals_v1(proposals,
|
||||
this->lifetime, 0, this->method, MODE_NONE, FALSE);
|
||||
proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
|
||||
|
||||
message->add_payload(message, &sa_payload->payload_interface);
|
||||
|
||||
group = this->ike_cfg->get_dh_group(this->ike_cfg);
|
||||
if (group == MODP_NONE)
|
||||
{
|
||||
DBG1(DBG_IKE, "DH group selection failed");
|
||||
return FAILED;
|
||||
}
|
||||
if (!this->ph1->create_dh(this->ph1, group))
|
||||
{
|
||||
DBG1(DBG_IKE, "DH group %N not supported",
|
||||
diffie_hellman_group_names, group);
|
||||
return FAILED;
|
||||
}
|
||||
if (!this->ph1->add_nonce_ke(this->ph1, message))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE);
|
||||
if (!id)
|
||||
{
|
||||
DBG1(DBG_CFG, "own identity not known");
|
||||
return FAILED;
|
||||
}
|
||||
this->ike_sa->set_my_id(this->ike_sa, id->clone(id));
|
||||
id_payload = id_payload_create_from_identification(ID_V1, id);
|
||||
this->id_data = id_payload->get_encoded(id_payload);
|
||||
message->add_payload(message, &id_payload->payload_interface);
|
||||
|
||||
/* pregenerate message to store SA payload */
|
||||
if (this->ike_sa->generate_message(this->ike_sa, message,
|
||||
&packet) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "pregenerating SA payload failed");
|
||||
return FAILED;
|
||||
}
|
||||
packet->destroy(packet);
|
||||
if (!this->ph1->save_sa_payload(this->ph1, message))
|
||||
{
|
||||
DBG1(DBG_IKE, "SA payload invalid");
|
||||
return FAILED;
|
||||
}
|
||||
this->state = AM_AUTH;
|
||||
return NEED_MORE;
|
||||
}
|
||||
case AM_AUTH:
|
||||
{
|
||||
if (!this->ph1->build_auth(this->ph1, this->method, message,
|
||||
this->id_data))
|
||||
{
|
||||
this->id_data = chunk_empty;
|
||||
return send_notify(this, AUTHENTICATION_FAILED);
|
||||
}
|
||||
this->id_data = chunk_empty;
|
||||
|
||||
switch (this->method)
|
||||
{
|
||||
case AUTH_XAUTH_INIT_PSK:
|
||||
case AUTH_XAUTH_INIT_RSA:
|
||||
case AUTH_HYBRID_INIT_RSA:
|
||||
/* wait for XAUTH request */
|
||||
break;
|
||||
case AUTH_XAUTH_RESP_PSK:
|
||||
case AUTH_XAUTH_RESP_RSA:
|
||||
case AUTH_HYBRID_RESP_RSA:
|
||||
/* TODO-IKEv1: not yet */
|
||||
return FAILED;
|
||||
default:
|
||||
if (!establish(this))
|
||||
{
|
||||
return send_notify(this, AUTHENTICATION_FAILED);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this->peer_cfg->get_virtual_ip(this->peer_cfg))
|
||||
{
|
||||
this->ike_sa->queue_task(this->ike_sa,
|
||||
(task_t*)mode_config_create(this->ike_sa, TRUE));
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_aggressive_mode_t *this, message_t *message)
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case AM_INIT:
|
||||
{
|
||||
sa_payload_t *sa_payload;
|
||||
id_payload_t *id_payload;
|
||||
identification_t *id;
|
||||
linked_list_t *list;
|
||||
u_int16_t group;
|
||||
|
||||
this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
DBG0(DBG_IKE, "%H is initiating a Aggressive Mode IKE_SA",
|
||||
message->get_source(message));
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
|
||||
|
||||
this->ike_sa->update_hosts(this->ike_sa,
|
||||
message->get_destination(message),
|
||||
message->get_source(message), TRUE);
|
||||
|
||||
sa_payload = (sa_payload_t*)message->get_payload(message,
|
||||
SECURITY_ASSOCIATION_V1);
|
||||
if (!sa_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "SA payload missing");
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
if (!this->ph1->save_sa_payload(this->ph1, message))
|
||||
{
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
|
||||
list = sa_payload->get_proposals(sa_payload);
|
||||
this->proposal = this->ike_cfg->select_proposal(this->ike_cfg,
|
||||
list, FALSE);
|
||||
list->destroy_offset(list, offsetof(proposal_t, destroy));
|
||||
if (!this->proposal)
|
||||
{
|
||||
DBG1(DBG_IKE, "no proposal found");
|
||||
return send_notify(this, NO_PROPOSAL_CHOSEN);
|
||||
}
|
||||
this->ike_sa->set_proposal(this->ike_sa, this->proposal);
|
||||
|
||||
this->method = sa_payload->get_auth_method(sa_payload);
|
||||
this->lifetime = sa_payload->get_lifetime(sa_payload);
|
||||
|
||||
if (!this->proposal->get_algorithm(this->proposal,
|
||||
DIFFIE_HELLMAN_GROUP, &group, NULL))
|
||||
{
|
||||
DBG1(DBG_IKE, "DH group selection failed");
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
if (!this->ph1->create_dh(this->ph1, group))
|
||||
{
|
||||
DBG1(DBG_IKE, "negotiated DH group not supported");
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
if (!this->ph1->get_nonce_ke(this->ph1, message))
|
||||
{
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
|
||||
id_payload = (id_payload_t*)message->get_payload(message, ID_V1);
|
||||
if (!id_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "IDii payload missing");
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
|
||||
id = id_payload->get_identification(id_payload);
|
||||
this->id_data = id_payload->get_encoded(id_payload);
|
||||
this->ike_sa->set_other_id(this->ike_sa, id);
|
||||
this->peer_cfg = this->ph1->select_config(this->ph1,
|
||||
this->method, TRUE, id);
|
||||
if (!this->peer_cfg)
|
||||
{
|
||||
DBG1(DBG_IKE, "no peer config found");
|
||||
return send_notify(this, AUTHENTICATION_FAILED);
|
||||
}
|
||||
this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg);
|
||||
|
||||
this->state = AM_AUTH;
|
||||
if (has_notify_errors(this, message))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
case AM_AUTH:
|
||||
{
|
||||
if (!this->ph1->verify_auth(this->ph1, this->method, message,
|
||||
this->id_data))
|
||||
{
|
||||
this->id_data = chunk_empty;
|
||||
return send_delete(this);
|
||||
}
|
||||
this->id_data = chunk_empty;
|
||||
|
||||
if (!charon->bus->authorize(charon->bus, FALSE))
|
||||
{
|
||||
DBG1(DBG_IKE, "Aggressive Mode authorization hook forbids "
|
||||
"IKE_SA, cancelling");
|
||||
return send_delete(this);
|
||||
}
|
||||
|
||||
switch (this->method)
|
||||
{
|
||||
case AUTH_XAUTH_INIT_PSK:
|
||||
case AUTH_XAUTH_INIT_RSA:
|
||||
case AUTH_HYBRID_INIT_RSA:
|
||||
this->ike_sa->queue_task(this->ike_sa,
|
||||
(task_t*)xauth_create(this->ike_sa, TRUE));
|
||||
return SUCCESS;
|
||||
case AUTH_XAUTH_RESP_PSK:
|
||||
case AUTH_XAUTH_RESP_RSA:
|
||||
case AUTH_HYBRID_RESP_RSA:
|
||||
/* TODO-IKEv1: not yet supported */
|
||||
return FAILED;
|
||||
default:
|
||||
if (!establish(this))
|
||||
{
|
||||
return send_delete(this);
|
||||
}
|
||||
lib->processor->queue_job(lib->processor, (job_t*)
|
||||
adopt_children_job_create(
|
||||
this->ike_sa->get_id(this->ike_sa)));
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_aggressive_mode_t *this, message_t *message)
|
||||
{
|
||||
if (this->state == AM_AUTH)
|
||||
{
|
||||
sa_payload_t *sa_payload;
|
||||
id_payload_t *id_payload;
|
||||
identification_t *id;
|
||||
|
||||
sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
|
||||
this->lifetime, 0, this->method, MODE_NONE, FALSE);
|
||||
message->add_payload(message, &sa_payload->payload_interface);
|
||||
|
||||
if (!this->ph1->add_nonce_ke(this->ph1, message))
|
||||
{
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
if (!this->ph1->create_hasher(this->ph1))
|
||||
{
|
||||
return send_notify(this, NO_PROPOSAL_CHOSEN);
|
||||
}
|
||||
if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method))
|
||||
{
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
|
||||
id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE);
|
||||
if (!id)
|
||||
{
|
||||
DBG1(DBG_CFG, "own identity not known");
|
||||
return send_notify(this, INVALID_ID_INFORMATION);
|
||||
}
|
||||
this->ike_sa->set_my_id(this->ike_sa, id->clone(id));
|
||||
|
||||
id_payload = id_payload_create_from_identification(ID_V1, id);
|
||||
message->add_payload(message, &id_payload->payload_interface);
|
||||
|
||||
if (!this->ph1->build_auth(this->ph1, this->method, message,
|
||||
id_payload->get_encoded(id_payload)))
|
||||
{
|
||||
return send_notify(this, AUTHENTICATION_FAILED);
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_aggressive_mode_t *this, message_t *message)
|
||||
{
|
||||
if (this->state == AM_AUTH)
|
||||
{
|
||||
auth_method_t method;
|
||||
sa_payload_t *sa_payload;
|
||||
id_payload_t *id_payload;
|
||||
identification_t *id, *cid;
|
||||
linked_list_t *list;
|
||||
u_int32_t lifetime;
|
||||
|
||||
sa_payload = (sa_payload_t*)message->get_payload(message,
|
||||
SECURITY_ASSOCIATION_V1);
|
||||
if (!sa_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "SA payload missing");
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
list = sa_payload->get_proposals(sa_payload);
|
||||
this->proposal = this->ike_cfg->select_proposal(this->ike_cfg,
|
||||
list, FALSE);
|
||||
list->destroy_offset(list, offsetof(proposal_t, destroy));
|
||||
if (!this->proposal)
|
||||
{
|
||||
DBG1(DBG_IKE, "no proposal found");
|
||||
return send_notify(this, NO_PROPOSAL_CHOSEN);
|
||||
}
|
||||
this->ike_sa->set_proposal(this->ike_sa, this->proposal);
|
||||
|
||||
lifetime = sa_payload->get_lifetime(sa_payload);
|
||||
if (lifetime != this->lifetime)
|
||||
{
|
||||
DBG1(DBG_IKE, "received lifetime %us does not match configured "
|
||||
"lifetime %us", lifetime, this->lifetime);
|
||||
}
|
||||
this->lifetime = lifetime;
|
||||
method = sa_payload->get_auth_method(sa_payload);
|
||||
if (method != this->method)
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N authentication, but configured %N, "
|
||||
"continue with configured", auth_method_names, method,
|
||||
auth_method_names, this->method);
|
||||
}
|
||||
if (!this->ph1->get_nonce_ke(this->ph1, message))
|
||||
{
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
if (!this->ph1->create_hasher(this->ph1))
|
||||
{
|
||||
return send_notify(this, NO_PROPOSAL_CHOSEN);
|
||||
}
|
||||
if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method))
|
||||
{
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
|
||||
id_payload = (id_payload_t*)message->get_payload(message, ID_V1);
|
||||
if (!id_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "IDir payload missing");
|
||||
return send_delete(this);
|
||||
}
|
||||
id = id_payload->get_identification(id_payload);
|
||||
cid = this->ph1->get_id(this->ph1, this->peer_cfg, FALSE);
|
||||
if (cid && !id->matches(id, cid))
|
||||
{
|
||||
DBG1(DBG_IKE, "IDir '%Y' does not match to '%Y'", id, cid);
|
||||
id->destroy(id);
|
||||
return send_notify(this, INVALID_ID_INFORMATION);
|
||||
}
|
||||
this->ike_sa->set_other_id(this->ike_sa, id);
|
||||
|
||||
if (!this->ph1->verify_auth(this->ph1, this->method, message,
|
||||
id_payload->get_encoded(id_payload)))
|
||||
{
|
||||
return send_notify(this, AUTHENTICATION_FAILED);
|
||||
}
|
||||
if (!charon->bus->authorize(charon->bus, FALSE))
|
||||
{
|
||||
DBG1(DBG_IKE, "Aggressive Mode authorization hook forbids IKE_SA, "
|
||||
"cancelling");
|
||||
return send_notify(this, AUTHENTICATION_FAILED);
|
||||
}
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_aggressive_mode_t *this)
|
||||
{
|
||||
return TASK_AGGRESSIVE_MODE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_aggressive_mode_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
DESTROY_IF(this->peer_cfg);
|
||||
DESTROY_IF(this->proposal);
|
||||
this->ph1->destroy(this->ph1);
|
||||
chunk_free(&this->id_data);
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->state = AM_INIT;
|
||||
this->peer_cfg = NULL;
|
||||
this->proposal = NULL;
|
||||
this->ph1 = phase1_create(ike_sa, this->initiator);
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_aggressive_mode_t *this)
|
||||
{
|
||||
DESTROY_IF(this->peer_cfg);
|
||||
DESTROY_IF(this->proposal);
|
||||
this->ph1->destroy(this->ph1);
|
||||
chunk_free(&this->id_data);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
aggressive_mode_t *aggressive_mode_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_aggressive_mode_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.ph1 = phase1_create(ike_sa, initiator),
|
||||
.initiator = initiator,
|
||||
.state = AM_INIT,
|
||||
);
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Willi
|
||||
* Copyright (C) 2012 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup aggressive_mode aggressive_mode
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef AGGRESSIVE_MODE_H_
|
||||
#define AGGRESSIVE_MODE_H_
|
||||
|
||||
typedef struct aggressive_mode_t aggressive_mode_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* IKEv1 aggressive mode, establishes an IKE_SA without identity protection.
|
||||
*/
|
||||
struct aggressive_mode_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new AGGRESSIVE_MODE task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if task initiated locally
|
||||
* @return task to handle by the task_manager
|
||||
*/
|
||||
aggressive_mode_t *aggressive_mode_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** AGGRESSIVE_MODE_H_ @}*/
|
||||
Executable
+222
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "informational.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev1/tasks/isakmp_delete.h>
|
||||
#include <sa/ikev1/tasks/quick_delete.h>
|
||||
|
||||
#include <encoding/payloads/delete_payload.h>
|
||||
|
||||
typedef struct private_informational_t private_informational_t;
|
||||
|
||||
/**
|
||||
* Private members of a informational_t task.
|
||||
*/
|
||||
struct private_informational_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
informational_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Notify payload to send
|
||||
*/
|
||||
notify_payload_t *notify;
|
||||
|
||||
/**
|
||||
* Delete subtask
|
||||
*/
|
||||
task_t *del;
|
||||
};
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_informational_t *this, message_t *message)
|
||||
{
|
||||
message->add_payload(message, &this->notify->payload_interface);
|
||||
this->notify = NULL;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_informational_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
delete_payload_t *delete;
|
||||
notify_payload_t *notify;
|
||||
notify_type_t type;
|
||||
payload_t *payload;
|
||||
status_t status = SUCCESS;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case NOTIFY_V1:
|
||||
notify = (notify_payload_t*)payload;
|
||||
type = notify->get_notify_type(notify);
|
||||
|
||||
if (type == INITIAL_CONTACT_IKEV1)
|
||||
{
|
||||
this->ike_sa->set_condition(this->ike_sa,
|
||||
COND_INIT_CONTACT_SEEN, TRUE);
|
||||
}
|
||||
else if (type == UNITY_LOAD_BALANCE)
|
||||
{
|
||||
host_t *redirect, *me;
|
||||
chunk_t data;
|
||||
|
||||
data = notify->get_notification_data(notify);
|
||||
redirect = host_create_from_chunk(AF_INET, data,
|
||||
IKEV2_UDP_PORT);
|
||||
if (redirect)
|
||||
{ /* treat the redirect as reauthentication */
|
||||
DBG1(DBG_IKE, "received %N notify. redirected to %H",
|
||||
notify_type_names, type, redirect);
|
||||
/* Cisco boxes reject the first message from 4500 */
|
||||
me = this->ike_sa->get_my_host(this->ike_sa);
|
||||
me->set_port(me, IKEV2_UDP_PORT);
|
||||
this->ike_sa->set_other_host(this->ike_sa, redirect);
|
||||
this->ike_sa->reauth(this->ike_sa);
|
||||
enumerator->destroy(enumerator);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N notify, invalid address");
|
||||
}
|
||||
}
|
||||
else if (type < 16384)
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N error notify",
|
||||
notify_type_names, type);
|
||||
if (this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING)
|
||||
{ /* only critical during main mode */
|
||||
status = FAILED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N notify",
|
||||
notify_type_names, type);
|
||||
}
|
||||
continue;
|
||||
case DELETE_V1:
|
||||
if (!this->del)
|
||||
{
|
||||
delete = (delete_payload_t*)payload;
|
||||
if (delete->get_protocol_id(delete) == PROTO_IKE)
|
||||
{
|
||||
this->del = (task_t*)isakmp_delete_create(this->ike_sa,
|
||||
FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->del = (task_t*)quick_delete_create(this->ike_sa,
|
||||
PROTO_NONE, 0, FALSE, FALSE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
if (this->del && status == SUCCESS)
|
||||
{
|
||||
return this->del->process(this->del, message);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_informational_t *this, message_t *message)
|
||||
{
|
||||
if (this->del)
|
||||
{
|
||||
return this->del->build(this->del, message);
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_informational_t *this, message_t *message)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_informational_t *this)
|
||||
{
|
||||
return TASK_INFORMATIONAL;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_informational_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_informational_t *this)
|
||||
{
|
||||
DESTROY_IF(this->notify);
|
||||
DESTROY_IF(this->del);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify)
|
||||
{
|
||||
private_informational_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.notify = notify,
|
||||
);
|
||||
|
||||
if (notify)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup informational informational
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef INFORMATIONAL_H_
|
||||
#define INFORMATIONAL_H_
|
||||
|
||||
typedef struct informational_t informational_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
|
||||
/**
|
||||
* IKEv1 informational exchange, negotiates errors.
|
||||
*/
|
||||
struct informational_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new informational task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param notify notify to send as initiator, NULL if responder
|
||||
* @return task to handle by the task_manager
|
||||
*/
|
||||
informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify);
|
||||
|
||||
#endif /** INFORMATIONAL_H_ @}*/
|
||||
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "isakmp_cert_post.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <encoding/payloads/cert_payload.h>
|
||||
#include <encoding/payloads/certreq_payload.h>
|
||||
#include <encoding/payloads/auth_payload.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <credentials/certificates/x509.h>
|
||||
|
||||
|
||||
typedef struct private_isakmp_cert_post_t private_isakmp_cert_post_t;
|
||||
|
||||
/**
|
||||
* Private members of a isakmp_cert_post_t task.
|
||||
*/
|
||||
struct private_isakmp_cert_post_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
isakmp_cert_post_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* States of ike cert pre
|
||||
*/
|
||||
enum {
|
||||
CR_SA,
|
||||
CR_KE,
|
||||
CR_AUTH,
|
||||
} state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if we actually use certificates for authentication
|
||||
*/
|
||||
static bool use_certs(private_isakmp_cert_post_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
bool use = FALSE;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1)
|
||||
{
|
||||
sa_payload_t *sa_payload = (sa_payload_t*)payload;
|
||||
|
||||
switch (sa_payload->get_auth_method(sa_payload))
|
||||
{
|
||||
case AUTH_RSA:
|
||||
case AUTH_ECDSA_256:
|
||||
case AUTH_ECDSA_384:
|
||||
case AUTH_ECDSA_521:
|
||||
case AUTH_XAUTH_INIT_RSA:
|
||||
case AUTH_XAUTH_RESP_RSA:
|
||||
case AUTH_HYBRID_INIT_RSA:
|
||||
case AUTH_HYBRID_RESP_RSA:
|
||||
use = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
return use;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add certificates to message
|
||||
*/
|
||||
static void build_certs(private_isakmp_cert_post_t *this, message_t *message)
|
||||
{
|
||||
peer_cfg_t *peer_cfg;
|
||||
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
if (!peer_cfg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (peer_cfg->get_cert_policy(peer_cfg))
|
||||
{
|
||||
case CERT_NEVER_SEND:
|
||||
break;
|
||||
case CERT_SEND_IF_ASKED:
|
||||
if (!this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN))
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* FALL */
|
||||
case CERT_ALWAYS_SEND:
|
||||
{
|
||||
cert_payload_t *payload;
|
||||
enumerator_t *enumerator;
|
||||
certificate_t *cert;
|
||||
auth_rule_t type;
|
||||
auth_cfg_t *auth;
|
||||
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
|
||||
cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
|
||||
if (!cert)
|
||||
{
|
||||
break;
|
||||
}
|
||||
payload = cert_payload_create_from_cert(CERTIFICATE_V1, cert);
|
||||
if (!payload)
|
||||
{
|
||||
break;
|
||||
}
|
||||
DBG1(DBG_IKE, "sending end entity cert \"%Y\"",
|
||||
cert->get_subject(cert));
|
||||
message->add_payload(message, (payload_t*)payload);
|
||||
|
||||
enumerator = auth->create_enumerator(auth);
|
||||
while (enumerator->enumerate(enumerator, &type, &cert))
|
||||
{
|
||||
if (type == AUTH_RULE_IM_CERT)
|
||||
{
|
||||
payload = cert_payload_create_from_cert(CERTIFICATE_V1, cert);
|
||||
if (payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "sending issuer cert \"%Y\"",
|
||||
cert->get_subject(cert));
|
||||
message->add_payload(message, (payload_t*)payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_isakmp_cert_post_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
if (this->state == CR_AUTH)
|
||||
{
|
||||
build_certs(this, message);
|
||||
return SUCCESS;
|
||||
}
|
||||
return NEED_MORE;
|
||||
case AGGRESSIVE:
|
||||
if (this->state == CR_AUTH)
|
||||
{
|
||||
build_certs(this, message);
|
||||
return SUCCESS;
|
||||
}
|
||||
return NEED_MORE;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_isakmp_cert_post_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
return NEED_MORE;
|
||||
case CR_KE:
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
return NEED_MORE;
|
||||
}
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
return SUCCESS;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_isakmp_cert_post_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
this->state = CR_KE;
|
||||
return NEED_MORE;
|
||||
case CR_KE:
|
||||
this->state = CR_AUTH;
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
build_certs(this, message);
|
||||
return SUCCESS;
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
build_certs(this, message);
|
||||
this->state = CR_AUTH;
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
return SUCCESS;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_isakmp_cert_post_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
this->state = CR_KE;
|
||||
return NEED_MORE;
|
||||
case CR_KE:
|
||||
this->state = CR_AUTH;
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
return SUCCESS;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
{
|
||||
if (this->state == CR_SA)
|
||||
{
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
this->state = CR_AUTH;
|
||||
return NEED_MORE;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_isakmp_cert_post_t *this)
|
||||
{
|
||||
return TASK_ISAKMP_CERT_POST;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_isakmp_cert_post_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
this->state = CR_SA;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_isakmp_cert_post_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
isakmp_cert_post_t *isakmp_cert_post_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_isakmp_cert_post_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.initiator = initiator,
|
||||
.state = CR_SA,
|
||||
);
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.process = _process_i;
|
||||
this->public.task.build = _build_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.process = _process_r;
|
||||
this->public.task.build = _build_r;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup isakmp_cert_post isakmp_cert_post
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef ISAKMP_CERT_POST_H_
|
||||
#define ISAKMP_CERT_POST_H_
|
||||
|
||||
typedef struct isakmp_cert_post_t isakmp_cert_post_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* ISAKMP_CERT_POST, IKEv1 certificate processing after authentication.
|
||||
*/
|
||||
struct isakmp_cert_post_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new isakmp_cert_post task.
|
||||
*
|
||||
* The initiator parameter means the original initiator, not the initiator
|
||||
* of the certificate request.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if task is the original initiator
|
||||
* @return isakmp_cert_post task to handle by the task_manager
|
||||
*/
|
||||
isakmp_cert_post_t *isakmp_cert_post_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** ISAKMP_CERT_POST_H_ @}*/
|
||||
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "isakmp_cert_pre.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <encoding/payloads/cert_payload.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/certreq_payload.h>
|
||||
#include <credentials/certificates/x509.h>
|
||||
|
||||
|
||||
typedef struct private_isakmp_cert_pre_t private_isakmp_cert_pre_t;
|
||||
|
||||
/**
|
||||
* Private members of a isakmp_cert_pre_t task.
|
||||
*/
|
||||
struct private_isakmp_cert_pre_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
isakmp_cert_pre_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* Send certificate requests?
|
||||
*/
|
||||
bool send_req;
|
||||
|
||||
/** next message we expect */
|
||||
enum {
|
||||
CR_SA,
|
||||
CR_KE,
|
||||
CR_AUTH,
|
||||
} state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the CA certificate for a given certreq payload
|
||||
*/
|
||||
static certificate_t* find_certificate(private_isakmp_cert_pre_t *this,
|
||||
certreq_payload_t *certreq)
|
||||
{
|
||||
identification_t *id;
|
||||
certificate_t *cert;
|
||||
|
||||
if (certreq->get_cert_type(certreq) != CERT_X509)
|
||||
{
|
||||
DBG1(DBG_IKE, "%N CERTREQ not supported - ignored",
|
||||
certificate_type_names, certreq->get_cert_type(certreq));
|
||||
return NULL;
|
||||
}
|
||||
id = certreq->get_dn(certreq);
|
||||
if (!id)
|
||||
{
|
||||
DBG1(DBG_IKE, "ignoring certificate request without data",
|
||||
certificate_type_names, certreq->get_cert_type(certreq));
|
||||
return NULL;
|
||||
}
|
||||
cert = lib->credmgr->get_cert(lib->credmgr, CERT_X509, KEY_ANY, id, TRUE);
|
||||
if (cert)
|
||||
{
|
||||
DBG1(DBG_IKE, "received cert request for '%Y'",
|
||||
cert->get_subject(cert));
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "received cert request for unknown ca '%Y'", id);
|
||||
}
|
||||
id->destroy(id);
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
/**
|
||||
* read certificate requests
|
||||
*/
|
||||
static void process_certreqs(private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
auth_cfg_t *auth;
|
||||
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case CERTIFICATE_REQUEST_V1:
|
||||
{
|
||||
certificate_t *cert;
|
||||
|
||||
this->ike_sa->set_condition(this->ike_sa,
|
||||
COND_CERTREQ_SEEN, TRUE);
|
||||
cert = find_certificate(this, (certreq_payload_t*)payload);
|
||||
if (cert)
|
||||
{
|
||||
auth->add(auth, AUTH_RULE_CA_CERT, cert);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Import receuved certificates
|
||||
*/
|
||||
static void process_certs(private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
auth_cfg_t *auth;
|
||||
bool first = TRUE;
|
||||
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == CERTIFICATE_V1)
|
||||
{
|
||||
cert_payload_t *cert_payload;
|
||||
cert_encoding_t encoding;
|
||||
certificate_t *cert;
|
||||
|
||||
cert_payload = (cert_payload_t*)payload;
|
||||
encoding = cert_payload->get_cert_encoding(cert_payload);
|
||||
|
||||
switch (encoding)
|
||||
{
|
||||
case ENC_X509_SIGNATURE:
|
||||
{
|
||||
cert = cert_payload->get_cert(cert_payload);
|
||||
if (cert)
|
||||
{
|
||||
if (first)
|
||||
{ /* the first is an end entity certificate */
|
||||
DBG1(DBG_IKE, "received end entity cert \"%Y\"",
|
||||
cert->get_subject(cert));
|
||||
auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert);
|
||||
first = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "received issuer cert \"%Y\"",
|
||||
cert->get_subject(cert));
|
||||
auth->add(auth, AUTH_HELPER_IM_CERT, cert);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ENC_CRL:
|
||||
cert = cert_payload->get_cert(cert_payload);
|
||||
if (cert)
|
||||
{
|
||||
DBG1(DBG_IKE, "received CRL \"%Y\"",
|
||||
cert->get_subject(cert));
|
||||
auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert);
|
||||
}
|
||||
break;
|
||||
case ENC_PKCS7_WRAPPED_X509:
|
||||
case ENC_PGP:
|
||||
case ENC_DNS_SIGNED_KEY:
|
||||
case ENC_KERBEROS_TOKEN:
|
||||
case ENC_ARL:
|
||||
case ENC_SPKI:
|
||||
case ENC_X509_ATTRIBUTE:
|
||||
case ENC_RAW_RSA_KEY:
|
||||
case ENC_X509_HASH_AND_URL_BUNDLE:
|
||||
case ENC_OCSP_CONTENT:
|
||||
default:
|
||||
DBG1(DBG_ENC, "certificate encoding %N not supported",
|
||||
cert_encoding_names, encoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the subject of a CA certificate a message
|
||||
*/
|
||||
static void add_certreq(private_isakmp_cert_pre_t *this, message_t *message,
|
||||
certificate_t *cert)
|
||||
{
|
||||
if (cert->get_type(cert) == CERT_X509)
|
||||
{
|
||||
x509_t *x509 = (x509_t*)cert;
|
||||
|
||||
if (x509->get_flags(x509) & X509_CA)
|
||||
{
|
||||
DBG1(DBG_IKE, "sending cert request for \"%Y\"",
|
||||
cert->get_subject(cert));
|
||||
message->add_payload(message, (payload_t*)
|
||||
certreq_payload_create_dn(cert->get_subject(cert)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add auth_cfg's CA certificates to the certificate request
|
||||
*/
|
||||
static void add_certreqs(private_isakmp_cert_pre_t *this,
|
||||
auth_cfg_t *auth, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
auth_rule_t type;
|
||||
void *value;
|
||||
|
||||
enumerator = auth->create_enumerator(auth);
|
||||
while (enumerator->enumerate(enumerator, &type, &value))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case AUTH_RULE_CA_CERT:
|
||||
add_certreq(this, message, (certificate_t*)value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build certificate requests
|
||||
*/
|
||||
static void build_certreqs(private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
ike_cfg_t *ike_cfg;
|
||||
peer_cfg_t *peer_cfg;
|
||||
certificate_t *cert;
|
||||
auth_cfg_t *auth;
|
||||
|
||||
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
if (!ike_cfg->send_certreq(ike_cfg))
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* check if we require a specific CA for that peer */
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
if (peer_cfg)
|
||||
{
|
||||
enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
|
||||
if (enumerator->enumerate(enumerator, &auth))
|
||||
{
|
||||
add_certreqs(this, auth, message);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
if (!message->get_payload(message, CERTIFICATE_REQUEST_V1))
|
||||
{
|
||||
/* otherwise add all trusted CA certificates */
|
||||
enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
|
||||
CERT_ANY, KEY_ANY, NULL, TRUE);
|
||||
while (enumerator->enumerate(enumerator, &cert))
|
||||
{
|
||||
add_certreq(this, message, cert);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we actually use certificates for authentication
|
||||
*/
|
||||
static bool use_certs(private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
bool use = FALSE;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1)
|
||||
{
|
||||
sa_payload_t *sa_payload = (sa_payload_t*)payload;
|
||||
|
||||
switch (sa_payload->get_auth_method(sa_payload))
|
||||
{
|
||||
case AUTH_HYBRID_INIT_RSA:
|
||||
case AUTH_HYBRID_RESP_RSA:
|
||||
if (!this->initiator)
|
||||
{
|
||||
this->send_req = FALSE;
|
||||
}
|
||||
/* FALL */
|
||||
case AUTH_RSA:
|
||||
case AUTH_ECDSA_256:
|
||||
case AUTH_ECDSA_384:
|
||||
case AUTH_ECDSA_521:
|
||||
case AUTH_XAUTH_INIT_RSA:
|
||||
case AUTH_XAUTH_RESP_RSA:
|
||||
use = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
return use;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
if (this->state == CR_AUTH)
|
||||
{
|
||||
build_certreqs(this, message);
|
||||
}
|
||||
return NEED_MORE;
|
||||
case AGGRESSIVE:
|
||||
if (this->state == CR_SA)
|
||||
{
|
||||
build_certreqs(this, message);
|
||||
}
|
||||
return NEED_MORE;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
return NEED_MORE;
|
||||
case CR_KE:
|
||||
process_certreqs(this, message);
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
process_certreqs(this, message);
|
||||
process_certs(this, message);
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
process_certreqs(this, message);
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
process_certs(this, message);
|
||||
return SUCCESS;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
this->state = CR_KE;
|
||||
return NEED_MORE;
|
||||
case CR_KE:
|
||||
if (this->send_req)
|
||||
{
|
||||
build_certreqs(this, message);
|
||||
}
|
||||
this->state = CR_AUTH;
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
return NEED_MORE;
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
if (this->send_req)
|
||||
{
|
||||
build_certreqs(this, message);
|
||||
}
|
||||
this->state = CR_AUTH;
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
return SUCCESS;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
this->state = CR_KE;
|
||||
return NEED_MORE;
|
||||
case CR_KE:
|
||||
process_certreqs(this, message);
|
||||
this->state = CR_AUTH;
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
process_certs(this, message);
|
||||
return SUCCESS;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
{
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
process_certreqs(this, message);
|
||||
process_certs(this, message);
|
||||
this->state = CR_AUTH;
|
||||
return SUCCESS;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_isakmp_cert_pre_t *this)
|
||||
{
|
||||
return TASK_ISAKMP_CERT_PRE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_isakmp_cert_pre_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
this->state = CR_SA;
|
||||
this->send_req = TRUE;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_isakmp_cert_pre_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
isakmp_cert_pre_t *isakmp_cert_pre_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_isakmp_cert_pre_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.initiator = initiator,
|
||||
.state = CR_SA,
|
||||
.send_req = TRUE,
|
||||
);
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup isakmp_cert_pre isakmp_cert_pre
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef ISAKMP_CERT_PRE_H_
|
||||
#define ISAKMP_CERT_PRE_H_
|
||||
|
||||
typedef struct isakmp_cert_pre_t isakmp_cert_pre_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* ISAKMP_CERT_PRE task, IKEv1 certificate processing before authentication.
|
||||
*/
|
||||
struct isakmp_cert_pre_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new ISAKMP_CERT_PRE task.
|
||||
*
|
||||
* The initiator parameter means the original initiator, not the initiator
|
||||
* of the certificate request.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if task is the original initiator
|
||||
* @return isakmp_cert_pre task to handle by the task_manager
|
||||
*/
|
||||
isakmp_cert_pre_t *isakmp_cert_pre_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** ISAKMP_CERT_PRE_H_ @}*/
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "isakmp_delete.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/delete_payload.h>
|
||||
|
||||
typedef struct private_isakmp_delete_t private_isakmp_delete_t;
|
||||
|
||||
/**
|
||||
* Private members of a isakmp_delete_t task.
|
||||
*/
|
||||
struct private_isakmp_delete_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
isakmp_delete_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
};
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_isakmp_delete_t *this, message_t *message)
|
||||
{
|
||||
delete_payload_t *delete_payload;
|
||||
ike_sa_id_t *id;
|
||||
|
||||
DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa),
|
||||
this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_my_id(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
|
||||
delete_payload = delete_payload_create(DELETE_V1, PROTO_IKE);
|
||||
id = this->ike_sa->get_id(this->ike_sa);
|
||||
delete_payload->set_ike_spi(delete_payload, id->get_initiator_spi(id),
|
||||
id->get_responder_spi(id));
|
||||
message->add_payload(message, (payload_t*)delete_payload);
|
||||
|
||||
DBG1(DBG_IKE, "sending DELETE for IKE_SA %s[%d]",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa));
|
||||
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
|
||||
charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_isakmp_delete_t *this, message_t *message)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_isakmp_delete_t *this, message_t *message)
|
||||
{
|
||||
DBG1(DBG_IKE, "received DELETE for IKE_SA %s[%d]",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa));
|
||||
DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa),
|
||||
this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_my_id(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
|
||||
charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_isakmp_delete_t *this, message_t *message)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_isakmp_delete_t *this)
|
||||
{
|
||||
return TASK_ISAKMP_DELETE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_isakmp_delete_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_isakmp_delete_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
isakmp_delete_t *isakmp_delete_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_isakmp_delete_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
);
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup isakmp_delete isakmp_delete
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef ISAKMP_DELETE_H_
|
||||
#define ISAKMP_DELETE_H_
|
||||
|
||||
typedef struct isakmp_delete_t isakmp_delete_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type ISAKMP_DELETE, delete an IKEv1 IKE_SA.
|
||||
*/
|
||||
struct isakmp_delete_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new isakmp_delete task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if we initiate the delete
|
||||
* @return isakmp_delete task to handle by the task_manager
|
||||
*/
|
||||
isakmp_delete_t *isakmp_delete_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** ISAKMP_DELETE_H_ @}*/
|
||||
Executable
+153
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "isakmp_dpd.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
|
||||
typedef struct private_isakmp_dpd_t private_isakmp_dpd_t;
|
||||
|
||||
/**
|
||||
* Private members of a isakmp_dpd_t task.
|
||||
*/
|
||||
struct private_isakmp_dpd_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
isakmp_dpd_t public;
|
||||
|
||||
/**
|
||||
* Sequence number.
|
||||
*/
|
||||
u_int32_t seqnr;
|
||||
|
||||
/**
|
||||
* DPD initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* IKE SA we are serving.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
};
|
||||
|
||||
METHOD(task_t, build, status_t,
|
||||
private_isakmp_dpd_t *this, message_t *message)
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
notify_type_t type;
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
u_int64_t spi_i, spi_r;
|
||||
u_int32_t seqnr;
|
||||
chunk_t spi;
|
||||
|
||||
type = this->initiator ? DPD_R_U_THERE : DPD_R_U_THERE_ACK;
|
||||
notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1,
|
||||
PROTO_IKE, type);
|
||||
seqnr = htonl(this->seqnr);
|
||||
ike_sa_id = this->ike_sa->get_id(this->ike_sa);
|
||||
spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
|
||||
spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
|
||||
spi = chunk_cata("cc", chunk_from_thing(spi_i), chunk_from_thing(spi_r));
|
||||
|
||||
notify->set_spi_data(notify, spi);
|
||||
notify->set_notification_data(notify, chunk_from_thing(seqnr));
|
||||
|
||||
message->add_payload(message, (payload_t*)notify);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process, status_t,
|
||||
private_isakmp_dpd_t *this, message_t *message)
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
notify_type_t type;
|
||||
u_int32_t seqnr = 0;
|
||||
chunk_t chunk;
|
||||
|
||||
type = this->initiator ? DPD_R_U_THERE_ACK : DPD_R_U_THERE;
|
||||
notify = message->get_notify(message, type);
|
||||
if (notify)
|
||||
{
|
||||
chunk = notify->get_notification_data(notify);
|
||||
if (chunk.len == 4)
|
||||
{
|
||||
seqnr = untoh32(chunk.ptr);
|
||||
if (seqnr == this->seqnr)
|
||||
{
|
||||
this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
|
||||
time_monotonic(NULL));
|
||||
if (!this->initiator)
|
||||
{ /* queue DPD_ACK */
|
||||
this->ike_sa->queue_task(this->ike_sa,
|
||||
&isakmp_dpd_create(this->ike_sa, FALSE,
|
||||
this->seqnr)->task);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
DBG1(DBG_IKE, "received invalid DPD sequence number %u (expected %u), "
|
||||
"ignored", seqnr, this->seqnr);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_isakmp_dpd_t *this)
|
||||
{
|
||||
return TASK_ISAKMP_DPD;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_isakmp_dpd_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_isakmp_dpd_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
isakmp_dpd_t *isakmp_dpd_create(ike_sa_t *ike_sa, bool initiator,
|
||||
u_int32_t seqnr)
|
||||
{
|
||||
private_isakmp_dpd_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.build = _build,
|
||||
.process = _process,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.seqnr = seqnr,
|
||||
.initiator = initiator,
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Willi
|
||||
* Copyright (C) 2012 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup isakmp_dpd isakmp_dpd
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef ISAKMP_DPD_H_
|
||||
#define ISAKMP_DPD_H_
|
||||
|
||||
typedef struct isakmp_dpd_t isakmp_dpd_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* IKEv1 dead peer detection task.
|
||||
*/
|
||||
struct isakmp_dpd_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new ISAKMP_DPD task.
|
||||
*
|
||||
* @param ike_sa associated IKE_SA
|
||||
* @param initiator TRUE if DPD initiator
|
||||
* @param seqnr DPD sequence number to use/expect
|
||||
* @return ISAKMP_DPD task to handle by the task_manager
|
||||
*/
|
||||
isakmp_dpd_t *isakmp_dpd_create(ike_sa_t *ike_sa, bool initiator,
|
||||
u_int32_t seqnr);
|
||||
|
||||
#endif /** ISAKMP_DPD_H_ @}*/
|
||||
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2011 Tobias Brunner,
|
||||
* Copyright (C) 2006-2007 Martin Willi
|
||||
* Copyright (C) 2006 Daniel Roethlisberger
|
||||
* 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 "isakmp_natd.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <hydra.h>
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev1/keymat_v1.h>
|
||||
#include <config/peer_cfg.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
#include <encoding/payloads/hash_payload.h>
|
||||
|
||||
typedef struct private_isakmp_natd_t private_isakmp_natd_t;
|
||||
|
||||
/**
|
||||
* Private members of a ike_natt_t task.
|
||||
*/
|
||||
struct private_isakmp_natd_t {
|
||||
|
||||
/**
|
||||
* Public interface.
|
||||
*/
|
||||
isakmp_natd_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* Keymat derivation (from SA)
|
||||
*/
|
||||
keymat_v1_t *keymat;
|
||||
|
||||
/**
|
||||
* Did we process any NAT detection payloads for a source address?
|
||||
*/
|
||||
bool src_seen;
|
||||
|
||||
/**
|
||||
* Did we process any NAT detection payloads for a destination address?
|
||||
*/
|
||||
bool dst_seen;
|
||||
|
||||
/**
|
||||
* Have we found a matching source address NAT hash?
|
||||
*/
|
||||
bool src_matched;
|
||||
|
||||
/**
|
||||
* Have we found a matching destination address NAT hash?
|
||||
*/
|
||||
bool dst_matched;
|
||||
};
|
||||
|
||||
/**
|
||||
* Build NAT detection hash for a host.
|
||||
*/
|
||||
static chunk_t generate_natd_hash(private_isakmp_natd_t *this,
|
||||
ike_sa_id_t *ike_sa_id, host_t *host)
|
||||
{
|
||||
hasher_t *hasher;
|
||||
chunk_t natd_chunk, natd_hash;
|
||||
u_int64_t spi_i, spi_r;
|
||||
u_int16_t port;
|
||||
|
||||
hasher = this->keymat->get_hasher(this->keymat);
|
||||
if (!hasher)
|
||||
{
|
||||
DBG1(DBG_IKE, "no hasher available to build NAT-D payload");
|
||||
return chunk_empty;
|
||||
}
|
||||
|
||||
spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
|
||||
spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
|
||||
port = htons(host->get_port(host));
|
||||
|
||||
/* natd_hash = HASH(CKY-I | CKY-R | IP | Port) */
|
||||
natd_chunk = chunk_cata("cccc", chunk_from_thing(spi_i),
|
||||
chunk_from_thing(spi_r), host->get_address(host),
|
||||
chunk_from_thing(port));
|
||||
hasher->allocate_hash(hasher, natd_chunk, &natd_hash);
|
||||
DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk);
|
||||
DBG3(DBG_IKE, "natd_hash %B", &natd_hash);
|
||||
|
||||
return natd_hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a faked NAT-D payload to enforce UDP encapsulation.
|
||||
*/
|
||||
static chunk_t generate_natd_hash_faked(private_isakmp_natd_t *this)
|
||||
{
|
||||
hasher_t *hasher;
|
||||
chunk_t chunk;
|
||||
rng_t *rng;
|
||||
|
||||
hasher = this->keymat->get_hasher(this->keymat);
|
||||
if (!hasher)
|
||||
{
|
||||
DBG1(DBG_IKE, "no hasher available to build NAT-D payload");
|
||||
return chunk_empty;
|
||||
}
|
||||
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||
if (!rng)
|
||||
{
|
||||
DBG1(DBG_IKE, "unable to get random bytes for NAT-D fake");
|
||||
return chunk_empty;
|
||||
}
|
||||
rng->allocate_bytes(rng, hasher->get_hash_size(hasher), &chunk);
|
||||
rng->destroy(rng);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a NAT-D payload.
|
||||
*/
|
||||
static hash_payload_t *build_natd_payload(private_isakmp_natd_t *this, bool src,
|
||||
host_t *host)
|
||||
{
|
||||
hash_payload_t *payload;
|
||||
ike_cfg_t *config;
|
||||
chunk_t hash;
|
||||
|
||||
config = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
if (src && config->force_encap(config))
|
||||
{
|
||||
hash = generate_natd_hash_faked(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
ike_sa_id_t *ike_sa_id = this->ike_sa->get_id(this->ike_sa);
|
||||
hash = generate_natd_hash(this, ike_sa_id, host);
|
||||
}
|
||||
payload = hash_payload_create(NAT_D_V1);
|
||||
payload->set_hash(payload, hash);
|
||||
chunk_free(&hash);
|
||||
return payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add NAT-D payloads to the message.
|
||||
*/
|
||||
static void add_natd_payloads(private_isakmp_natd_t *this, message_t *message)
|
||||
{
|
||||
hash_payload_t *payload;
|
||||
host_t *host;
|
||||
|
||||
/* destination has to be added first */
|
||||
host = message->get_destination(message);
|
||||
payload = build_natd_payload(this, FALSE, host);
|
||||
message->add_payload(message, (payload_t*)payload);
|
||||
|
||||
/* source is added second, compared with IKEv2 we always know the source,
|
||||
* as these payloads are added in the second Phase 1 exchange or the
|
||||
* response to the first */
|
||||
host = message->get_source(message);
|
||||
payload = build_natd_payload(this, TRUE, host);
|
||||
message->add_payload(message, (payload_t*)payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read NAT-D payloads from message and evaluate them.
|
||||
*/
|
||||
static void process_payloads(private_isakmp_natd_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
hash_payload_t *hash_payload;
|
||||
chunk_t hash, src_hash, dst_hash;
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
host_t *me, *other;
|
||||
ike_cfg_t *config;
|
||||
|
||||
/* precompute hashes for incoming NAT-D comparison */
|
||||
ike_sa_id = message->get_ike_sa_id(message);
|
||||
me = message->get_destination(message);
|
||||
other = message->get_source(message);
|
||||
dst_hash = generate_natd_hash(this, ike_sa_id, me);
|
||||
src_hash = generate_natd_hash(this, ike_sa_id, other);
|
||||
|
||||
DBG3(DBG_IKE, "precalculated src_hash %B", &src_hash);
|
||||
DBG3(DBG_IKE, "precalculated dst_hash %B", &dst_hash);
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) != NAT_D_V1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
hash_payload = (hash_payload_t*)payload;
|
||||
if (!this->dst_seen)
|
||||
{ /* the first NAT-D payload contains the destination hash */
|
||||
this->dst_seen = TRUE;
|
||||
hash = hash_payload->get_hash(hash_payload);
|
||||
DBG3(DBG_IKE, "received dst_hash %B", &hash);
|
||||
if (chunk_equals(hash, dst_hash))
|
||||
{
|
||||
this->dst_matched = TRUE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* the other NAT-D payloads contain source hashes */
|
||||
this->src_seen = TRUE;
|
||||
if (!this->src_matched)
|
||||
{
|
||||
hash = hash_payload->get_hash(hash_payload);
|
||||
DBG3(DBG_IKE, "received src_hash %B", &hash);
|
||||
if (chunk_equals(hash, src_hash))
|
||||
{
|
||||
this->src_matched = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
chunk_free(&src_hash);
|
||||
chunk_free(&dst_hash);
|
||||
|
||||
if (this->src_seen && this->dst_seen)
|
||||
{
|
||||
this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE,
|
||||
!this->dst_matched);
|
||||
this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE,
|
||||
!this->src_matched);
|
||||
config = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
if (this->dst_matched && this->src_matched &&
|
||||
config->force_encap(config))
|
||||
{
|
||||
this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_isakmp_natd_t *this, message_t *message)
|
||||
{
|
||||
status_t result = NEED_MORE;
|
||||
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case AGGRESSIVE:
|
||||
{ /* add NAT-D payloads to the second request, already processed
|
||||
* those by the responder contained in the first response */
|
||||
result = SUCCESS;
|
||||
/* fall */
|
||||
}
|
||||
case ID_PROT:
|
||||
{ /* add NAT-D payloads to the second request, need to process
|
||||
* those by the responder contained in the second response */
|
||||
if (message->get_payload(message, SECURITY_ASSOCIATION_V1))
|
||||
{ /* wait for the second exchange */
|
||||
return NEED_MORE;
|
||||
}
|
||||
add_natd_payloads(this, message);
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_isakmp_natd_t *this, message_t *message)
|
||||
{
|
||||
status_t result = NEED_MORE;
|
||||
|
||||
if (!this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))
|
||||
{ /* we didn't receive VIDs inidcating support for NAT-T */
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
{ /* process NAT-D payloads in the second response, added them in the
|
||||
* second request already, so we're done afterwards */
|
||||
if (message->get_payload(message, SECURITY_ASSOCIATION_V1))
|
||||
{ /* wait for the second exchange */
|
||||
return NEED_MORE;
|
||||
}
|
||||
result = SUCCESS;
|
||||
/* fall */
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
{ /* process NAT-D payloads in the first response, add them in the
|
||||
* following second request */
|
||||
process_payloads(this, message);
|
||||
|
||||
if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
|
||||
{
|
||||
this->ike_sa->float_ports(this->ike_sa);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_isakmp_natd_t *this, message_t *message)
|
||||
{
|
||||
status_t result = NEED_MORE;
|
||||
|
||||
if (!this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))
|
||||
{ /* we didn't receive VIDs indicating NAT-T support */
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case AGGRESSIVE:
|
||||
{ /* proccess NAT-D payloads in the second request, already added ours
|
||||
* in the first response */
|
||||
result = SUCCESS;
|
||||
/* fall */
|
||||
}
|
||||
case ID_PROT:
|
||||
{ /* process NAT-D payloads in the second request, need to add ours
|
||||
* to the second response */
|
||||
if (message->get_payload(message, SECURITY_ASSOCIATION_V1))
|
||||
{ /* wait for the second exchange */
|
||||
return NEED_MORE;
|
||||
}
|
||||
process_payloads(this, message);
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_isakmp_natd_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
{ /* add NAT-D payloads to second response, already processed those
|
||||
* contained in the second request */
|
||||
if (message->get_payload(message, SECURITY_ASSOCIATION_V1))
|
||||
{ /* wait for the second exchange */
|
||||
return NEED_MORE;
|
||||
}
|
||||
add_natd_payloads(this, message);
|
||||
return SUCCESS;
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
{ /* add NAT-D payloads to the first response, process those contained
|
||||
* in the following second request */
|
||||
add_natd_payloads(this, message);
|
||||
return NEED_MORE;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_isakmp_natd_t *this)
|
||||
{
|
||||
return TASK_ISAKMP_NATD;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_isakmp_natd_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
this->keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
|
||||
this->src_seen = FALSE;
|
||||
this->dst_seen = FALSE;
|
||||
this->src_matched = FALSE;
|
||||
this->dst_matched = FALSE;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_isakmp_natd_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
isakmp_natd_t *isakmp_natd_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_isakmp_natd_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
|
||||
.initiator = initiator,
|
||||
);
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Tobias Brunner
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup isakmp_natd isakmp_natd
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef ISAKMP_NATD_H_
|
||||
#define ISAKMP_NATD_H_
|
||||
|
||||
typedef struct isakmp_natd_t isakmp_natd_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type ISAKMP_NATD, detects NAT situation in IKEv1 Phase 1.
|
||||
*/
|
||||
struct isakmp_natd_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new ISAKMP_NATD task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if task is the original initiator
|
||||
* @return isakmp_natd task to handle by the task_manager
|
||||
*/
|
||||
isakmp_natd_t *isakmp_natd_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** ISAKMP_NATD_H_ @}*/
|
||||
Executable
+222
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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 "isakmp_vendor.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/vendor_id_payload.h>
|
||||
|
||||
typedef struct private_isakmp_vendor_t private_isakmp_vendor_t;
|
||||
|
||||
/**
|
||||
* Private data of an isakmp_vendor_t object.
|
||||
*/
|
||||
struct private_isakmp_vendor_t {
|
||||
|
||||
/**
|
||||
* Public isakmp_vendor_t interface.
|
||||
*/
|
||||
isakmp_vendor_t public;
|
||||
|
||||
/**
|
||||
* Associated IKE_SA
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the inititator of this task
|
||||
*/
|
||||
bool initiator;
|
||||
};
|
||||
|
||||
/**
|
||||
* IKEv1 Vendor ID database
|
||||
*/
|
||||
static struct {
|
||||
/* Description */
|
||||
char *desc;
|
||||
/* extension flag negotiated with vendor ID, if any */
|
||||
ike_extension_t extension;
|
||||
/* send yourself? */
|
||||
bool send;
|
||||
/* length of vendor ID string */
|
||||
int len;
|
||||
/* vendor ID string */
|
||||
char *id;
|
||||
} vendor_ids[] = {
|
||||
|
||||
/* strongSwan MD5("strongSwan") */
|
||||
{ "strongSwan", EXT_STRONGSWAN, FALSE, 16,
|
||||
"\x88\x2f\xe5\x6d\x6f\xd2\x0d\xbc\x22\x51\x61\x3b\x2e\xbe\x5b\xeb"},
|
||||
|
||||
/* XAuth, MD5("draft-ietf-ipsra-isakmp-xauth-06.txt") */
|
||||
{ "XAuth", EXT_XAUTH, TRUE, 8,
|
||||
"\x09\x00\x26\x89\xdf\xd6\xb7\x12"},
|
||||
|
||||
/* NAT-Traversal, MD5("RFC 3947") */
|
||||
{ "NAT-T (RFC 3947)", EXT_NATT, TRUE, 16,
|
||||
"\x4a\x13\x1c\x81\x07\x03\x58\x45\x5c\x57\x28\xf2\x0e\x95\x45\x2f"},
|
||||
|
||||
/* Dead peer detection, RFC 3706 */
|
||||
{ "DPD", EXT_DPD, TRUE, 16,
|
||||
"\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00"},
|
||||
|
||||
{ "draft-stenberg-ipsec-nat-traversal-01", 0, FALSE, 16,
|
||||
"\x27\xba\xb5\xdc\x01\xea\x07\x60\xea\x4e\x31\x90\xac\x27\xc0\xd0"},
|
||||
|
||||
{ "draft-stenberg-ipsec-nat-traversal-02", 0, FALSE, 16,
|
||||
"\x61\x05\xc4\x22\xe7\x68\x47\xe4\x3f\x96\x84\x80\x12\x92\xae\xcd"},
|
||||
|
||||
{ "draft-ietf-ipsec-nat-t-ike", 0, FALSE, 16,
|
||||
"\x4d\xf3\x79\x28\xe9\xfc\x4f\xd1\xb3\x26\x21\x70\xd5\x15\xc6\x62"},
|
||||
|
||||
{ "draft-ietf-ipsec-nat-t-ike-00", 0, FALSE, 16,
|
||||
"\x44\x85\x15\x2d\x18\xb6\xbb\xcd\x0b\xe8\xa8\x46\x95\x79\xdd\xcc"},
|
||||
|
||||
{ "draft-ietf-ipsec-nat-t-ike-02", 0, FALSE, 16,
|
||||
"\xcd\x60\x46\x43\x35\xdf\x21\xf8\x7c\xfd\xb2\xfc\x68\xb6\xa4\x48"},
|
||||
|
||||
{ "draft-ietf-ipsec-nat-t-ike-02\\n", 0, FALSE, 16,
|
||||
"\x90\xcb\x80\x91\x3e\xbb\x69\x6e\x08\x63\x81\xb5\xec\x42\x7b\x1f"},
|
||||
|
||||
{ "draft-ietf-ipsec-nat-t-ike-03", 0, FALSE, 16,
|
||||
"\x7d\x94\x19\xa6\x53\x10\xca\x6f\x2c\x17\x9d\x92\x15\x52\x9d\x56"},
|
||||
|
||||
{ "draft-ietf-ipsec-nat-t-ike-04", 0, FALSE, 16,
|
||||
"\x99\x09\xb6\x4e\xed\x93\x7c\x65\x73\xde\x52\xac\xe9\x52\xfa\x6b"},
|
||||
|
||||
{ "draft-ietf-ipsec-nat-t-ike-05", 0, FALSE, 16,
|
||||
"\x80\xd0\xbb\x3d\xef\x54\x56\x5e\xe8\x46\x45\xd4\xc8\x5c\xe3\xee"},
|
||||
|
||||
{ "draft-ietf-ipsec-nat-t-ike-06", 0, FALSE, 16,
|
||||
"\x4d\x1e\x0e\x13\x6d\xea\xfa\x34\xc4\xf3\xea\x9f\x02\xec\x72\x85"},
|
||||
|
||||
{ "draft-ietf-ipsec-nat-t-ike-07", 0, FALSE, 16,
|
||||
"\x43\x9b\x59\xf8\xba\x67\x6c\x4c\x77\x37\xae\x22\xea\xb8\xf5\x82"},
|
||||
|
||||
{ "draft-ietf-ipsec-nat-t-ike-08", 0, FALSE, 16,
|
||||
"\x8f\x8d\x83\x82\x6d\x24\x6b\x6f\xc7\xa8\xa6\xa4\x28\xc1\x1d\xe8"},
|
||||
|
||||
{ "Cisco Unity", 0, FALSE, 16,
|
||||
"\x12\xf5\xf2\x8c\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00"},
|
||||
};
|
||||
|
||||
METHOD(task_t, build, status_t,
|
||||
private_isakmp_vendor_t *this, message_t *message)
|
||||
{
|
||||
vendor_id_payload_t *vid_payload;
|
||||
bool strongswan;
|
||||
int i;
|
||||
|
||||
strongswan = lib->settings->get_bool(lib->settings,
|
||||
"charon.send_vendor_id", FALSE);
|
||||
for (i = 0; i < countof(vendor_ids); i++)
|
||||
{
|
||||
if (vendor_ids[i].send ||
|
||||
(vendor_ids[i].extension == EXT_STRONGSWAN && strongswan))
|
||||
{
|
||||
vid_payload = vendor_id_payload_create_data(VENDOR_ID_V1,
|
||||
chunk_clone(chunk_create(vendor_ids[i].id, vendor_ids[i].len)));
|
||||
message->add_payload(message, &vid_payload->payload_interface);
|
||||
}
|
||||
}
|
||||
return this->initiator ? NEED_MORE : SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process, status_t,
|
||||
private_isakmp_vendor_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
int i;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == VENDOR_ID_V1)
|
||||
{
|
||||
vendor_id_payload_t *vid;
|
||||
bool found = FALSE;
|
||||
chunk_t data;
|
||||
|
||||
vid = (vendor_id_payload_t*)payload;
|
||||
data = vid->get_data(vid);
|
||||
|
||||
for (i = 0; i < countof(vendor_ids); i++)
|
||||
{
|
||||
if (chunk_equals(data, chunk_create(vendor_ids[i].id,
|
||||
vendor_ids[i].len)))
|
||||
{
|
||||
DBG1(DBG_IKE, "received %s vendor id", vendor_ids[i].desc);
|
||||
if (vendor_ids[i].extension)
|
||||
{
|
||||
this->ike_sa->enable_extension(this->ike_sa,
|
||||
vendor_ids[i].extension);
|
||||
}
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
DBG1(DBG_ENC, "received unknown vendor id: %#B", &data);
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
return this->initiator ? SUCCESS : NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_isakmp_vendor_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_isakmp_vendor_t *this)
|
||||
{
|
||||
return TASK_ISAKMP_VENDOR;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_isakmp_vendor_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
isakmp_vendor_t *isakmp_vendor_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_isakmp_vendor_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.build = _build,
|
||||
.process = _process,
|
||||
.migrate = _migrate,
|
||||
.get_type = _get_type,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.initiator = initiator,
|
||||
.ike_sa = ike_sa,
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup isakmp_vendor isakmp_vendor
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef ISAKMP_VENDOR_H_
|
||||
#define ISAKMP_VENDOR_H_
|
||||
|
||||
typedef struct isakmp_vendor_t isakmp_vendor_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Vendor ID processing task for IKEv1.
|
||||
*/
|
||||
struct isakmp_vendor_t {
|
||||
|
||||
/**
|
||||
* Implements task interface.
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a isakmp_vendor instance.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if task is the original initiator
|
||||
*/
|
||||
isakmp_vendor_t *isakmp_vendor_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** ISAKMP_VENDOR_H_ @}*/
|
||||
Executable
+698
@@ -0,0 +1,698 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Tobias Brunner
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "main_mode.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev1/phase1.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/id_payload.h>
|
||||
#include <encoding/payloads/hash_payload.h>
|
||||
#include <sa/ikev1/tasks/xauth.h>
|
||||
#include <sa/ikev1/tasks/mode_config.h>
|
||||
#include <sa/ikev1/tasks/informational.h>
|
||||
#include <sa/ikev1/tasks/isakmp_delete.h>
|
||||
#include <processing/jobs/adopt_children_job.h>
|
||||
|
||||
typedef struct private_main_mode_t private_main_mode_t;
|
||||
|
||||
/**
|
||||
* Private members of a main_mode_t task.
|
||||
*/
|
||||
struct private_main_mode_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
main_mode_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* Common phase 1 helper class
|
||||
*/
|
||||
phase1_t *ph1;
|
||||
|
||||
/**
|
||||
* IKE config to establish
|
||||
*/
|
||||
ike_cfg_t *ike_cfg;
|
||||
|
||||
/**
|
||||
* Peer config to use
|
||||
*/
|
||||
peer_cfg_t *peer_cfg;
|
||||
|
||||
/**
|
||||
* selected IKE proposal
|
||||
*/
|
||||
proposal_t *proposal;
|
||||
|
||||
/**
|
||||
* Negotiated SA lifetime
|
||||
*/
|
||||
u_int32_t lifetime;
|
||||
|
||||
/**
|
||||
* Negotiated authentication method
|
||||
*/
|
||||
auth_method_t method;
|
||||
|
||||
/** states of main mode */
|
||||
enum {
|
||||
MM_INIT,
|
||||
MM_SA,
|
||||
MM_KE,
|
||||
MM_AUTH,
|
||||
} state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set IKE_SA to established state
|
||||
*/
|
||||
static bool establish(private_main_mode_t *this)
|
||||
{
|
||||
if (!charon->bus->authorize(charon->bus, TRUE))
|
||||
{
|
||||
DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa),
|
||||
this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_my_id(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
|
||||
charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for notify errors, return TRUE if error found
|
||||
*/
|
||||
static bool has_notify_errors(private_main_mode_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
bool err = FALSE;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == NOTIFY_V1)
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
notify_type_t type;
|
||||
|
||||
notify = (notify_payload_t*)payload;
|
||||
type = notify->get_notify_type(notify);
|
||||
if (type < 16384)
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N error notify",
|
||||
notify_type_names, type);
|
||||
err = TRUE;
|
||||
}
|
||||
else if (type == INITIAL_CONTACT_IKEV1)
|
||||
{
|
||||
if (!this->initiator && this->state == MM_AUTH)
|
||||
{
|
||||
/* If authenticated and received INITIAL_CONTACT,
|
||||
* delete any existing IKE_SAs with that peer.
|
||||
* The delete takes place when the SA is checked in due
|
||||
* to other id not known until the 3rd message.*/
|
||||
this->ike_sa->set_condition(this->ike_sa,
|
||||
COND_INIT_CONTACT_SEEN, TRUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N notify", notify_type_names, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a task sending a notify in an INFORMATIONAL exchange
|
||||
*/
|
||||
static status_t send_notify(private_main_mode_t *this, notify_type_t type)
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
u_int64_t spi_i, spi_r;
|
||||
chunk_t spi;
|
||||
|
||||
notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1,
|
||||
PROTO_IKE, type);
|
||||
ike_sa_id = this->ike_sa->get_id(this->ike_sa);
|
||||
spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
|
||||
spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
|
||||
spi = chunk_cata("cc", chunk_from_thing(spi_i), chunk_from_thing(spi_r));
|
||||
notify->set_spi_data(notify, spi);
|
||||
|
||||
this->ike_sa->queue_task(this->ike_sa,
|
||||
(task_t*)informational_create(this->ike_sa, notify));
|
||||
/* cancel all active/passive tasks in favour of informational */
|
||||
return ALREADY_DONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a delete task if authentication failed as initiator
|
||||
*/
|
||||
static status_t send_delete(private_main_mode_t *this)
|
||||
{
|
||||
this->ike_sa->queue_task(this->ike_sa,
|
||||
(task_t*)isakmp_delete_create(this->ike_sa, TRUE));
|
||||
/* cancel all active tasks in favour of informational */
|
||||
return ALREADY_DONE;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_main_mode_t *this, message_t *message)
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case MM_INIT:
|
||||
{
|
||||
sa_payload_t *sa_payload;
|
||||
linked_list_t *proposals;
|
||||
packet_t *packet;
|
||||
|
||||
DBG0(DBG_IKE, "initiating Main Mode IKE_SA %s[%d] to %H",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa));
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
|
||||
|
||||
this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
this->peer_cfg->get_ref(this->peer_cfg);
|
||||
|
||||
this->method = this->ph1->get_auth_method(this->ph1, this->peer_cfg);
|
||||
if (this->method == AUTH_NONE)
|
||||
{
|
||||
DBG1(DBG_CFG, "configuration uses unsupported authentication");
|
||||
return FAILED;
|
||||
}
|
||||
this->lifetime = this->peer_cfg->get_reauth_time(this->peer_cfg,
|
||||
FALSE);
|
||||
if (!this->lifetime)
|
||||
{ /* fall back to rekey time of no rekey time configured */
|
||||
this->lifetime = this->peer_cfg->get_rekey_time(this->peer_cfg,
|
||||
FALSE);
|
||||
}
|
||||
this->lifetime += this->peer_cfg->get_over_time(this->peer_cfg);
|
||||
proposals = this->ike_cfg->get_proposals(this->ike_cfg);
|
||||
sa_payload = sa_payload_create_from_proposals_v1(proposals,
|
||||
this->lifetime, 0, this->method, MODE_NONE, FALSE);
|
||||
proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
|
||||
|
||||
message->add_payload(message, &sa_payload->payload_interface);
|
||||
|
||||
/* pregenerate message to store SA payload */
|
||||
if (this->ike_sa->generate_message(this->ike_sa, message,
|
||||
&packet) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "pregenerating SA payload failed");
|
||||
return FAILED;
|
||||
}
|
||||
packet->destroy(packet);
|
||||
if (!this->ph1->save_sa_payload(this->ph1, message))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
this->state = MM_SA;
|
||||
return NEED_MORE;
|
||||
}
|
||||
case MM_SA:
|
||||
{
|
||||
u_int16_t group;
|
||||
|
||||
if (!this->ph1->create_hasher(this->ph1))
|
||||
{
|
||||
return send_notify(this, NO_PROPOSAL_CHOSEN);
|
||||
}
|
||||
if (!this->proposal->get_algorithm(this->proposal,
|
||||
DIFFIE_HELLMAN_GROUP, &group, NULL))
|
||||
{
|
||||
DBG1(DBG_IKE, "DH group selection failed");
|
||||
return send_notify(this, NO_PROPOSAL_CHOSEN);
|
||||
}
|
||||
if (!this->ph1->create_dh(this->ph1, group))
|
||||
{
|
||||
DBG1(DBG_IKE, "negotiated DH group not supported");
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
if (!this->ph1->add_nonce_ke(this->ph1, message))
|
||||
{
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
this->state = MM_KE;
|
||||
return NEED_MORE;
|
||||
}
|
||||
case MM_KE:
|
||||
{
|
||||
id_payload_t *id_payload;
|
||||
identification_t *id;
|
||||
|
||||
id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE);
|
||||
if (!id)
|
||||
{
|
||||
DBG1(DBG_CFG, "own identity not known");
|
||||
return send_notify(this, INVALID_ID_INFORMATION);
|
||||
}
|
||||
this->ike_sa->set_my_id(this->ike_sa, id->clone(id));
|
||||
id_payload = id_payload_create_from_identification(ID_V1, id);
|
||||
message->add_payload(message, &id_payload->payload_interface);
|
||||
|
||||
if (!this->ph1->build_auth(this->ph1, this->method, message,
|
||||
id_payload->get_encoded(id_payload)))
|
||||
{
|
||||
return send_notify(this, AUTHENTICATION_FAILED);
|
||||
}
|
||||
|
||||
this->state = MM_AUTH;
|
||||
return NEED_MORE;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_main_mode_t *this, message_t *message)
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case MM_INIT:
|
||||
{
|
||||
linked_list_t *list;
|
||||
sa_payload_t *sa_payload;
|
||||
|
||||
this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
DBG0(DBG_IKE, "%H is initiating a Main Mode IKE_SA",
|
||||
message->get_source(message));
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
|
||||
|
||||
this->ike_sa->update_hosts(this->ike_sa,
|
||||
message->get_destination(message),
|
||||
message->get_source(message), TRUE);
|
||||
|
||||
sa_payload = (sa_payload_t*)message->get_payload(message,
|
||||
SECURITY_ASSOCIATION_V1);
|
||||
if (!sa_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "SA payload missing");
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
if (!this->ph1->save_sa_payload(this->ph1, message))
|
||||
{
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
|
||||
list = sa_payload->get_proposals(sa_payload);
|
||||
this->proposal = this->ike_cfg->select_proposal(this->ike_cfg,
|
||||
list, FALSE);
|
||||
list->destroy_offset(list, offsetof(proposal_t, destroy));
|
||||
if (!this->proposal)
|
||||
{
|
||||
DBG1(DBG_IKE, "no proposal found");
|
||||
return send_notify(this, NO_PROPOSAL_CHOSEN);
|
||||
}
|
||||
this->ike_sa->set_proposal(this->ike_sa, this->proposal);
|
||||
|
||||
this->method = sa_payload->get_auth_method(sa_payload);
|
||||
this->lifetime = sa_payload->get_lifetime(sa_payload);
|
||||
|
||||
this->state = MM_SA;
|
||||
return NEED_MORE;
|
||||
}
|
||||
case MM_SA:
|
||||
{
|
||||
u_int16_t group;
|
||||
|
||||
if (!this->ph1->create_hasher(this->ph1))
|
||||
{
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
if (!this->proposal->get_algorithm(this->proposal,
|
||||
DIFFIE_HELLMAN_GROUP, &group, NULL))
|
||||
{
|
||||
DBG1(DBG_IKE, "DH group selection failed");
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
if (!this->ph1->create_dh(this->ph1, group))
|
||||
{
|
||||
DBG1(DBG_IKE, "negotiated DH group not supported");
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
if (!this->ph1->get_nonce_ke(this->ph1, message))
|
||||
{
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
this->state = MM_KE;
|
||||
return NEED_MORE;
|
||||
}
|
||||
case MM_KE:
|
||||
{
|
||||
id_payload_t *id_payload;
|
||||
identification_t *id;
|
||||
|
||||
id_payload = (id_payload_t*)message->get_payload(message, ID_V1);
|
||||
if (!id_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "IDii payload missing");
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
|
||||
id = id_payload->get_identification(id_payload);
|
||||
this->ike_sa->set_other_id(this->ike_sa, id);
|
||||
this->peer_cfg = this->ph1->select_config(this->ph1,
|
||||
this->method, FALSE, id);
|
||||
if (!this->peer_cfg)
|
||||
{
|
||||
DBG1(DBG_IKE, "no peer config found");
|
||||
return send_notify(this, AUTHENTICATION_FAILED);
|
||||
}
|
||||
this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg);
|
||||
|
||||
if (!this->ph1->verify_auth(this->ph1, this->method, message,
|
||||
id_payload->get_encoded(id_payload)))
|
||||
{
|
||||
return send_notify(this, AUTHENTICATION_FAILED);
|
||||
}
|
||||
if (!charon->bus->authorize(charon->bus, FALSE))
|
||||
{
|
||||
DBG1(DBG_IKE, "Main Mode authorization hook forbids IKE_SA, "
|
||||
"cancelling");
|
||||
return send_notify(this, AUTHENTICATION_FAILED);
|
||||
}
|
||||
|
||||
this->state = MM_AUTH;
|
||||
if (has_notify_errors(this, message))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_main_mode_t *this, message_t *message)
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case MM_SA:
|
||||
{
|
||||
sa_payload_t *sa_payload;
|
||||
|
||||
sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
|
||||
this->lifetime, 0, this->method, MODE_NONE, FALSE);
|
||||
message->add_payload(message, &sa_payload->payload_interface);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
case MM_KE:
|
||||
{
|
||||
if (!this->ph1->add_nonce_ke(this->ph1, message))
|
||||
{
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method))
|
||||
{
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
case MM_AUTH:
|
||||
{
|
||||
id_payload_t *id_payload;
|
||||
identification_t *id;
|
||||
|
||||
id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE);
|
||||
if (!id)
|
||||
{
|
||||
DBG1(DBG_CFG, "own identity not known");
|
||||
return send_notify(this, INVALID_ID_INFORMATION);
|
||||
}
|
||||
this->ike_sa->set_my_id(this->ike_sa, id->clone(id));
|
||||
|
||||
id_payload = id_payload_create_from_identification(ID_V1, id);
|
||||
message->add_payload(message, &id_payload->payload_interface);
|
||||
|
||||
if (!this->ph1->build_auth(this->ph1, this->method, message,
|
||||
id_payload->get_encoded(id_payload)))
|
||||
{
|
||||
return send_notify(this, AUTHENTICATION_FAILED);
|
||||
}
|
||||
|
||||
switch (this->method)
|
||||
{
|
||||
case AUTH_XAUTH_INIT_PSK:
|
||||
case AUTH_XAUTH_INIT_RSA:
|
||||
case AUTH_HYBRID_INIT_RSA:
|
||||
this->ike_sa->queue_task(this->ike_sa,
|
||||
(task_t*)xauth_create(this->ike_sa, TRUE));
|
||||
return SUCCESS;
|
||||
case AUTH_XAUTH_RESP_PSK:
|
||||
case AUTH_XAUTH_RESP_RSA:
|
||||
case AUTH_HYBRID_RESP_RSA:
|
||||
/* TODO-IKEv1: not yet supported */
|
||||
return FAILED;
|
||||
default:
|
||||
if (!establish(this))
|
||||
{
|
||||
return send_notify(this, AUTHENTICATION_FAILED);
|
||||
}
|
||||
lib->processor->queue_job(lib->processor, (job_t*)
|
||||
adopt_children_job_create(
|
||||
this->ike_sa->get_id(this->ike_sa)));
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_main_mode_t *this, message_t *message)
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case MM_SA:
|
||||
{
|
||||
linked_list_t *list;
|
||||
sa_payload_t *sa_payload;
|
||||
auth_method_t method;
|
||||
u_int32_t lifetime;
|
||||
|
||||
sa_payload = (sa_payload_t*)message->get_payload(message,
|
||||
SECURITY_ASSOCIATION_V1);
|
||||
if (!sa_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "SA payload missing");
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
list = sa_payload->get_proposals(sa_payload);
|
||||
this->proposal = this->ike_cfg->select_proposal(this->ike_cfg,
|
||||
list, FALSE);
|
||||
list->destroy_offset(list, offsetof(proposal_t, destroy));
|
||||
if (!this->proposal)
|
||||
{
|
||||
DBG1(DBG_IKE, "no proposal found");
|
||||
return send_notify(this, NO_PROPOSAL_CHOSEN);
|
||||
}
|
||||
this->ike_sa->set_proposal(this->ike_sa, this->proposal);
|
||||
|
||||
lifetime = sa_payload->get_lifetime(sa_payload);
|
||||
if (lifetime != this->lifetime)
|
||||
{
|
||||
DBG1(DBG_IKE, "received lifetime %us does not match configured "
|
||||
"lifetime %us", lifetime, this->lifetime);
|
||||
}
|
||||
this->lifetime = lifetime;
|
||||
method = sa_payload->get_auth_method(sa_payload);
|
||||
if (method != this->method)
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N authentication, but configured %N, "
|
||||
"continue with configured", auth_method_names, method,
|
||||
auth_method_names, this->method);
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
case MM_KE:
|
||||
{
|
||||
if (!this->ph1->get_nonce_ke(this->ph1, message))
|
||||
{
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method))
|
||||
{
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
case MM_AUTH:
|
||||
{
|
||||
id_payload_t *id_payload;
|
||||
identification_t *id, *cid;
|
||||
|
||||
id_payload = (id_payload_t*)message->get_payload(message, ID_V1);
|
||||
if (!id_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "IDir payload missing");
|
||||
return send_delete(this);
|
||||
}
|
||||
id = id_payload->get_identification(id_payload);
|
||||
cid = this->ph1->get_id(this->ph1, this->peer_cfg, FALSE);
|
||||
if (cid && !id->matches(id, cid))
|
||||
{
|
||||
DBG1(DBG_IKE, "IDir '%Y' does not match to '%Y'", id, cid);
|
||||
id->destroy(id);
|
||||
return send_delete(this);
|
||||
}
|
||||
this->ike_sa->set_other_id(this->ike_sa, id);
|
||||
|
||||
if (!this->ph1->verify_auth(this->ph1, this->method, message,
|
||||
id_payload->get_encoded(id_payload)))
|
||||
{
|
||||
return send_delete(this);
|
||||
}
|
||||
if (!charon->bus->authorize(charon->bus, FALSE))
|
||||
{
|
||||
DBG1(DBG_IKE, "Main Mode authorization hook forbids IKE_SA, "
|
||||
"cancelling");
|
||||
return send_delete(this);
|
||||
}
|
||||
switch (this->method)
|
||||
{
|
||||
case AUTH_XAUTH_INIT_PSK:
|
||||
case AUTH_XAUTH_INIT_RSA:
|
||||
case AUTH_HYBRID_INIT_RSA:
|
||||
/* wait for XAUTH request */
|
||||
break;
|
||||
case AUTH_XAUTH_RESP_PSK:
|
||||
case AUTH_XAUTH_RESP_RSA:
|
||||
case AUTH_HYBRID_RESP_RSA:
|
||||
/* TODO-IKEv1: not yet */
|
||||
return FAILED;
|
||||
default:
|
||||
if (!establish(this))
|
||||
{
|
||||
return send_delete(this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this->peer_cfg->get_virtual_ip(this->peer_cfg))
|
||||
{
|
||||
this->ike_sa->queue_task(this->ike_sa,
|
||||
(task_t*)mode_config_create(this->ike_sa, TRUE));
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_main_mode_t *this)
|
||||
{
|
||||
return TASK_MAIN_MODE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_main_mode_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
DESTROY_IF(this->peer_cfg);
|
||||
DESTROY_IF(this->proposal);
|
||||
this->ph1->destroy(this->ph1);
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->state = MM_INIT;
|
||||
this->peer_cfg = NULL;
|
||||
this->proposal = NULL;
|
||||
this->ph1 = phase1_create(ike_sa, this->initiator);
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_main_mode_t *this)
|
||||
{
|
||||
DESTROY_IF(this->peer_cfg);
|
||||
DESTROY_IF(this->proposal);
|
||||
this->ph1->destroy(this->ph1);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
main_mode_t *main_mode_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_main_mode_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.ph1 = phase1_create(ike_sa, initiator),
|
||||
.initiator = initiator,
|
||||
.state = MM_INIT,
|
||||
);
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup main_mode main_mode
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef MAIN_MODE_H_
|
||||
#define MAIN_MODE_H_
|
||||
|
||||
typedef struct main_mode_t main_mode_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* IKEv1 main mode, establishes a mainmode including authentication.
|
||||
*/
|
||||
struct main_mode_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new main_mode task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if task initiated locally
|
||||
* @return task to handle by the task_manager
|
||||
*/
|
||||
main_mode_t *main_mode_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** MAIN_MODE_H_ @}*/
|
||||
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "mode_config.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <hydra.h>
|
||||
#include <encoding/payloads/cp_payload.h>
|
||||
|
||||
typedef struct private_mode_config_t private_mode_config_t;
|
||||
|
||||
/**
|
||||
* Private members of a mode_config_t task.
|
||||
*/
|
||||
struct private_mode_config_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
mode_config_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* virtual ip
|
||||
*/
|
||||
host_t *virtual_ip;
|
||||
|
||||
/**
|
||||
* list of attributes requested and its handler, entry_t
|
||||
*/
|
||||
linked_list_t *requested;
|
||||
|
||||
/**
|
||||
* Identifier to include in response
|
||||
*/
|
||||
u_int16_t identifier;
|
||||
};
|
||||
|
||||
/**
|
||||
* Entry for a requested attribute and the requesting handler
|
||||
*/
|
||||
typedef struct {
|
||||
/** attribute requested */
|
||||
configuration_attribute_type_t type;
|
||||
/** handler requesting this attribute */
|
||||
attribute_handler_t *handler;
|
||||
} entry_t;
|
||||
|
||||
/**
|
||||
* build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip
|
||||
*/
|
||||
static configuration_attribute_t *build_vip(host_t *vip)
|
||||
{
|
||||
configuration_attribute_type_t type;
|
||||
chunk_t chunk, prefix;
|
||||
|
||||
if (vip->get_family(vip) == AF_INET)
|
||||
{
|
||||
type = INTERNAL_IP4_ADDRESS;
|
||||
if (vip->is_anyaddr(vip))
|
||||
{
|
||||
chunk = chunk_empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
chunk = vip->get_address(vip);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
type = INTERNAL_IP6_ADDRESS;
|
||||
if (vip->is_anyaddr(vip))
|
||||
{
|
||||
chunk = chunk_empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix = chunk_alloca(1);
|
||||
*prefix.ptr = 64;
|
||||
chunk = vip->get_address(vip);
|
||||
chunk = chunk_cata("cc", chunk, prefix);
|
||||
}
|
||||
}
|
||||
return configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1,
|
||||
type, chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a received attribute as initiator
|
||||
*/
|
||||
static void handle_attribute(private_mode_config_t *this,
|
||||
configuration_attribute_t *ca)
|
||||
{
|
||||
attribute_handler_t *handler = NULL;
|
||||
enumerator_t *enumerator;
|
||||
entry_t *entry;
|
||||
|
||||
/* find the handler which requested this attribute */
|
||||
enumerator = this->requested->create_enumerator(this->requested);
|
||||
while (enumerator->enumerate(enumerator, &entry))
|
||||
{
|
||||
if (entry->type == ca->get_type(ca))
|
||||
{
|
||||
handler = entry->handler;
|
||||
this->requested->remove_at(this->requested, enumerator);
|
||||
free(entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
/* and pass it to the handle function */
|
||||
handler = hydra->attributes->handle(hydra->attributes,
|
||||
this->ike_sa->get_other_id(this->ike_sa), handler,
|
||||
ca->get_type(ca), ca->get_chunk(ca));
|
||||
if (handler)
|
||||
{
|
||||
this->ike_sa->add_configuration_attribute(this->ike_sa,
|
||||
handler, ca->get_type(ca), ca->get_chunk(ca));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* process a single configuration attribute
|
||||
*/
|
||||
static void process_attribute(private_mode_config_t *this,
|
||||
configuration_attribute_t *ca)
|
||||
{
|
||||
host_t *ip;
|
||||
chunk_t addr;
|
||||
int family = AF_INET6;
|
||||
|
||||
switch (ca->get_type(ca))
|
||||
{
|
||||
case INTERNAL_IP4_ADDRESS:
|
||||
family = AF_INET;
|
||||
/* fall */
|
||||
case INTERNAL_IP6_ADDRESS:
|
||||
{
|
||||
addr = ca->get_chunk(ca);
|
||||
if (addr.len == 0)
|
||||
{
|
||||
ip = host_create_any(family);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* skip prefix byte in IPv6 payload*/
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
addr.len--;
|
||||
}
|
||||
ip = host_create_from_chunk(family, addr, 0);
|
||||
}
|
||||
if (ip)
|
||||
{
|
||||
DESTROY_IF(this->virtual_ip);
|
||||
this->virtual_ip = ip;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (this->initiator)
|
||||
{
|
||||
handle_attribute(this, ca);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan for configuration payloads and attributes
|
||||
*/
|
||||
static void process_payloads(private_mode_config_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator, *attributes;
|
||||
payload_t *payload;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == CONFIGURATION_V1)
|
||||
{
|
||||
cp_payload_t *cp = (cp_payload_t*)payload;
|
||||
configuration_attribute_t *ca;
|
||||
|
||||
switch (cp->get_type(cp))
|
||||
{
|
||||
case CFG_REQUEST:
|
||||
this->identifier = cp->get_identifier(cp);
|
||||
/* FALL */
|
||||
case CFG_REPLY:
|
||||
attributes = cp->create_attribute_enumerator(cp);
|
||||
while (attributes->enumerate(attributes, &ca))
|
||||
{
|
||||
DBG2(DBG_IKE, "processing %N attribute",
|
||||
configuration_attribute_type_names, ca->get_type(ca));
|
||||
process_attribute(this, ca);
|
||||
}
|
||||
attributes->destroy(attributes);
|
||||
break;
|
||||
default:
|
||||
DBG1(DBG_IKE, "ignoring %N config payload",
|
||||
config_type_names, cp->get_type(cp));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_mode_config_t *this, message_t *message)
|
||||
{
|
||||
cp_payload_t *cp = NULL;
|
||||
enumerator_t *enumerator;
|
||||
attribute_handler_t *handler;
|
||||
peer_cfg_t *config;
|
||||
configuration_attribute_type_t type;
|
||||
chunk_t data;
|
||||
host_t *vip;
|
||||
|
||||
/* reuse virtual IP if we already have one */
|
||||
vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
|
||||
if (!vip)
|
||||
{
|
||||
config = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
vip = config->get_virtual_ip(config);
|
||||
}
|
||||
if (vip)
|
||||
{
|
||||
cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST);
|
||||
cp->add_attribute(cp, build_vip(vip));
|
||||
}
|
||||
|
||||
enumerator = hydra->attributes->create_initiator_enumerator(hydra->attributes,
|
||||
this->ike_sa->get_other_id(this->ike_sa), vip);
|
||||
while (enumerator->enumerate(enumerator, &handler, &type, &data))
|
||||
{
|
||||
configuration_attribute_t *ca;
|
||||
entry_t *entry;
|
||||
|
||||
DBG2(DBG_IKE, "building %N attribute",
|
||||
configuration_attribute_type_names, type);
|
||||
ca = configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1,
|
||||
type, data);
|
||||
if (!cp)
|
||||
{
|
||||
cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST);
|
||||
}
|
||||
cp->add_attribute(cp, ca);
|
||||
|
||||
INIT(entry,
|
||||
.type = type,
|
||||
.handler = handler,
|
||||
);
|
||||
this->requested->insert_last(this->requested, entry);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
if (cp)
|
||||
{
|
||||
message->add_payload(message, (payload_t*)cp);
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_mode_config_t *this, message_t *message)
|
||||
{
|
||||
process_payloads(this, message);
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_mode_config_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
configuration_attribute_type_t type;
|
||||
chunk_t value;
|
||||
host_t *vip = NULL;
|
||||
cp_payload_t *cp = NULL;
|
||||
peer_cfg_t *config;
|
||||
identification_t *id;
|
||||
|
||||
id = this->ike_sa->get_other_eap_id(this->ike_sa);
|
||||
|
||||
config = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
if (this->virtual_ip)
|
||||
{
|
||||
DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
|
||||
if (config->get_pool(config))
|
||||
{
|
||||
vip = hydra->attributes->acquire_address(hydra->attributes,
|
||||
config->get_pool(config), id, this->virtual_ip);
|
||||
}
|
||||
cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
|
||||
if (vip)
|
||||
{
|
||||
DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", vip, id);
|
||||
this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip);
|
||||
cp->add_attribute(cp, build_vip(vip));
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "no virtual IP found, sending empty config payload");
|
||||
}
|
||||
}
|
||||
/* query registered providers for additional attributes to include */
|
||||
enumerator = hydra->attributes->create_responder_enumerator(
|
||||
hydra->attributes, config->get_pool(config), id, vip);
|
||||
while (enumerator->enumerate(enumerator, &type, &value))
|
||||
{
|
||||
if (!cp)
|
||||
{
|
||||
cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
|
||||
}
|
||||
DBG2(DBG_IKE, "building %N attribute",
|
||||
configuration_attribute_type_names, type);
|
||||
cp->add_attribute(cp,
|
||||
configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1,
|
||||
type, value));
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
if (cp)
|
||||
{
|
||||
cp->set_identifier(cp, this->identifier);
|
||||
message->add_payload(message, (payload_t*)cp);
|
||||
}
|
||||
DESTROY_IF(vip);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_mode_config_t *this, message_t *message)
|
||||
{
|
||||
process_payloads(this, message);
|
||||
|
||||
if (this->virtual_ip)
|
||||
{
|
||||
this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_mode_config_t *this)
|
||||
{
|
||||
return TASK_MODE_CONFIG;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_mode_config_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
DESTROY_IF(this->virtual_ip);
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->virtual_ip = NULL;
|
||||
this->requested->destroy_function(this->requested, free);
|
||||
this->requested = linked_list_create();
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_mode_config_t *this)
|
||||
{
|
||||
DESTROY_IF(this->virtual_ip);
|
||||
this->requested->destroy_function(this->requested, free);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_mode_config_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.initiator = initiator,
|
||||
.ike_sa = ike_sa,
|
||||
.requested = linked_list_create(),
|
||||
);
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup mode_config mode_config
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef MODE_CONFIG_H_
|
||||
#define MODE_CONFIG_H_
|
||||
|
||||
typedef struct mode_config_t mode_config_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type TASK_MODE_COFNIG, IKEv1 configuration attribute exchange.
|
||||
*/
|
||||
struct mode_config_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new mode_config task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE for initiator
|
||||
* @return mode_config task to handle by the task_manager
|
||||
*/
|
||||
mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** MODE_CONFIG_H_ @}*/
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "quick_delete.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/delete_payload.h>
|
||||
|
||||
typedef struct private_quick_delete_t private_quick_delete_t;
|
||||
|
||||
/**
|
||||
* Private members of a quick_delete_t task.
|
||||
*/
|
||||
struct private_quick_delete_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
quick_delete_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* Protocol of CHILD_SA to delete
|
||||
*/
|
||||
protocol_id_t protocol;
|
||||
|
||||
/**
|
||||
* Inbound SPI of CHILD_SA to delete
|
||||
*/
|
||||
u_int32_t spi;
|
||||
|
||||
/**
|
||||
* Send delete even if SA does not exist
|
||||
*/
|
||||
bool force;
|
||||
|
||||
/**
|
||||
* SA already expired?
|
||||
*/
|
||||
bool expired;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete the specified CHILD_SA, if found
|
||||
*/
|
||||
static bool delete_child(private_quick_delete_t *this,
|
||||
protocol_id_t protocol, u_int32_t spi)
|
||||
{
|
||||
u_int64_t bytes_in, bytes_out;
|
||||
child_sa_t *child_sa;
|
||||
bool rekeyed;
|
||||
|
||||
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, TRUE);
|
||||
if (!child_sa)
|
||||
{ /* fallback and check for outbound SA */
|
||||
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, FALSE);
|
||||
if (!child_sa)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
this->spi = spi = child_sa->get_spi(child_sa, TRUE);
|
||||
}
|
||||
|
||||
rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYING;
|
||||
child_sa->set_state(child_sa, CHILD_DELETING);
|
||||
|
||||
if (this->expired)
|
||||
{
|
||||
DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
|
||||
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
|
||||
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
|
||||
ntohl(child_sa->get_spi(child_sa, TRUE)),
|
||||
ntohl(child_sa->get_spi(child_sa, FALSE)),
|
||||
child_sa->get_traffic_selectors(child_sa, TRUE),
|
||||
child_sa->get_traffic_selectors(child_sa, FALSE));
|
||||
}
|
||||
else
|
||||
{
|
||||
child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in);
|
||||
child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out);
|
||||
|
||||
DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs "
|
||||
"%.8x_i (%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R",
|
||||
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
|
||||
ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
|
||||
ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
|
||||
child_sa->get_traffic_selectors(child_sa, TRUE),
|
||||
child_sa->get_traffic_selectors(child_sa, FALSE));
|
||||
}
|
||||
|
||||
if (!rekeyed)
|
||||
{
|
||||
charon->bus->child_updown(charon->bus, child_sa, FALSE);
|
||||
}
|
||||
|
||||
this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
|
||||
|
||||
/* TODO-IKEv1: handle close action? */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_quick_delete_t *this, message_t *message)
|
||||
{
|
||||
if (delete_child(this, this->protocol, this->spi) || this->force)
|
||||
{
|
||||
delete_payload_t *delete_payload;
|
||||
|
||||
DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
|
||||
protocol_id_names, this->protocol, ntohl(this->spi));
|
||||
|
||||
delete_payload = delete_payload_create(DELETE_V1, PROTO_ESP);
|
||||
delete_payload->add_spi(delete_payload, this->spi);
|
||||
message->add_payload(message, &delete_payload->payload_interface);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
return ALREADY_DONE;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_quick_delete_t *this, message_t *message)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_quick_delete_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *payloads, *spis;
|
||||
payload_t *payload;
|
||||
delete_payload_t *delete_payload;
|
||||
protocol_id_t protocol;
|
||||
u_int32_t spi;
|
||||
|
||||
payloads = message->create_payload_enumerator(message);
|
||||
while (payloads->enumerate(payloads, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == DELETE_V1)
|
||||
{
|
||||
delete_payload = (delete_payload_t*)payload;
|
||||
protocol = delete_payload->get_protocol_id(delete_payload);
|
||||
if (protocol != PROTO_ESP && protocol != PROTO_AH)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
spis = delete_payload->create_spi_enumerator(delete_payload);
|
||||
while (spis->enumerate(spis, &spi))
|
||||
{
|
||||
DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
|
||||
protocol_id_names, protocol, ntohl(spi));
|
||||
if (!delete_child(this, protocol, spi))
|
||||
{
|
||||
DBG1(DBG_IKE, "CHILD_SA not found, ignored");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
spis->destroy(spis);
|
||||
}
|
||||
}
|
||||
payloads->destroy(payloads);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_quick_delete_t *this, message_t *message)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_quick_delete_t *this)
|
||||
{
|
||||
return TASK_QUICK_DELETE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_quick_delete_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_quick_delete_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
|
||||
u_int32_t spi, bool force, bool expired)
|
||||
{
|
||||
private_quick_delete_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.protocol = protocol,
|
||||
.spi = spi,
|
||||
.force = force,
|
||||
.expired = expired,
|
||||
);
|
||||
|
||||
if (protocol != PROTO_NONE)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup quick_delete quick_delete
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef QUICK_DELETE_H_
|
||||
#define QUICK_DELETE_H_
|
||||
|
||||
typedef struct quick_delete_t quick_delete_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
#include <sa/child_sa.h>
|
||||
|
||||
/**
|
||||
* Task of type QUICK_DELETE, delete an IKEv1 quick mode SA.
|
||||
*/
|
||||
struct quick_delete_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new quick_delete task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param protocol protocol of CHILD_SA to delete, PROTO_NONE as responder
|
||||
* @param spi inbound SPI of CHILD_SA to delete
|
||||
* @param force send delete even if SA does not exist
|
||||
* @param expired TRUE if SA already expired
|
||||
* @return quick_delete task to handle by the task_manager
|
||||
*/
|
||||
quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
|
||||
u_int32_t spi, bool force, bool expired);
|
||||
|
||||
#endif /** QUICK_DELETE_H_ @}*/
|
||||
Executable
+1104
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup quick_mode quick_mode
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef QUICK_MODE_H_
|
||||
#define QUICK_MODE_H_
|
||||
|
||||
typedef struct quick_mode_t quick_mode_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* IKEv1 quick mode, establishes a CHILD_SA in IKEv1.
|
||||
*/
|
||||
struct quick_mode_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
|
||||
/**
|
||||
* Use a specific reqid to install this CHILD_SA.
|
||||
*
|
||||
* @param reqid reqid to use
|
||||
*/
|
||||
void (*use_reqid)(quick_mode_t *this, u_int32_t reqid);
|
||||
|
||||
/**
|
||||
* Set the SPI of the old SA, if rekeying.
|
||||
*
|
||||
* @param spi spi of SA to rekey
|
||||
*/
|
||||
void (*rekey)(quick_mode_t *this, u_int32_t spi);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new quick_mode task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param config child_cfg if task initiator, NULL if responder
|
||||
* @param tsi source of triggering packet, or NULL
|
||||
* @param tsr destination of triggering packet, or NULL
|
||||
* @return task to handle by the task_manager
|
||||
*/
|
||||
quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
|
||||
traffic_selector_t *tsi, traffic_selector_t *tsr);
|
||||
|
||||
#endif /** QUICK_MODE_H_ @}*/
|
||||
Executable
+458
@@ -0,0 +1,458 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "xauth.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <hydra.h>
|
||||
#include <encoding/payloads/cp_payload.h>
|
||||
#include <processing/jobs/adopt_children_job.h>
|
||||
|
||||
typedef struct private_xauth_t private_xauth_t;
|
||||
|
||||
/**
|
||||
* Status types exchanged
|
||||
*/
|
||||
typedef enum {
|
||||
XAUTH_FAILED = 0,
|
||||
XAUTH_OK = 1,
|
||||
} xauth_status_t;
|
||||
|
||||
/**
|
||||
* Private members of a xauth_t task.
|
||||
*/
|
||||
struct private_xauth_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
xauth_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the XAUTH initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* XAuth backend to use
|
||||
*/
|
||||
xauth_method_t *xauth;
|
||||
|
||||
/**
|
||||
* XAuth username
|
||||
*/
|
||||
identification_t *user;
|
||||
|
||||
/**
|
||||
* Generated configuration payload
|
||||
*/
|
||||
cp_payload_t *cp;
|
||||
|
||||
/**
|
||||
* received identifier
|
||||
*/
|
||||
u_int16_t identifier;
|
||||
|
||||
/**
|
||||
* status of Xauth exchange
|
||||
*/
|
||||
xauth_status_t status;
|
||||
};
|
||||
|
||||
/**
|
||||
* Load XAuth backend
|
||||
*/
|
||||
static xauth_method_t *load_method(private_xauth_t* this)
|
||||
{
|
||||
identification_t *server, *peer;
|
||||
enumerator_t *enumerator;
|
||||
xauth_method_t *xauth;
|
||||
xauth_role_t role;
|
||||
peer_cfg_t *peer_cfg;
|
||||
auth_cfg_t *auth;
|
||||
char *name;
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
server = this->ike_sa->get_my_id(this->ike_sa);
|
||||
peer = this->ike_sa->get_other_id(this->ike_sa);
|
||||
role = XAUTH_SERVER;
|
||||
}
|
||||
else
|
||||
{
|
||||
peer = this->ike_sa->get_my_id(this->ike_sa);
|
||||
server = this->ike_sa->get_other_id(this->ike_sa);
|
||||
role = XAUTH_PEER;
|
||||
}
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, !this->initiator);
|
||||
if (!enumerator->enumerate(enumerator, &auth) ||
|
||||
(uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
|
||||
{
|
||||
if (!enumerator->enumerate(enumerator, &auth) ||
|
||||
(uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
|
||||
{
|
||||
DBG1(DBG_CFG, "no XAuth authentication round found");
|
||||
enumerator->destroy(enumerator);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND);
|
||||
this->user = auth->get(auth, AUTH_RULE_XAUTH_IDENTITY);
|
||||
if (!this->initiator && this->user)
|
||||
{ /* use XAUTH username, if configured */
|
||||
peer = this->user;
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
xauth = charon->xauth->create_instance(charon->xauth, name, role,
|
||||
server, peer);
|
||||
if (!xauth)
|
||||
{
|
||||
if (name)
|
||||
{
|
||||
DBG1(DBG_CFG, "no XAuth method found named '%s'");
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, "no XAuth method found");
|
||||
}
|
||||
}
|
||||
return xauth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set IKE_SA to established state
|
||||
*/
|
||||
static bool establish(private_xauth_t *this)
|
||||
{
|
||||
if (!charon->bus->authorize(charon->bus, FALSE))
|
||||
{
|
||||
DBG1(DBG_IKE, "XAuth authorization hook forbids IKE_SA, cancelling");
|
||||
return FALSE;
|
||||
}
|
||||
if (!charon->bus->authorize(charon->bus, TRUE))
|
||||
{
|
||||
DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa),
|
||||
this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_my_id(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
|
||||
charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create auth config after successful authentication
|
||||
*/
|
||||
static void add_auth_cfg(private_xauth_t *this, identification_t *id, bool local)
|
||||
{
|
||||
auth_cfg_t *auth;
|
||||
|
||||
auth = auth_cfg_create();
|
||||
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
|
||||
auth->add(auth, AUTH_RULE_XAUTH_IDENTITY, id->clone(id));
|
||||
|
||||
this->ike_sa->add_auth_cfg(this->ike_sa, local, auth);
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i_status, status_t,
|
||||
private_xauth_t *this, message_t *message)
|
||||
{
|
||||
cp_payload_t *cp;
|
||||
|
||||
cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET);
|
||||
cp->add_attribute(cp,
|
||||
configuration_attribute_create_value(XAUTH_STATUS, this->status));
|
||||
|
||||
message->add_payload(message, (payload_t *)cp);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_xauth_t *this, message_t *message)
|
||||
{
|
||||
if (!this->xauth)
|
||||
{
|
||||
cp_payload_t *cp;
|
||||
|
||||
this->xauth = load_method(this);
|
||||
if (!this->xauth)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
if (this->xauth->initiate(this->xauth, &cp) != NEED_MORE)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
message->add_payload(message, (payload_t *)cp);
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
if (this->cp)
|
||||
{ /* send previously generated payload */
|
||||
message->add_payload(message, (payload_t *)this->cp);
|
||||
this->cp = NULL;
|
||||
return NEED_MORE;
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r_ack, status_t,
|
||||
private_xauth_t *this, message_t *message)
|
||||
{
|
||||
cp_payload_t *cp;
|
||||
|
||||
cp = cp_payload_create_type(CONFIGURATION_V1, CFG_ACK);
|
||||
cp->set_identifier(cp, this->identifier);
|
||||
cp->add_attribute(cp,
|
||||
configuration_attribute_create_chunk(
|
||||
CONFIGURATION_ATTRIBUTE_V1, XAUTH_STATUS, chunk_empty));
|
||||
|
||||
message->add_payload(message, (payload_t *)cp);
|
||||
|
||||
if (this->status == XAUTH_OK && establish(this))
|
||||
{
|
||||
lib->processor->queue_job(lib->processor, (job_t*)
|
||||
adopt_children_job_create(this->ike_sa->get_id(this->ike_sa)));
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_xauth_t *this, message_t *message)
|
||||
{
|
||||
cp_payload_t *cp;
|
||||
|
||||
if (!this->xauth)
|
||||
{
|
||||
this->xauth = load_method(this);
|
||||
if (!this->xauth)
|
||||
{ /* send empty reply */
|
||||
return NEED_MORE;
|
||||
}
|
||||
}
|
||||
cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
|
||||
if (!cp)
|
||||
{
|
||||
DBG1(DBG_IKE, "configuration payload missing in XAuth request");
|
||||
return FAILED;
|
||||
}
|
||||
if (cp->get_type(cp) == CFG_REQUEST)
|
||||
{
|
||||
switch (this->xauth->process(this->xauth, cp, &this->cp))
|
||||
{
|
||||
case NEED_MORE:
|
||||
return NEED_MORE;
|
||||
case SUCCESS:
|
||||
case FAILED:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this->cp = NULL;
|
||||
return NEED_MORE;
|
||||
}
|
||||
if (cp->get_type(cp) == CFG_SET)
|
||||
{
|
||||
configuration_attribute_t *attribute;
|
||||
enumerator_t *enumerator;
|
||||
|
||||
enumerator = cp->create_attribute_enumerator(cp);
|
||||
while (enumerator->enumerate(enumerator, &attribute))
|
||||
{
|
||||
if (attribute->get_type(attribute) == XAUTH_STATUS)
|
||||
{
|
||||
this->status = attribute->get_value(attribute);
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
if (this->status == XAUTH_OK)
|
||||
{
|
||||
DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) successful",
|
||||
this->xauth->get_identity(this->xauth));
|
||||
add_auth_cfg(this, this->xauth->get_identity(this->xauth), TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) failed",
|
||||
this->xauth->get_identity(this->xauth));
|
||||
}
|
||||
}
|
||||
this->identifier = cp->get_identifier(cp);
|
||||
this->public.task.build = _build_r_ack;
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_xauth_t *this, message_t *message)
|
||||
{
|
||||
if (!this->cp)
|
||||
{ /* send empty reply if building data failed */
|
||||
this->cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
|
||||
}
|
||||
message->add_payload(message, (payload_t *)this->cp);
|
||||
this->cp = NULL;
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i_status, status_t,
|
||||
private_xauth_t *this, message_t *message)
|
||||
{
|
||||
cp_payload_t *cp;
|
||||
|
||||
cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
|
||||
if (!cp || cp->get_type(cp) != CFG_ACK)
|
||||
{
|
||||
DBG1(DBG_IKE, "received invalid XAUTH status response");
|
||||
return FAILED;
|
||||
}
|
||||
if (this->status != XAUTH_OK)
|
||||
{
|
||||
DBG1(DBG_IKE, "destroying IKE_SA after failed XAuth authentication");
|
||||
return FAILED;
|
||||
}
|
||||
if (!establish(this))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
this->ike_sa->set_condition(this->ike_sa, COND_XAUTH_AUTHENTICATED, TRUE);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_xauth_t *this, message_t *message)
|
||||
{
|
||||
identification_t *id;
|
||||
cp_payload_t *cp;
|
||||
|
||||
cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
|
||||
if (!cp)
|
||||
{
|
||||
DBG1(DBG_IKE, "configuration payload missing in XAuth response");
|
||||
return FAILED;
|
||||
}
|
||||
switch (this->xauth->process(this->xauth, cp, &this->cp))
|
||||
{
|
||||
case NEED_MORE:
|
||||
return NEED_MORE;
|
||||
case SUCCESS:
|
||||
id = this->xauth->get_identity(this->xauth);
|
||||
if (this->user && !id->matches(id, this->user))
|
||||
{
|
||||
DBG1(DBG_IKE, "XAuth username '%Y' does not match to "
|
||||
"configured username '%Y'", id, this->user);
|
||||
break;
|
||||
}
|
||||
DBG1(DBG_IKE, "XAuth authentication of '%Y' successful", id);
|
||||
add_auth_cfg(this, id, FALSE);
|
||||
this->status = XAUTH_OK;
|
||||
break;
|
||||
case FAILED:
|
||||
DBG1(DBG_IKE, "XAuth authentication of '%Y' failed",
|
||||
this->xauth->get_identity(this->xauth));
|
||||
break;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
this->public.task.build = _build_i_status;
|
||||
this->public.task.process = _process_i_status;
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_xauth_t *this)
|
||||
{
|
||||
return TASK_XAUTH;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_xauth_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
DESTROY_IF(this->xauth);
|
||||
DESTROY_IF(this->cp);
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->xauth = NULL;
|
||||
this->cp = NULL;
|
||||
this->user = NULL;
|
||||
this->status = XAUTH_FAILED;
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_xauth_t *this)
|
||||
{
|
||||
DESTROY_IF(this->xauth);
|
||||
DESTROY_IF(this->cp);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_xauth_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.initiator = initiator,
|
||||
.ike_sa = ike_sa,
|
||||
.status = XAUTH_FAILED,
|
||||
);
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup xauth xauth
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef XAUTH_H_
|
||||
#define XAUTH_H_
|
||||
|
||||
typedef struct xauth_t xauth_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type TASK_XAUTH, additional authentication after main/aggressive mode.
|
||||
*/
|
||||
struct xauth_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new xauth task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE for initiator
|
||||
* @return xauth task to handle by the task_manager
|
||||
*/
|
||||
xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** XAUTH_H_ @}*/
|
||||
+7
-7
@@ -16,7 +16,8 @@
|
||||
#include "eap_authenticator.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/authenticators/eap/eap_method.h>
|
||||
#include <sa/ikev2/keymat_v2.h>
|
||||
#include <sa/eap/eap_method.h>
|
||||
#include <encoding/payloads/auth_payload.h>
|
||||
#include <encoding/payloads/eap_payload.h>
|
||||
|
||||
@@ -365,7 +366,7 @@ static eap_payload_t* client_process_eap(private_eap_authenticator_t *this,
|
||||
if (vendor)
|
||||
{
|
||||
DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d ",
|
||||
"(id 0x%02X)", type, vendor, in->get_identifier(in));
|
||||
"(id 0x%02X)", type, vendor, in->get_identifier(in));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -408,7 +409,7 @@ static bool verify_auth(private_eap_authenticator_t *this, message_t *message,
|
||||
chunk_t auth_data, recv_auth_data;
|
||||
identification_t *other_id;
|
||||
auth_cfg_t *auth;
|
||||
keymat_t *keymat;
|
||||
keymat_v2_t *keymat;
|
||||
|
||||
auth_payload = (auth_payload_t*)message->get_payload(message,
|
||||
AUTHENTICATION);
|
||||
@@ -418,7 +419,7 @@ static bool verify_auth(private_eap_authenticator_t *this, message_t *message,
|
||||
return FALSE;
|
||||
}
|
||||
other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
keymat = this->ike_sa->get_keymat(this->ike_sa);
|
||||
keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||
auth_data = keymat->get_psk_sig(keymat, TRUE, init, nonce,
|
||||
this->msk, other_id, this->reserved);
|
||||
recv_auth_data = auth_payload->get_data(auth_payload);
|
||||
@@ -448,10 +449,10 @@ static void build_auth(private_eap_authenticator_t *this, message_t *message,
|
||||
auth_payload_t *auth_payload;
|
||||
identification_t *my_id;
|
||||
chunk_t auth_data;
|
||||
keymat_t *keymat;
|
||||
keymat_v2_t *keymat;
|
||||
|
||||
my_id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
keymat = this->ike_sa->get_keymat(this->ike_sa);
|
||||
keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||
|
||||
DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N",
|
||||
my_id, auth_class_names, AUTH_CLASS_EAP);
|
||||
@@ -695,4 +696,3 @@ eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa,
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
|
||||
typedef struct eap_authenticator_t eap_authenticator_t;
|
||||
|
||||
#include <sa/authenticators/authenticator.h>
|
||||
#include <sa/authenticator.h>
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t using EAP authentication.
|
||||
+5
-5
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/auth_payload.h>
|
||||
#include <sa/ikev2/keymat_v2.h>
|
||||
|
||||
typedef struct private_psk_authenticator_t private_psk_authenticator_t;
|
||||
|
||||
@@ -59,9 +60,9 @@ METHOD(authenticator_t, build, status_t,
|
||||
auth_payload_t *auth_payload;
|
||||
shared_key_t *key;
|
||||
chunk_t auth_data;
|
||||
keymat_t *keymat;
|
||||
keymat_v2_t *keymat;
|
||||
|
||||
keymat = this->ike_sa->get_keymat(this->ike_sa);
|
||||
keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||
my_id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N",
|
||||
@@ -96,14 +97,14 @@ METHOD(authenticator_t, process, status_t,
|
||||
enumerator_t *enumerator;
|
||||
bool authenticated = FALSE;
|
||||
int keys_found = 0;
|
||||
keymat_t *keymat;
|
||||
keymat_v2_t *keymat;
|
||||
|
||||
auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION);
|
||||
if (!auth_payload)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
keymat = this->ike_sa->get_keymat(this->ike_sa);
|
||||
keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||
recv_auth_data = auth_payload->get_data(auth_payload);
|
||||
my_id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
@@ -201,4 +202,3 @@ psk_authenticator_t *psk_authenticator_create_verifier(ike_sa_t *ike_sa,
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
|
||||
typedef struct psk_authenticator_t psk_authenticator_t;
|
||||
|
||||
#include <sa/authenticators/authenticator.h>
|
||||
#include <sa/authenticator.h>
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t using pre-shared keys.
|
||||
+5
-4
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/auth_payload.h>
|
||||
#include <sa/ikev2/keymat_v2.h>
|
||||
|
||||
typedef struct private_pubkey_authenticator_t private_pubkey_authenticator_t;
|
||||
|
||||
@@ -64,7 +65,7 @@ METHOD(authenticator_t, build, status_t,
|
||||
auth_payload_t *auth_payload;
|
||||
auth_method_t auth_method;
|
||||
signature_scheme_t scheme;
|
||||
keymat_t *keymat;
|
||||
keymat_v2_t *keymat;
|
||||
|
||||
id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
|
||||
@@ -110,7 +111,7 @@ METHOD(authenticator_t, build, status_t,
|
||||
key_type_names, private->get_type(private));
|
||||
return status;
|
||||
}
|
||||
keymat = this->ike_sa->get_keymat(this->ike_sa);
|
||||
keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||
octets = keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init,
|
||||
this->nonce, id, this->reserved);
|
||||
if (private->sign(private, scheme, octets, &auth_data))
|
||||
@@ -144,7 +145,7 @@ METHOD(authenticator_t, process, status_t,
|
||||
key_type_t key_type = KEY_ECDSA;
|
||||
signature_scheme_t scheme;
|
||||
status_t status = NOT_FOUND;
|
||||
keymat_t *keymat;
|
||||
keymat_v2_t *keymat;
|
||||
|
||||
auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION);
|
||||
if (!auth_payload)
|
||||
@@ -174,7 +175,7 @@ METHOD(authenticator_t, process, status_t,
|
||||
}
|
||||
auth_data = auth_payload->get_data(auth_payload);
|
||||
id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
keymat = this->ike_sa->get_keymat(this->ike_sa);
|
||||
keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||
octets = keymat->get_auth_octets(keymat, TRUE, this->ike_sa_init,
|
||||
this->nonce, id, this->reserved);
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
|
||||
typedef struct pubkey_authenticator_t pubkey_authenticator_t;
|
||||
|
||||
#include <sa/authenticators/authenticator.h>
|
||||
#include <sa/authenticator.h>
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t using public key authenitcation.
|
||||
@@ -1028,14 +1028,15 @@ static void queue_retransmission(private_connect_manager_t *this, check_list_t *
|
||||
static void send_check(private_connect_manager_t *this, check_list_t *checklist,
|
||||
check_t *check, endpoint_pair_t *pair, bool request)
|
||||
{
|
||||
message_t *message = message_create();
|
||||
message_t *message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION);
|
||||
message->set_message_id(message, check->mid);
|
||||
message->set_exchange_type(message, INFORMATIONAL);
|
||||
message->set_request(message, request);
|
||||
message->set_destination(message, check->dst->clone(check->dst));
|
||||
message->set_source(message, check->src->clone(check->src));
|
||||
|
||||
ike_sa_id_t *ike_sa_id = ike_sa_id_create(0, 0, request);
|
||||
ike_sa_id_t *ike_sa_id = ike_sa_id_create(IKEV2_MAJOR_VERSION, 0, 0,
|
||||
request);
|
||||
message->set_ike_sa_id(message, ike_sa_id);
|
||||
ike_sa_id->destroy(ike_sa_id);
|
||||
|
||||
@@ -0,0 +1,588 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 "keymat_v2.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <crypto/prf_plus.h>
|
||||
|
||||
typedef struct private_keymat_v2_t private_keymat_v2_t;
|
||||
|
||||
/**
|
||||
* Private data of an keymat_t object.
|
||||
*/
|
||||
struct private_keymat_v2_t {
|
||||
|
||||
/**
|
||||
* Public keymat_v2_t interface.
|
||||
*/
|
||||
keymat_v2_t public;
|
||||
|
||||
/**
|
||||
* IKE_SA Role, initiator or responder
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* inbound AEAD
|
||||
*/
|
||||
aead_t *aead_in;
|
||||
|
||||
/**
|
||||
* outbound AEAD
|
||||
*/
|
||||
aead_t *aead_out;
|
||||
|
||||
/**
|
||||
* General purpose PRF
|
||||
*/
|
||||
prf_t *prf;
|
||||
|
||||
/**
|
||||
* Negotiated PRF algorithm
|
||||
*/
|
||||
pseudo_random_function_t prf_alg;
|
||||
|
||||
/**
|
||||
* Key to derive key material from for CHILD_SAs, rekeying
|
||||
*/
|
||||
chunk_t skd;
|
||||
|
||||
/**
|
||||
* Key to build outging authentication data (SKp)
|
||||
*/
|
||||
chunk_t skp_build;
|
||||
|
||||
/**
|
||||
* Key to verify incoming authentication data (SKp)
|
||||
*/
|
||||
chunk_t skp_verify;
|
||||
};
|
||||
|
||||
METHOD(keymat_t, get_version, ike_version_t,
|
||||
private_keymat_v2_t *this)
|
||||
{
|
||||
return IKEV2;
|
||||
}
|
||||
|
||||
METHOD(keymat_t, create_dh, diffie_hellman_t*,
|
||||
private_keymat_v2_t *this, diffie_hellman_group_t group)
|
||||
{
|
||||
return lib->crypto->create_dh(lib->crypto, group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive IKE keys for a combined AEAD algorithm
|
||||
*/
|
||||
static bool derive_ike_aead(private_keymat_v2_t *this, u_int16_t alg,
|
||||
u_int16_t key_size, prf_plus_t *prf_plus)
|
||||
{
|
||||
aead_t *aead_i, *aead_r;
|
||||
chunk_t key;
|
||||
|
||||
/* SK_ei/SK_er used for encryption */
|
||||
aead_i = lib->crypto->create_aead(lib->crypto, alg, key_size / 8);
|
||||
aead_r = lib->crypto->create_aead(lib->crypto, alg, key_size / 8);
|
||||
if (aead_i == NULL || aead_r == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
|
||||
transform_type_names, ENCRYPTION_ALGORITHM,
|
||||
encryption_algorithm_names, alg, key_size);
|
||||
return FALSE;
|
||||
}
|
||||
key_size = aead_i->get_key_size(aead_i);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_ei secret %B", &key);
|
||||
aead_i->set_key(aead_i, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_er secret %B", &key);
|
||||
aead_r->set_key(aead_r, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
this->aead_in = aead_r;
|
||||
this->aead_out = aead_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->aead_in = aead_i;
|
||||
this->aead_out = aead_r;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive IKE keys for traditional encryption and MAC algorithms
|
||||
*/
|
||||
static bool derive_ike_traditional(private_keymat_v2_t *this, u_int16_t enc_alg,
|
||||
u_int16_t enc_size, u_int16_t int_alg, prf_plus_t *prf_plus)
|
||||
{
|
||||
crypter_t *crypter_i, *crypter_r;
|
||||
signer_t *signer_i, *signer_r;
|
||||
size_t key_size;
|
||||
chunk_t key;
|
||||
|
||||
/* SK_ai/SK_ar used for integrity protection */
|
||||
signer_i = lib->crypto->create_signer(lib->crypto, int_alg);
|
||||
signer_r = lib->crypto->create_signer(lib->crypto, int_alg);
|
||||
if (signer_i == NULL || signer_r == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "%N %N not supported!",
|
||||
transform_type_names, INTEGRITY_ALGORITHM,
|
||||
integrity_algorithm_names, int_alg);
|
||||
return FALSE;
|
||||
}
|
||||
key_size = signer_i->get_key_size(signer_i);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_ai secret %B", &key);
|
||||
signer_i->set_key(signer_i, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_ar secret %B", &key);
|
||||
signer_r->set_key(signer_r, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
/* SK_ei/SK_er used for encryption */
|
||||
crypter_i = lib->crypto->create_crypter(lib->crypto, enc_alg, enc_size / 8);
|
||||
crypter_r = lib->crypto->create_crypter(lib->crypto, enc_alg, enc_size / 8);
|
||||
if (crypter_i == NULL || crypter_r == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
|
||||
transform_type_names, ENCRYPTION_ALGORITHM,
|
||||
encryption_algorithm_names, enc_alg, enc_size);
|
||||
signer_i->destroy(signer_i);
|
||||
signer_r->destroy(signer_r);
|
||||
return FALSE;
|
||||
}
|
||||
key_size = crypter_i->get_key_size(crypter_i);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_ei secret %B", &key);
|
||||
crypter_i->set_key(crypter_i, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_er secret %B", &key);
|
||||
crypter_r->set_key(crypter_r, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
this->aead_in = aead_create(crypter_r, signer_r);
|
||||
this->aead_out = aead_create(crypter_i, signer_i);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->aead_in = aead_create(crypter_i, signer_i);
|
||||
this->aead_out = aead_create(crypter_r, signer_r);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(keymat_v2_t, derive_ike_keys, bool,
|
||||
private_keymat_v2_t *this, proposal_t *proposal, diffie_hellman_t *dh,
|
||||
chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id,
|
||||
pseudo_random_function_t rekey_function, chunk_t rekey_skd)
|
||||
{
|
||||
chunk_t skeyseed, key, secret, full_nonce, fixed_nonce, prf_plus_seed;
|
||||
chunk_t spi_i, spi_r;
|
||||
prf_plus_t *prf_plus;
|
||||
u_int16_t alg, key_size, int_alg;
|
||||
prf_t *rekey_prf = NULL;
|
||||
|
||||
spi_i = chunk_alloca(sizeof(u_int64_t));
|
||||
spi_r = chunk_alloca(sizeof(u_int64_t));
|
||||
|
||||
if (dh->get_shared_secret(dh, &secret) != SUCCESS)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Create SAs general purpose PRF first, we may use it here */
|
||||
if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
|
||||
{
|
||||
DBG1(DBG_IKE, "no %N selected",
|
||||
transform_type_names, PSEUDO_RANDOM_FUNCTION);
|
||||
return FALSE;
|
||||
}
|
||||
this->prf_alg = alg;
|
||||
this->prf = lib->crypto->create_prf(lib->crypto, alg);
|
||||
if (this->prf == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "%N %N not supported!",
|
||||
transform_type_names, PSEUDO_RANDOM_FUNCTION,
|
||||
pseudo_random_function_names, alg);
|
||||
return FALSE;
|
||||
}
|
||||
DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret);
|
||||
/* full nonce is used as seed for PRF+ ... */
|
||||
full_nonce = chunk_cat("cc", nonce_i, nonce_r);
|
||||
/* but the PRF may need a fixed key which only uses the first bytes of
|
||||
* the nonces. */
|
||||
switch (alg)
|
||||
{
|
||||
case PRF_AES128_XCBC:
|
||||
/* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does
|
||||
* not and therefore fixed key semantics apply to XCBC for key
|
||||
* derivation. */
|
||||
case PRF_CAMELLIA128_XCBC:
|
||||
/* draft-kanno-ipsecme-camellia-xcbc refers to rfc 4434, we
|
||||
* assume fixed key length. */
|
||||
key_size = this->prf->get_key_size(this->prf)/2;
|
||||
nonce_i.len = min(nonce_i.len, key_size);
|
||||
nonce_r.len = min(nonce_r.len, key_size);
|
||||
break;
|
||||
default:
|
||||
/* all other algorithms use variable key length, full nonce */
|
||||
break;
|
||||
}
|
||||
fixed_nonce = chunk_cat("cc", nonce_i, nonce_r);
|
||||
*((u_int64_t*)spi_i.ptr) = id->get_initiator_spi(id);
|
||||
*((u_int64_t*)spi_r.ptr) = id->get_responder_spi(id);
|
||||
prf_plus_seed = chunk_cat("ccc", full_nonce, spi_i, spi_r);
|
||||
|
||||
/* KEYMAT = prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr)
|
||||
*
|
||||
* if we are rekeying, SKEYSEED is built on another way
|
||||
*/
|
||||
if (rekey_function == PRF_UNDEFINED) /* not rekeying */
|
||||
{
|
||||
/* SKEYSEED = prf(Ni | Nr, g^ir) */
|
||||
this->prf->set_key(this->prf, fixed_nonce);
|
||||
this->prf->allocate_bytes(this->prf, secret, &skeyseed);
|
||||
this->prf->set_key(this->prf, skeyseed);
|
||||
prf_plus = prf_plus_create(this->prf, TRUE, prf_plus_seed);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* SKEYSEED = prf(SK_d (old), [g^ir (new)] | Ni | Nr)
|
||||
* use OLD SAs PRF functions for both prf_plus and prf */
|
||||
rekey_prf = lib->crypto->create_prf(lib->crypto, rekey_function);
|
||||
if (!rekey_prf)
|
||||
{
|
||||
DBG1(DBG_IKE, "PRF of old SA %N not supported!",
|
||||
pseudo_random_function_names, rekey_function);
|
||||
chunk_free(&full_nonce);
|
||||
chunk_free(&fixed_nonce);
|
||||
chunk_clear(&prf_plus_seed);
|
||||
return FALSE;
|
||||
}
|
||||
secret = chunk_cat("mc", secret, full_nonce);
|
||||
rekey_prf->set_key(rekey_prf, rekey_skd);
|
||||
rekey_prf->allocate_bytes(rekey_prf, secret, &skeyseed);
|
||||
rekey_prf->set_key(rekey_prf, skeyseed);
|
||||
prf_plus = prf_plus_create(rekey_prf, TRUE, prf_plus_seed);
|
||||
}
|
||||
DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
|
||||
|
||||
chunk_clear(&skeyseed);
|
||||
chunk_clear(&secret);
|
||||
chunk_free(&full_nonce);
|
||||
chunk_free(&fixed_nonce);
|
||||
chunk_clear(&prf_plus_seed);
|
||||
|
||||
/* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */
|
||||
|
||||
/* SK_d is used for generating CHILD_SA key mat => store for later use */
|
||||
key_size = this->prf->get_key_size(this->prf);
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &this->skd);
|
||||
DBG4(DBG_IKE, "Sk_d secret %B", &this->skd);
|
||||
|
||||
if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &key_size))
|
||||
{
|
||||
DBG1(DBG_IKE, "no %N selected",
|
||||
transform_type_names, ENCRYPTION_ALGORITHM);
|
||||
prf_plus->destroy(prf_plus);
|
||||
DESTROY_IF(rekey_prf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (encryption_algorithm_is_aead(alg))
|
||||
{
|
||||
if (!derive_ike_aead(this, alg, key_size, prf_plus))
|
||||
{
|
||||
prf_plus->destroy(prf_plus);
|
||||
DESTROY_IF(rekey_prf);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
|
||||
&int_alg, NULL))
|
||||
{
|
||||
DBG1(DBG_IKE, "no %N selected",
|
||||
transform_type_names, INTEGRITY_ALGORITHM);
|
||||
prf_plus->destroy(prf_plus);
|
||||
DESTROY_IF(rekey_prf);
|
||||
return FALSE;
|
||||
}
|
||||
if (!derive_ike_traditional(this, alg, key_size, int_alg, prf_plus))
|
||||
{
|
||||
prf_plus->destroy(prf_plus);
|
||||
DESTROY_IF(rekey_prf);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* SK_pi/SK_pr used for authentication => stored for later */
|
||||
key_size = this->prf->get_key_size(this->prf);
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_pi secret %B", &key);
|
||||
if (this->initiator)
|
||||
{
|
||||
this->skp_build = key;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->skp_verify = key;
|
||||
}
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_pr secret %B", &key);
|
||||
if (this->initiator)
|
||||
{
|
||||
this->skp_verify = key;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->skp_build = key;
|
||||
}
|
||||
|
||||
/* all done, prf_plus not needed anymore */
|
||||
prf_plus->destroy(prf_plus);
|
||||
DESTROY_IF(rekey_prf);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(keymat_v2_t, derive_child_keys, bool,
|
||||
private_keymat_v2_t *this, proposal_t *proposal, diffie_hellman_t *dh,
|
||||
chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i,
|
||||
chunk_t *encr_r, chunk_t *integ_r)
|
||||
{
|
||||
u_int16_t enc_alg, int_alg, enc_size = 0, int_size = 0;
|
||||
chunk_t seed, secret = chunk_empty;
|
||||
prf_plus_t *prf_plus;
|
||||
|
||||
if (dh)
|
||||
{
|
||||
if (dh->get_shared_secret(dh, &secret) != SUCCESS)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
DBG4(DBG_CHD, "DH secret %B", &secret);
|
||||
}
|
||||
seed = chunk_cata("mcc", secret, nonce_i, nonce_r);
|
||||
DBG4(DBG_CHD, "seed %B", &seed);
|
||||
|
||||
if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
|
||||
&enc_alg, &enc_size))
|
||||
{
|
||||
DBG2(DBG_CHD, " using %N for encryption",
|
||||
encryption_algorithm_names, enc_alg);
|
||||
|
||||
if (!enc_size)
|
||||
{
|
||||
enc_size = keymat_get_keylen_encr(enc_alg);
|
||||
}
|
||||
if (enc_alg != ENCR_NULL && !enc_size)
|
||||
{
|
||||
DBG1(DBG_CHD, "no keylength defined for %N",
|
||||
encryption_algorithm_names, enc_alg);
|
||||
return FALSE;
|
||||
}
|
||||
/* to bytes */
|
||||
enc_size /= 8;
|
||||
|
||||
/* CCM/GCM/CTR/GMAC needs additional bytes */
|
||||
switch (enc_alg)
|
||||
{
|
||||
case ENCR_AES_CCM_ICV8:
|
||||
case ENCR_AES_CCM_ICV12:
|
||||
case ENCR_AES_CCM_ICV16:
|
||||
case ENCR_CAMELLIA_CCM_ICV8:
|
||||
case ENCR_CAMELLIA_CCM_ICV12:
|
||||
case ENCR_CAMELLIA_CCM_ICV16:
|
||||
enc_size += 3;
|
||||
break;
|
||||
case ENCR_AES_GCM_ICV8:
|
||||
case ENCR_AES_GCM_ICV12:
|
||||
case ENCR_AES_GCM_ICV16:
|
||||
case ENCR_AES_CTR:
|
||||
case ENCR_NULL_AUTH_AES_GMAC:
|
||||
enc_size += 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
|
||||
&int_alg, &int_size))
|
||||
{
|
||||
DBG2(DBG_CHD, " using %N for integrity",
|
||||
integrity_algorithm_names, int_alg);
|
||||
|
||||
if (!int_size)
|
||||
{
|
||||
int_size = keymat_get_keylen_integ(int_alg);
|
||||
}
|
||||
if (!int_size)
|
||||
{
|
||||
DBG1(DBG_CHD, "no keylength defined for %N",
|
||||
integrity_algorithm_names, int_alg);
|
||||
return FALSE;
|
||||
}
|
||||
/* to bytes */
|
||||
int_size /= 8;
|
||||
}
|
||||
|
||||
this->prf->set_key(this->prf, this->skd);
|
||||
prf_plus = prf_plus_create(this->prf, TRUE, seed);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, enc_size, encr_i);
|
||||
prf_plus->allocate_bytes(prf_plus, int_size, integ_i);
|
||||
prf_plus->allocate_bytes(prf_plus, enc_size, encr_r);
|
||||
prf_plus->allocate_bytes(prf_plus, int_size, integ_r);
|
||||
|
||||
prf_plus->destroy(prf_plus);
|
||||
|
||||
if (enc_size)
|
||||
{
|
||||
DBG4(DBG_CHD, "encryption initiator key %B", encr_i);
|
||||
DBG4(DBG_CHD, "encryption responder key %B", encr_r);
|
||||
}
|
||||
if (int_size)
|
||||
{
|
||||
DBG4(DBG_CHD, "integrity initiator key %B", integ_i);
|
||||
DBG4(DBG_CHD, "integrity responder key %B", integ_r);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(keymat_v2_t, get_skd, pseudo_random_function_t,
|
||||
private_keymat_v2_t *this, chunk_t *skd)
|
||||
{
|
||||
*skd = this->skd;
|
||||
return this->prf_alg;
|
||||
}
|
||||
|
||||
METHOD(keymat_t, get_aead, aead_t*,
|
||||
private_keymat_v2_t *this, bool in)
|
||||
{
|
||||
return in ? this->aead_in : this->aead_out;
|
||||
}
|
||||
|
||||
METHOD(keymat_v2_t, get_auth_octets, chunk_t,
|
||||
private_keymat_v2_t *this, bool verify, chunk_t ike_sa_init,
|
||||
chunk_t nonce, identification_t *id, char reserved[3])
|
||||
{
|
||||
chunk_t chunk, idx, octets;
|
||||
chunk_t skp;
|
||||
|
||||
skp = verify ? this->skp_verify : this->skp_build;
|
||||
|
||||
chunk = chunk_alloca(4);
|
||||
chunk.ptr[0] = id->get_type(id);
|
||||
memcpy(chunk.ptr + 1, reserved, 3);
|
||||
idx = chunk_cata("cc", chunk, id->get_encoding(id));
|
||||
|
||||
DBG3(DBG_IKE, "IDx' %B", &idx);
|
||||
DBG3(DBG_IKE, "SK_p %B", &skp);
|
||||
this->prf->set_key(this->prf, skp);
|
||||
this->prf->allocate_bytes(this->prf, idx, &chunk);
|
||||
|
||||
octets = chunk_cat("ccm", ike_sa_init, nonce, chunk);
|
||||
DBG3(DBG_IKE, "octets = message + nonce + prf(Sk_px, IDx') %B", &octets);
|
||||
return octets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
|
||||
*/
|
||||
#define IKEV2_KEY_PAD "Key Pad for IKEv2"
|
||||
#define IKEV2_KEY_PAD_LENGTH 17
|
||||
|
||||
METHOD(keymat_v2_t, get_psk_sig, chunk_t,
|
||||
private_keymat_v2_t *this, bool verify, chunk_t ike_sa_init,
|
||||
chunk_t nonce, chunk_t secret, identification_t *id, char reserved[3])
|
||||
{
|
||||
chunk_t key_pad, key, sig, octets;
|
||||
|
||||
if (!secret.len)
|
||||
{ /* EAP uses SK_p if no MSK has been established */
|
||||
secret = verify ? this->skp_verify : this->skp_build;
|
||||
}
|
||||
octets = get_auth_octets(this, verify, ike_sa_init, nonce, id, reserved);
|
||||
/* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */
|
||||
key_pad = chunk_create(IKEV2_KEY_PAD, IKEV2_KEY_PAD_LENGTH);
|
||||
this->prf->set_key(this->prf, secret);
|
||||
this->prf->allocate_bytes(this->prf, key_pad, &key);
|
||||
this->prf->set_key(this->prf, key);
|
||||
this->prf->allocate_bytes(this->prf, octets, &sig);
|
||||
DBG4(DBG_IKE, "secret %B", &secret);
|
||||
DBG4(DBG_IKE, "prf(secret, keypad) %B", &key);
|
||||
DBG3(DBG_IKE, "AUTH = prf(prf(secret, keypad), octets) %B", &sig);
|
||||
chunk_free(&octets);
|
||||
chunk_free(&key);
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
METHOD(keymat_t, destroy, void,
|
||||
private_keymat_v2_t *this)
|
||||
{
|
||||
DESTROY_IF(this->aead_in);
|
||||
DESTROY_IF(this->aead_out);
|
||||
DESTROY_IF(this->prf);
|
||||
chunk_clear(&this->skd);
|
||||
chunk_clear(&this->skp_verify);
|
||||
chunk_clear(&this->skp_build);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
keymat_v2_t *keymat_v2_create(bool initiator)
|
||||
{
|
||||
private_keymat_v2_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.keymat = {
|
||||
.get_version = _get_version,
|
||||
.create_dh = _create_dh,
|
||||
.get_aead = _get_aead,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.derive_ike_keys = _derive_ike_keys,
|
||||
.derive_child_keys = _derive_child_keys,
|
||||
.get_skd = _get_skd,
|
||||
.get_auth_octets = _get_auth_octets,
|
||||
.get_psk_sig = _get_psk_sig,
|
||||
},
|
||||
.initiator = initiator,
|
||||
.prf_alg = PRF_UNDEFINED,
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Tobias Brunner
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup keymat_v2 keymat_v2
|
||||
* @{ @ingroup sa
|
||||
*/
|
||||
|
||||
#ifndef KEYMAT_V2_H_
|
||||
#define KEYMAT_V2_H_
|
||||
|
||||
#include <sa/keymat.h>
|
||||
|
||||
typedef struct keymat_v2_t keymat_v2_t;
|
||||
|
||||
/**
|
||||
* Derivation and management of sensitive keying material, IKEv2 variant.
|
||||
*/
|
||||
struct keymat_v2_t {
|
||||
|
||||
/**
|
||||
* Implements keymat_t.
|
||||
*/
|
||||
keymat_t keymat;
|
||||
|
||||
/**
|
||||
* Derive keys for the IKE_SA.
|
||||
*
|
||||
* These keys are not handed out, but are used by the associated signers,
|
||||
* crypters and authentication functions.
|
||||
*
|
||||
* @param proposal selected algorithms
|
||||
* @param dh diffie hellman key allocated by create_dh()
|
||||
* @param nonce_i initiators nonce value
|
||||
* @param nonce_r responders nonce value
|
||||
* @param id IKE_SA identifier
|
||||
* @param rekey_prf PRF of old SA if rekeying, PRF_UNDEFINED otherwise
|
||||
* @param rekey_sdk SKd of old SA if rekeying
|
||||
* @return TRUE on success
|
||||
*/
|
||||
bool (*derive_ike_keys)(keymat_v2_t *this, proposal_t *proposal,
|
||||
diffie_hellman_t *dh, chunk_t nonce_i,
|
||||
chunk_t nonce_r, ike_sa_id_t *id,
|
||||
pseudo_random_function_t rekey_function,
|
||||
chunk_t rekey_skd);
|
||||
|
||||
/**
|
||||
* Derive keys for a CHILD_SA.
|
||||
*
|
||||
* The keys for the CHILD_SA are allocated in the integ and encr chunks.
|
||||
* An implementation might hand out encrypted keys only, which are
|
||||
* decrypted in the kernel before use.
|
||||
* If no PFS is used for the CHILD_SA, dh can be NULL.
|
||||
*
|
||||
* @param proposal selected algorithms
|
||||
* @param dh diffie hellman key allocated by create_dh(), or NULL
|
||||
* @param nonce_i initiators nonce value
|
||||
* @param nonce_r responders nonce value
|
||||
* @param encr_i chunk to write initiators encryption key to
|
||||
* @param integ_i chunk to write initiators integrity key to
|
||||
* @param encr_r chunk to write responders encryption key to
|
||||
* @param integ_r chunk to write responders integrity key to
|
||||
* @return TRUE on success
|
||||
*/
|
||||
bool (*derive_child_keys)(keymat_v2_t *this,
|
||||
proposal_t *proposal, diffie_hellman_t *dh,
|
||||
chunk_t nonce_i, chunk_t nonce_r,
|
||||
chunk_t *encr_i, chunk_t *integ_i,
|
||||
chunk_t *encr_r, chunk_t *integ_r);
|
||||
/**
|
||||
* Get SKd to pass to derive_ikey_keys() during rekeying.
|
||||
*
|
||||
* @param skd chunk to write SKd to (internal data)
|
||||
* @return PRF function to derive keymat
|
||||
*/
|
||||
pseudo_random_function_t (*get_skd)(keymat_v2_t *this, chunk_t *skd);
|
||||
|
||||
/**
|
||||
* Generate octets to use for authentication procedure (RFC4306 2.15).
|
||||
*
|
||||
* This method creates the plain octets and is usually signed by a private
|
||||
* key. PSK and EAP authentication include a secret into the data, use
|
||||
* the get_psk_sig() method instead.
|
||||
*
|
||||
* @param verify TRUE to create for verfification, FALSE to sign
|
||||
* @param ike_sa_init encoded ike_sa_init message
|
||||
* @param nonce nonce value
|
||||
* @param id identity
|
||||
* @param reserved reserved bytes of id_payload
|
||||
* @return authentication octets
|
||||
*/
|
||||
chunk_t (*get_auth_octets)(keymat_v2_t *this, bool verify,
|
||||
chunk_t ike_sa_init, chunk_t nonce,
|
||||
identification_t *id, char reserved[3]);
|
||||
/**
|
||||
* Build the shared secret signature used for PSK and EAP authentication.
|
||||
*
|
||||
* This method wraps the get_auth_octets() method and additionally
|
||||
* includes the secret into the signature. If no secret is given, SK_p is
|
||||
* used as secret (used for EAP methods without MSK).
|
||||
*
|
||||
* @param verify TRUE to create for verfification, FALSE to sign
|
||||
* @param ike_sa_init encoded ike_sa_init message
|
||||
* @param nonce nonce value
|
||||
* @param secret optional secret to include into signature
|
||||
* @param id identity
|
||||
* @param reserved reserved bytes of id_payload
|
||||
* @return signature octets
|
||||
*/
|
||||
chunk_t (*get_psk_sig)(keymat_v2_t *this, bool verify, chunk_t ike_sa_init,
|
||||
chunk_t nonce, chunk_t secret,
|
||||
identification_t *id, char reserved[3]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a keymat instance.
|
||||
*
|
||||
* @param initiator TRUE if we are the initiator
|
||||
* @return keymat instance
|
||||
*/
|
||||
keymat_v2_t *keymat_v2_create(bool initiator);
|
||||
|
||||
#endif /** KEYMAT_V2_H_ @}*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup task_manager_v2 task_manager_v2
|
||||
* @{ @ingroup sa
|
||||
*/
|
||||
|
||||
#ifndef TASK_MANAGER_V2_H_
|
||||
#define TASK_MANAGER_V2_H_
|
||||
|
||||
typedef struct task_manager_v2_t task_manager_v2_t;
|
||||
|
||||
#include <sa/task_manager.h>
|
||||
|
||||
/**
|
||||
* Task manager, IKEv2 variant.
|
||||
*/
|
||||
struct task_manager_v2_t {
|
||||
|
||||
/**
|
||||
* Implements task_manager_t.
|
||||
*/
|
||||
task_manager_t task_manager;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an instance of the task manager.
|
||||
*
|
||||
* @param ike_sa IKE_SA to manage.
|
||||
*/
|
||||
task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa);
|
||||
|
||||
#endif /** TASK_MANAGER_V2_H_ @}*/
|
||||
+14
-11
@@ -18,6 +18,7 @@
|
||||
#include "child_create.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev2/keymat_v2.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <credentials/certificates/x509.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
@@ -109,7 +110,7 @@ struct private_child_create_t {
|
||||
/**
|
||||
* IKE_SAs keymat
|
||||
*/
|
||||
keymat_t *keymat;
|
||||
keymat_v2_t *keymat;
|
||||
|
||||
/**
|
||||
* mode the new CHILD_SA uses (transport/tunnel/beet)
|
||||
@@ -526,18 +527,18 @@ static void build_payloads(private_child_create_t *this, message_t *message)
|
||||
/* add SA payload */
|
||||
if (this->initiator)
|
||||
{
|
||||
sa_payload = sa_payload_create_from_proposal_list(this->proposals);
|
||||
sa_payload = sa_payload_create_from_proposals_v2(this->proposals);
|
||||
}
|
||||
else
|
||||
{
|
||||
sa_payload = sa_payload_create_from_proposal(this->proposal);
|
||||
sa_payload = sa_payload_create_from_proposal_v2(this->proposal);
|
||||
}
|
||||
message->add_payload(message, (payload_t*)sa_payload);
|
||||
|
||||
/* add nonce payload if not in IKE_AUTH */
|
||||
if (message->get_exchange_type(message) == CREATE_CHILD_SA)
|
||||
{
|
||||
nonce_payload = nonce_payload_create();
|
||||
nonce_payload = nonce_payload_create(NONCE);
|
||||
nonce_payload->set_nonce(nonce_payload, this->my_nonce);
|
||||
message->add_payload(message, (payload_t*)nonce_payload);
|
||||
}
|
||||
@@ -545,7 +546,8 @@ static void build_payloads(private_child_create_t *this, message_t *message)
|
||||
/* diffie hellman exchange, if PFS enabled */
|
||||
if (this->dh)
|
||||
{
|
||||
ke_payload = ke_payload_create_from_diffie_hellman(this->dh);
|
||||
ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE,
|
||||
this->dh);
|
||||
message->add_payload(message, (payload_t*)ke_payload);
|
||||
}
|
||||
|
||||
@@ -680,7 +682,8 @@ static void process_payloads(private_child_create_t *this, message_t *message)
|
||||
if (!this->initiator)
|
||||
{
|
||||
this->dh_group = ke_payload->get_dh_group_number(ke_payload);
|
||||
this->dh = this->keymat->create_dh(this->keymat, this->dh_group);
|
||||
this->dh = this->keymat->keymat.create_dh(
|
||||
&this->keymat->keymat, this->dh_group);
|
||||
}
|
||||
if (this->dh)
|
||||
{
|
||||
@@ -812,7 +815,8 @@ METHOD(task_t, build_i, status_t,
|
||||
|
||||
if (this->dh_group != MODP_NONE)
|
||||
{
|
||||
this->dh = this->keymat->create_dh(this->keymat, this->dh_group);
|
||||
this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
|
||||
this->dh_group);
|
||||
}
|
||||
|
||||
if (this->config->use_ipcomp(this->config))
|
||||
@@ -1209,7 +1213,7 @@ METHOD(child_create_t, get_lower_nonce, chunk_t,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_child_create_t *this)
|
||||
{
|
||||
return CHILD_CREATE;
|
||||
return TASK_CHILD_CREATE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
@@ -1234,7 +1238,7 @@ METHOD(task_t, migrate, void,
|
||||
}
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->keymat = ike_sa->get_keymat(ike_sa);
|
||||
this->keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
|
||||
this->proposal = NULL;
|
||||
this->proposals = NULL;
|
||||
this->tsi = NULL;
|
||||
@@ -1304,7 +1308,7 @@ child_create_t *child_create_create(ike_sa_t *ike_sa,
|
||||
.packet_tsi = tsi ? tsi->clone(tsi) : NULL,
|
||||
.packet_tsr = tsr ? tsr->clone(tsr) : NULL,
|
||||
.dh_group = MODP_NONE,
|
||||
.keymat = ike_sa->get_keymat(ike_sa),
|
||||
.keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa),
|
||||
.mode = MODE_TUNNEL,
|
||||
.tfcv3 = TRUE,
|
||||
.ipcomp = IPCOMP_NONE,
|
||||
@@ -1317,7 +1321,6 @@ child_create_t *child_create_create(ike_sa_t *ike_sa,
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
this->initiator = TRUE;
|
||||
config->get_ref(config);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -25,11 +25,11 @@ typedef struct child_create_t child_create_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
#include <config/child_cfg.h>
|
||||
|
||||
/**
|
||||
* Task of type CHILD_CREATE, established a new CHILD_SA.
|
||||
* Task of type TASK_CHILD_CREATE, established a new CHILD_SA.
|
||||
*
|
||||
* This task may be included in the IKE_AUTH message or in a separate
|
||||
* CREATE_CHILD_SA exchange.
|
||||
+32
-13
@@ -61,6 +61,11 @@ struct private_child_delete_t {
|
||||
*/
|
||||
bool rekeyed;
|
||||
|
||||
/**
|
||||
* CHILD_SA already expired?
|
||||
*/
|
||||
bool expired;
|
||||
|
||||
/**
|
||||
* CHILD_SAs which get deleted
|
||||
*/
|
||||
@@ -87,7 +92,7 @@ static void build_payloads(private_child_delete_t *this, message_t *message)
|
||||
case PROTO_ESP:
|
||||
if (esp == NULL)
|
||||
{
|
||||
esp = delete_payload_create(PROTO_ESP);
|
||||
esp = delete_payload_create(DELETE, PROTO_ESP);
|
||||
message->add_payload(message, (payload_t*)esp);
|
||||
}
|
||||
esp->add_spi(esp, spi);
|
||||
@@ -97,7 +102,7 @@ static void build_payloads(private_child_delete_t *this, message_t *message)
|
||||
case PROTO_AH:
|
||||
if (ah == NULL)
|
||||
{
|
||||
ah = delete_payload_create(PROTO_AH);
|
||||
ah = delete_payload_create(DELETE, PROTO_AH);
|
||||
message->add_payload(message, (payload_t*)ah);
|
||||
}
|
||||
ah->add_spi(ah, spi);
|
||||
@@ -247,16 +252,29 @@ static void log_children(private_child_delete_t *this)
|
||||
enumerator = this->child_sas->create_enumerator(this->child_sas);
|
||||
while (enumerator->enumerate(enumerator, (void**)&child_sa))
|
||||
{
|
||||
child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in);
|
||||
child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out);
|
||||
if (this->expired)
|
||||
{
|
||||
DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
|
||||
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
|
||||
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
|
||||
ntohl(child_sa->get_spi(child_sa, TRUE)),
|
||||
ntohl(child_sa->get_spi(child_sa, FALSE)),
|
||||
child_sa->get_traffic_selectors(child_sa, TRUE),
|
||||
child_sa->get_traffic_selectors(child_sa, FALSE));
|
||||
}
|
||||
else
|
||||
{
|
||||
child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in);
|
||||
child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out);
|
||||
|
||||
DBG0(DBG_IKE, "closing CHILD_SA %s{%d} "
|
||||
"with SPIs %.8x_i (%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R",
|
||||
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
|
||||
ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
|
||||
ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
|
||||
child_sa->get_traffic_selectors(child_sa, TRUE),
|
||||
child_sa->get_traffic_selectors(child_sa, FALSE));
|
||||
DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs %.8x_i "
|
||||
"(%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R",
|
||||
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
|
||||
ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
|
||||
ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
|
||||
child_sa->get_traffic_selectors(child_sa, TRUE),
|
||||
child_sa->get_traffic_selectors(child_sa, FALSE));
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
@@ -324,7 +342,7 @@ METHOD(task_t, build_r, status_t,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_child_delete_t *this)
|
||||
{
|
||||
return CHILD_DELETE;
|
||||
return TASK_CHILD_DELETE;
|
||||
}
|
||||
|
||||
METHOD(child_delete_t , get_child, child_sa_t*,
|
||||
@@ -356,7 +374,7 @@ METHOD(task_t, destroy, void,
|
||||
* Described in header.
|
||||
*/
|
||||
child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
|
||||
u_int32_t spi)
|
||||
u_int32_t spi, bool expired)
|
||||
{
|
||||
private_child_delete_t *this;
|
||||
|
||||
@@ -373,6 +391,7 @@ child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
|
||||
.child_sas = linked_list_create(),
|
||||
.protocol = protocol,
|
||||
.spi = spi,
|
||||
.expired = expired,
|
||||
);
|
||||
|
||||
if (protocol != PROTO_NONE)
|
||||
@@ -25,7 +25,7 @@ typedef struct child_delete_t child_delete_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
#include <sa/child_sa.h>
|
||||
|
||||
/**
|
||||
@@ -52,9 +52,10 @@ struct child_delete_t {
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param protocol protocol of CHILD_SA to delete, PROTO_NONE as responder
|
||||
* @param spi inbound SPI of CHILD_SA to delete
|
||||
* @param expired TRUE if CHILD_SA already expired
|
||||
* @return child_delete task to handle by the task_manager
|
||||
*/
|
||||
child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
|
||||
u_int32_t spi);
|
||||
u_int32_t spi, bool expired);
|
||||
|
||||
#endif /** CHILD_DELETE_H_ @}*/
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <sa/tasks/child_create.h>
|
||||
#include <sa/tasks/child_delete.h>
|
||||
#include <sa/ikev2/tasks/child_create.h>
|
||||
#include <sa/ikev2/tasks/child_delete.h>
|
||||
#include <processing/jobs/rekey_child_sa_job.h>
|
||||
#include <processing/jobs/rekey_ike_sa_job.h>
|
||||
|
||||
@@ -153,16 +153,16 @@ METHOD(task_t, build_i, status_t,
|
||||
config = this->child_sa->get_config(this->child_sa);
|
||||
|
||||
/* we just need the rekey notify ... */
|
||||
notify = notify_payload_create_from_protocol_and_type(this->protocol,
|
||||
REKEY_SA);
|
||||
notify = notify_payload_create_from_protocol_and_type(NOTIFY,
|
||||
this->protocol, REKEY_SA);
|
||||
notify->set_spi(notify, this->spi);
|
||||
message->add_payload(message, (payload_t*)notify);
|
||||
|
||||
/* ... our CHILD_CREATE task does the hard work for us. */
|
||||
if (!this->child_create)
|
||||
{
|
||||
this->child_create = child_create_create(this->ike_sa, config, TRUE,
|
||||
NULL, NULL);
|
||||
this->child_create = child_create_create(this->ike_sa,
|
||||
config->get_ref(config), TRUE, NULL, NULL);
|
||||
}
|
||||
reqid = this->child_sa->get_reqid(this->child_sa);
|
||||
this->child_create->use_reqid(this->child_create, reqid);
|
||||
@@ -224,7 +224,7 @@ static child_sa_t *handle_collision(private_child_rekey_t *this)
|
||||
{
|
||||
child_sa_t *to_delete;
|
||||
|
||||
if (this->collision->get_type(this->collision) == CHILD_REKEY)
|
||||
if (this->collision->get_type(this->collision) == TASK_CHILD_REKEY)
|
||||
{
|
||||
chunk_t this_nonce, other_nonce;
|
||||
private_child_rekey_t *other = (private_child_rekey_t*)this->collision;
|
||||
@@ -311,7 +311,7 @@ METHOD(task_t, process_i, status_t,
|
||||
/* establishing new child failed, reuse old. but not when we
|
||||
* received a delete in the meantime */
|
||||
if (!(this->collision &&
|
||||
this->collision->get_type(this->collision) == CHILD_DELETE))
|
||||
this->collision->get_type(this->collision) == TASK_CHILD_DELETE))
|
||||
{
|
||||
job_t *job;
|
||||
u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
|
||||
@@ -352,7 +352,7 @@ METHOD(task_t, process_i, status_t,
|
||||
protocol = to_delete->get_protocol(to_delete);
|
||||
|
||||
/* rekeying done, delete the obsolete CHILD_SA using a subtask */
|
||||
this->child_delete = child_delete_create(this->ike_sa, protocol, spi);
|
||||
this->child_delete = child_delete_create(this->ike_sa, protocol, spi, FALSE);
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i_delete;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i_delete;
|
||||
|
||||
@@ -362,7 +362,7 @@ METHOD(task_t, process_i, status_t,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_child_rekey_t *this)
|
||||
{
|
||||
return CHILD_REKEY;
|
||||
return TASK_CHILD_REKEY;
|
||||
}
|
||||
|
||||
METHOD(child_rekey_t, collide, void,
|
||||
@@ -370,7 +370,7 @@ METHOD(child_rekey_t, collide, void,
|
||||
{
|
||||
/* the task manager only detects exchange collision, but not if
|
||||
* the collision is for the same child. we check it here. */
|
||||
if (other->get_type(other) == CHILD_REKEY)
|
||||
if (other->get_type(other) == TASK_CHILD_REKEY)
|
||||
{
|
||||
private_child_rekey_t *rekey = (private_child_rekey_t*)other;
|
||||
if (rekey->child_sa != this->child_sa)
|
||||
@@ -380,7 +380,7 @@ METHOD(child_rekey_t, collide, void,
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (other->get_type(other) == CHILD_DELETE)
|
||||
else if (other->get_type(other) == TASK_CHILD_DELETE)
|
||||
{
|
||||
child_delete_t *del = (child_delete_t*)other;
|
||||
if (del->get_child(del) == this->child_create->get_child(this->child_create))
|
||||
@@ -403,8 +403,8 @@ METHOD(child_rekey_t, collide, void,
|
||||
other->destroy(other);
|
||||
return;
|
||||
}
|
||||
DBG1(DBG_IKE, "detected %N collision with %N", task_type_names, CHILD_REKEY,
|
||||
task_type_names, other->get_type(other));
|
||||
DBG1(DBG_IKE, "detected %N collision with %N", task_type_names,
|
||||
TASK_CHILD_REKEY, task_type_names, other->get_type(other));
|
||||
DESTROY_IF(this->collision);
|
||||
this->collision = other;
|
||||
}
|
||||
@@ -462,7 +462,7 @@ child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, protocol_id_t protocol,
|
||||
.protocol = protocol,
|
||||
.spi = spi,
|
||||
);
|
||||
|
||||
|
||||
if (protocol != PROTO_NONE)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
@@ -26,10 +26,10 @@ typedef struct child_rekey_t child_rekey_t;
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/child_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type CHILD_REKEY, rekey an established CHILD_SA.
|
||||
* Task of type TASK_CHILD_REKEY, rekey an established CHILD_SA.
|
||||
*/
|
||||
struct child_rekey_t {
|
||||
|
||||
@@ -51,7 +51,7 @@ struct child_rekey_t {
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new CHILD_REKEY task.
|
||||
* Create a new TASK_CHILD_REKEY task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param protocol protocol of CHILD_SA to rekey, PROTO_NONE as responder
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <encoding/payloads/auth_payload.h>
|
||||
#include <encoding/payloads/eap_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
#include <sa/authenticators/eap_authenticator.h>
|
||||
#include <sa/ikev2/authenticators/eap_authenticator.h>
|
||||
|
||||
typedef struct private_ike_auth_t private_ike_auth_t;
|
||||
|
||||
@@ -270,8 +270,10 @@ static bool load_cfg_candidates(private_ike_auth_t *this)
|
||||
my_id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
|
||||
DBG1(DBG_CFG, "looking for peer configs matching %H[%Y]...%H[%Y]",
|
||||
me, my_id, other, other_id);
|
||||
enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
|
||||
me, other, my_id, other_id);
|
||||
me, other, my_id, other_id, IKEV2);
|
||||
while (enumerator->enumerate(enumerator, &peer_cfg))
|
||||
{
|
||||
peer_cfg->get_ref(peer_cfg);
|
||||
@@ -1033,7 +1035,7 @@ peer_auth_failed:
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_ike_auth_t *this)
|
||||
{
|
||||
return IKE_AUTHENTICATE;
|
||||
return TASK_IKE_AUTH;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
@@ -1104,4 +1106,3 @@ ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator)
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ typedef struct ike_auth_t ike_auth_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type ike_auth, authenticates an IKE_SA using authenticators.
|
||||
@@ -46,7 +46,7 @@ struct ike_auth_t {
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new task of type IKE_AUTHENTICATE.
|
||||
* Create a new task of type TASK_IKE_AUTH.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if task is the initiator of an exchange
|
||||
+1
-2
@@ -124,7 +124,7 @@ METHOD(task_t, process_i, status_t,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_ike_auth_lifetime_t *this)
|
||||
{
|
||||
return IKE_AUTH_LIFETIME;
|
||||
return TASK_IKE_AUTH_LIFETIME;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
@@ -170,4 +170,3 @@ ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator)
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
+4
-4
@@ -25,10 +25,10 @@ typedef struct ike_auth_lifetime_t ike_auth_lifetime_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type IKE_AUTH_LIFETIME, implements RFC4478.
|
||||
* Task of type TASK_IKE_AUTH_LIFETIME, implements RFC4478.
|
||||
*
|
||||
* This task exchanges lifetimes for IKE_AUTH to force a client to
|
||||
* reauthenticate before the responders lifetime reaches the limit.
|
||||
@@ -42,7 +42,7 @@ struct ike_auth_lifetime_t {
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new IKE_AUTH_LIFETIME task.
|
||||
* Create a new TASK_IKE_AUTH_LIFETIME task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if taks is initiated by us
|
||||
@@ -50,4 +50,4 @@ struct ike_auth_lifetime_t {
|
||||
*/
|
||||
ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** IKE_MOBIKE_H_ @}*/
|
||||
#endif /** IKE_AUTH_LIFETIME_H_ @}*/
|
||||
+5
-6
@@ -62,14 +62,14 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this,
|
||||
|
||||
if (!this->ike_sa->supports_extension(this->ike_sa, EXT_HASH_AND_URL))
|
||||
{
|
||||
return cert_payload_create_from_cert(cert);
|
||||
return cert_payload_create_from_cert(CERTIFICATE, cert);
|
||||
}
|
||||
|
||||
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
|
||||
if (!hasher)
|
||||
{
|
||||
DBG1(DBG_IKE, "unable to use hash-and-url: sha1 not supported");
|
||||
return cert_payload_create_from_cert(cert);
|
||||
return cert_payload_create_from_cert(CERTIFICATE, cert);
|
||||
}
|
||||
|
||||
if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoded))
|
||||
@@ -91,7 +91,7 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this,
|
||||
}
|
||||
else
|
||||
{
|
||||
payload = cert_payload_create_from_cert(cert);
|
||||
payload = cert_payload_create_from_cert(CERTIFICATE, cert);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
chunk_free(&hash);
|
||||
@@ -154,7 +154,7 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message)
|
||||
{
|
||||
if (type == AUTH_RULE_IM_CERT)
|
||||
{
|
||||
payload = cert_payload_create_from_cert(cert);
|
||||
payload = cert_payload_create_from_cert(CERTIFICATE, cert);
|
||||
if (payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "sending issuer cert \"%Y\"",
|
||||
@@ -207,7 +207,7 @@ METHOD(task_t, process_i, status_t,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_ike_cert_post_t *this)
|
||||
{
|
||||
return IKE_CERT_POST;
|
||||
return TASK_IKE_CERT_POST;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
@@ -254,4 +254,3 @@ ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator)
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ typedef struct ike_cert_post_t ike_cert_post_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type ike_cert_post, certificate processing after authentication.
|
||||
@@ -479,7 +479,7 @@ METHOD(task_t, process_i, status_t,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_ike_cert_pre_t *this)
|
||||
{
|
||||
return IKE_CERT_PRE;
|
||||
return TASK_IKE_CERT_PRE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
@@ -25,7 +25,7 @@ typedef struct ike_cert_pre_t ike_cert_pre_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type ike_cert_post, certificate processing before authentication.
|
||||
@@ -98,7 +98,8 @@ static configuration_attribute_t *build_vip(host_t *vip)
|
||||
chunk = chunk_cata("cc", chunk, prefix);
|
||||
}
|
||||
}
|
||||
return configuration_attribute_create_value(type, chunk);
|
||||
return configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE,
|
||||
type, chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,11 +129,11 @@ static void handle_attribute(private_ike_config_t *this,
|
||||
/* and pass it to the handle function */
|
||||
handler = hydra->attributes->handle(hydra->attributes,
|
||||
this->ike_sa->get_other_id(this->ike_sa), handler,
|
||||
ca->get_type(ca), ca->get_value(ca));
|
||||
ca->get_type(ca), ca->get_chunk(ca));
|
||||
if (handler)
|
||||
{
|
||||
this->ike_sa->add_configuration_attribute(this->ike_sa,
|
||||
handler, ca->get_type(ca), ca->get_value(ca));
|
||||
handler, ca->get_type(ca), ca->get_chunk(ca));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +154,7 @@ static void process_attribute(private_ike_config_t *this,
|
||||
/* fall */
|
||||
case INTERNAL_IP6_ADDRESS:
|
||||
{
|
||||
addr = ca->get_value(ca);
|
||||
addr = ca->get_chunk(ca);
|
||||
if (addr.len == 0)
|
||||
{
|
||||
ip = host_create_any(family);
|
||||
@@ -252,7 +253,7 @@ METHOD(task_t, build_i, status_t,
|
||||
}
|
||||
if (vip)
|
||||
{
|
||||
cp = cp_payload_create_type(CFG_REQUEST);
|
||||
cp = cp_payload_create_type(CONFIGURATION, CFG_REQUEST);
|
||||
cp->add_attribute(cp, build_vip(vip));
|
||||
}
|
||||
|
||||
@@ -266,10 +267,11 @@ METHOD(task_t, build_i, status_t,
|
||||
/* create configuration attribute */
|
||||
DBG2(DBG_IKE, "building %N attribute",
|
||||
configuration_attribute_type_names, type);
|
||||
ca = configuration_attribute_create_value(type, data);
|
||||
ca = configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE,
|
||||
type, data);
|
||||
if (!cp)
|
||||
{
|
||||
cp = cp_payload_create_type(CFG_REQUEST);
|
||||
cp = cp_payload_create_type(CONFIGURATION, CFG_REQUEST);
|
||||
}
|
||||
cp->add_attribute(cp, ca);
|
||||
|
||||
@@ -335,7 +337,7 @@ METHOD(task_t, build_r, status_t,
|
||||
DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", vip, id);
|
||||
this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip);
|
||||
|
||||
cp = cp_payload_create_type(CFG_REPLY);
|
||||
cp = cp_payload_create_type(CONFIGURATION, CFG_REPLY);
|
||||
cp->add_attribute(cp, build_vip(vip));
|
||||
}
|
||||
|
||||
@@ -346,12 +348,13 @@ METHOD(task_t, build_r, status_t,
|
||||
{
|
||||
if (!cp)
|
||||
{
|
||||
cp = cp_payload_create_type(CFG_REPLY);
|
||||
cp = cp_payload_create_type(CONFIGURATION, CFG_REPLY);
|
||||
}
|
||||
DBG2(DBG_IKE, "building %N attribute",
|
||||
configuration_attribute_type_names, type);
|
||||
cp->add_attribute(cp,
|
||||
configuration_attribute_create_value(type, value));
|
||||
configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE,
|
||||
type, value));
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
@@ -385,7 +388,7 @@ METHOD(task_t, process_i, status_t,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_ike_config_t *this)
|
||||
{
|
||||
return IKE_CONFIG;
|
||||
return TASK_IKE_CONFIG;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
@@ -440,4 +443,3 @@ ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator)
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -25,10 +25,10 @@ typedef struct ike_config_t ike_config_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type IKE_CONFIG, sets up a virtual IP and other
|
||||
* Task of type TASK_IKE_CONFIG, sets up a virtual IP and other
|
||||
* configurations for an IKE_SA.
|
||||
*/
|
||||
struct ike_config_t {
|
||||
@@ -65,7 +65,7 @@ METHOD(task_t, build_i, status_t,
|
||||
this->ike_sa->get_other_host(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
|
||||
delete_payload = delete_payload_create(PROTO_IKE);
|
||||
delete_payload = delete_payload_create(DELETE, PROTO_IKE);
|
||||
message->add_payload(message, (payload_t*)delete_payload);
|
||||
|
||||
if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING)
|
||||
@@ -149,7 +149,7 @@ METHOD(task_t, build_r, status_t,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_ike_delete_t *this)
|
||||
{
|
||||
return IKE_DELETE;
|
||||
return TASK_IKE_DELETE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
@@ -25,7 +25,7 @@ typedef struct ike_delete_t ike_delete_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type ike_delete, delete an IKE_SA.
|
||||
@@ -46,7 +46,7 @@ METHOD(task_t, return_success, status_t,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_ike_dpd_t *this)
|
||||
{
|
||||
return IKE_DPD;
|
||||
return TASK_IKE_DPD;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ typedef struct ike_dpd_t ike_dpd_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type ike_dpd, detects dead peers.
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev2/keymat_v2.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/ke_payload.h>
|
||||
@@ -68,7 +69,7 @@ struct private_ike_init_t {
|
||||
/**
|
||||
* Keymat derivation (from IKE_SA)
|
||||
*/
|
||||
keymat_t *keymat;
|
||||
keymat_v2_t *keymat;
|
||||
|
||||
/**
|
||||
* nonce chosen by us
|
||||
@@ -132,7 +133,7 @@ static void build_payloads(private_ike_init_t *this, message_t *message)
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
sa_payload = sa_payload_create_from_proposal_list(proposal_list);
|
||||
sa_payload = sa_payload_create_from_proposals_v2(proposal_list);
|
||||
proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
|
||||
}
|
||||
else
|
||||
@@ -142,13 +143,13 @@ static void build_payloads(private_ike_init_t *this, message_t *message)
|
||||
/* include SPI of new IKE_SA when we are rekeying */
|
||||
this->proposal->set_spi(this->proposal, id->get_responder_spi(id));
|
||||
}
|
||||
sa_payload = sa_payload_create_from_proposal(this->proposal);
|
||||
sa_payload = sa_payload_create_from_proposal_v2(this->proposal);
|
||||
}
|
||||
message->add_payload(message, (payload_t*)sa_payload);
|
||||
|
||||
nonce_payload = nonce_payload_create();
|
||||
nonce_payload = nonce_payload_create(NONCE);
|
||||
nonce_payload->set_nonce(nonce_payload, this->my_nonce);
|
||||
ke_payload = ke_payload_create_from_diffie_hellman(this->dh);
|
||||
ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE, this->dh);
|
||||
|
||||
if (this->old_sa)
|
||||
{ /* payload order differs if we are rekeying */
|
||||
@@ -197,8 +198,8 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
|
||||
this->dh_group = ke_payload->get_dh_group_number(ke_payload);
|
||||
if (!this->initiator)
|
||||
{
|
||||
this->dh = this->keymat->create_dh(this->keymat,
|
||||
this->dh_group);
|
||||
this->dh = this->keymat->keymat.create_dh(
|
||||
&this->keymat->keymat, this->dh_group);
|
||||
}
|
||||
if (this->dh)
|
||||
{
|
||||
@@ -243,7 +244,8 @@ METHOD(task_t, build_i, status_t,
|
||||
if (!this->dh)
|
||||
{
|
||||
this->dh_group = this->config->get_dh_group(this->config);
|
||||
this->dh = this->keymat->create_dh(this->keymat, this->dh_group);
|
||||
this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
|
||||
this->dh_group);
|
||||
if (!this->dh)
|
||||
{
|
||||
DBG1(DBG_IKE, "configured DH group %N not supported",
|
||||
@@ -327,7 +329,7 @@ METHOD(task_t, process_r, status_t,
|
||||
static bool derive_keys(private_ike_init_t *this,
|
||||
chunk_t nonce_i, chunk_t nonce_r)
|
||||
{
|
||||
keymat_t *old_keymat;
|
||||
keymat_v2_t *old_keymat;
|
||||
pseudo_random_function_t prf_alg = PRF_UNDEFINED;
|
||||
chunk_t skd = chunk_empty;
|
||||
ike_sa_id_t *id;
|
||||
@@ -336,7 +338,7 @@ static bool derive_keys(private_ike_init_t *this,
|
||||
if (this->old_sa)
|
||||
{
|
||||
/* rekeying: Include old SKd, use old PRF, apply SPI */
|
||||
old_keymat = this->old_sa->get_keymat(this->old_sa);
|
||||
old_keymat = (keymat_v2_t*)this->old_sa->get_keymat(this->old_sa);
|
||||
prf_alg = old_keymat->get_skd(old_keymat, &skd);
|
||||
if (this->initiator)
|
||||
{
|
||||
@@ -352,8 +354,8 @@ static bool derive_keys(private_ike_init_t *this,
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh,
|
||||
nonce_i, nonce_r, this->old_sa);
|
||||
charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, chunk_empty,
|
||||
nonce_i, nonce_r, this->old_sa, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -505,7 +507,7 @@ METHOD(task_t, process_i, status_t,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_ike_init_t *this)
|
||||
{
|
||||
return IKE_INIT;
|
||||
return TASK_IKE_INIT;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
@@ -515,12 +517,13 @@ METHOD(task_t, migrate, void,
|
||||
chunk_free(&this->other_nonce);
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->keymat = ike_sa->get_keymat(ike_sa);
|
||||
this->keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
|
||||
this->proposal = NULL;
|
||||
if (this->dh && this->dh->get_dh_group(this->dh) != this->dh_group)
|
||||
{ /* reset DH value only if group changed (INVALID_KE_PAYLOAD) */
|
||||
this->dh->destroy(this->dh);
|
||||
this->dh = this->keymat->create_dh(this->keymat, this->dh_group);
|
||||
this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
|
||||
this->dh_group);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,7 +571,7 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
|
||||
.ike_sa = ike_sa,
|
||||
.initiator = initiator,
|
||||
.dh_group = MODP_NONE,
|
||||
.keymat = ike_sa->get_keymat(ike_sa),
|
||||
.keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa),
|
||||
.old_sa = old_sa,
|
||||
);
|
||||
|
||||
@@ -25,10 +25,10 @@ typedef struct ike_init_t ike_init_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type IKE_INIT, creates an IKE_SA without authentication.
|
||||
* Task of type TASK_IKE_INIT, creates an IKE_SA without authentication.
|
||||
*
|
||||
* The authentication of is handle in the ike_auth task.
|
||||
*/
|
||||
@@ -48,7 +48,7 @@ struct ike_init_t {
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new IKE_INIT task.
|
||||
* Create a new TASK_IKE_INIT task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for (new one when rekeying)
|
||||
* @param initiator TRUE if task is the original initiator
|
||||
@@ -750,7 +750,7 @@ METHOD(ike_me_t, relay, void,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_ike_me_t *this)
|
||||
{
|
||||
return IKE_ME;
|
||||
return TASK_IKE_ME;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
@@ -25,10 +25,10 @@ typedef struct ike_me_t ike_me_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type IKE_ME, detects and handles IKE-ME extensions.
|
||||
* Task of type TASK_IKE_ME, detects and handles IKE-ME extensions.
|
||||
*
|
||||
* This tasks handles the ME_MEDIATION Notify exchange to setup a mediation
|
||||
* connection, allows to initiate mediated connections using ME_CONNECT
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include <hydra.h>
|
||||
#include <daemon.h>
|
||||
#include <sa/tasks/ike_natd.h>
|
||||
#include <sa/ikev2/tasks/ike_natd.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
|
||||
#define COOKIE2_SIZE 16
|
||||
@@ -54,7 +54,7 @@ struct private_ike_mobike_t {
|
||||
chunk_t cookie2;
|
||||
|
||||
/**
|
||||
* NAT discovery reusing the IKE_NATD task
|
||||
* NAT discovery reusing the TASK_IKE_NATD task
|
||||
*/
|
||||
ike_natd_t *natd;
|
||||
|
||||
@@ -584,7 +584,7 @@ METHOD(ike_mobike_t, is_probing, bool,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_ike_mobike_t *this)
|
||||
{
|
||||
return IKE_MOBIKE;
|
||||
return TASK_IKE_MOBIKE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
@@ -646,4 +646,3 @@ ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator)
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ typedef struct ike_mobike_t ike_mobike_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
#include <network/packet.h>
|
||||
|
||||
/**
|
||||
@@ -152,7 +152,7 @@ static notify_payload_t *build_natd_payload(private_ike_natd_t *this,
|
||||
{
|
||||
hash = generate_natd_hash(this, ike_sa_id, host);
|
||||
}
|
||||
notify = notify_payload_create();
|
||||
notify = notify_payload_create(NOTIFY);
|
||||
notify->set_notify_type(notify, type);
|
||||
notify->set_notification_data(notify, hash);
|
||||
chunk_free(&hash);
|
||||
@@ -385,7 +385,7 @@ METHOD(task_t, process_r, status_t,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_ike_natd_t *this)
|
||||
{
|
||||
return IKE_NATD;
|
||||
return TASK_IKE_NATD;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
@@ -25,7 +25,7 @@ typedef struct ike_natd_t ike_natd_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type ike_natd, detects NAT situation in IKE_SA_INIT exchange.
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "ike_reauth.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/tasks/ike_delete.h>
|
||||
#include <sa/ikev2/tasks/ike_delete.h>
|
||||
|
||||
|
||||
typedef struct private_ike_reauth_t private_ike_reauth_t;
|
||||
@@ -74,7 +74,12 @@ METHOD(task_t, process_i, status_t,
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE);
|
||||
new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
|
||||
this->ike_sa->get_version(this->ike_sa), TRUE);
|
||||
if (!new)
|
||||
{ /* shouldn't happen */
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
new->set_peer_cfg(new, peer_cfg);
|
||||
host = this->ike_sa->get_other_host(this->ike_sa);
|
||||
@@ -147,7 +152,7 @@ METHOD(task_t, process_i, status_t,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_ike_reauth_t *this)
|
||||
{
|
||||
return IKE_REAUTH;
|
||||
return TASK_IKE_REAUTH;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
@@ -187,4 +192,3 @@ ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa)
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ typedef struct ike_reauth_t ike_reauth_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type ike_reauth, reestablishes an IKE_SA.
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <sa/tasks/ike_init.h>
|
||||
#include <sa/tasks/ike_delete.h>
|
||||
#include <sa/ikev2/tasks/ike_init.h>
|
||||
#include <sa/ikev2/tasks/ike_delete.h>
|
||||
#include <processing/jobs/delete_ike_sa_job.h>
|
||||
#include <processing/jobs/rekey_ike_sa_job.h>
|
||||
|
||||
@@ -52,7 +52,7 @@ struct private_ike_rekey_t {
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* the IKE_INIT task which is reused to simplify rekeying
|
||||
* the TASK_IKE_INIT task which is reused to simplify rekeying
|
||||
*/
|
||||
ike_init_t *ike_init;
|
||||
|
||||
@@ -123,15 +123,20 @@ METHOD(task_t, process_i_delete, status_t,
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_ike_rekey_t *this, message_t *message)
|
||||
{
|
||||
ike_version_t version;
|
||||
peer_cfg_t *peer_cfg;
|
||||
host_t *other_host;
|
||||
|
||||
/* create new SA only on first try */
|
||||
if (this->new_sa == NULL)
|
||||
{
|
||||
this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
|
||||
TRUE);
|
||||
|
||||
version = this->ike_sa->get_version(this->ike_sa);
|
||||
this->new_sa = charon->ike_sa_manager->checkout_new(
|
||||
charon->ike_sa_manager, version, TRUE);
|
||||
if (!this->new_sa)
|
||||
{ /* shouldn't happen */
|
||||
return FAILED;
|
||||
}
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
other_host = this->ike_sa->get_other_host(this->ike_sa);
|
||||
this->new_sa->set_peer_cfg(this->new_sa, peer_cfg);
|
||||
@@ -176,7 +181,11 @@ METHOD(task_t, process_r, status_t,
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
|
||||
FALSE);
|
||||
this->ike_sa->get_version(this->ike_sa), FALSE);
|
||||
if (!this->new_sa)
|
||||
{ /* shouldn't happen */
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
this->new_sa->set_peer_cfg(this->new_sa, peer_cfg);
|
||||
@@ -230,8 +239,8 @@ METHOD(task_t, process_i, status_t,
|
||||
case FAILED:
|
||||
/* rekeying failed, fallback to old SA */
|
||||
if (!(this->collision && (
|
||||
this->collision->get_type(this->collision) == IKE_DELETE ||
|
||||
this->collision->get_type(this->collision) == IKE_REAUTH)))
|
||||
this->collision->get_type(this->collision) == TASK_IKE_DELETE ||
|
||||
this->collision->get_type(this->collision) == TASK_IKE_REAUTH)))
|
||||
{
|
||||
job_t *job;
|
||||
u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
|
||||
@@ -253,7 +262,7 @@ METHOD(task_t, process_i, status_t,
|
||||
|
||||
/* check for collisions */
|
||||
if (this->collision &&
|
||||
this->collision->get_type(this->collision) == IKE_REKEY)
|
||||
this->collision->get_type(this->collision) == TASK_IKE_REKEY)
|
||||
{
|
||||
private_ike_rekey_t *other = (private_ike_rekey_t*)this->collision;
|
||||
|
||||
@@ -323,14 +332,14 @@ METHOD(task_t, process_i, status_t,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_ike_rekey_t *this)
|
||||
{
|
||||
return IKE_REKEY;
|
||||
return TASK_IKE_REKEY;
|
||||
}
|
||||
|
||||
METHOD(ike_rekey_t, collide, void,
|
||||
private_ike_rekey_t* this, task_t *other)
|
||||
{
|
||||
DBG1(DBG_IKE, "detected %N collision with %N", task_type_names, IKE_REKEY,
|
||||
task_type_names, other->get_type(other));
|
||||
DBG1(DBG_IKE, "detected %N collision with %N", task_type_names,
|
||||
TASK_IKE_REKEY, task_type_names, other->get_type(other));
|
||||
DESTROY_IF(this->collision);
|
||||
this->collision = other;
|
||||
}
|
||||
@@ -25,10 +25,10 @@ typedef struct ike_rekey_t ike_rekey_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type IKE_REKEY, rekey an established IKE_SA.
|
||||
* Task of type TASK_IKE_REKEY, rekey an established IKE_SA.
|
||||
*/
|
||||
struct ike_rekey_t {
|
||||
|
||||
@@ -50,11 +50,11 @@ struct ike_rekey_t {
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new IKE_REKEY task.
|
||||
* Create a new TASK_IKE_REKEY task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE for initiator, FALSE for responder
|
||||
* @return IKE_REKEY task to handle by the task_manager
|
||||
* @return TASK_IKE_REKEY task to handle by the task_manager
|
||||
*/
|
||||
ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
@@ -57,7 +57,8 @@ METHOD(task_t, build, status_t,
|
||||
{
|
||||
vendor_id_payload_t *vid;
|
||||
|
||||
vid = vendor_id_payload_create_data(chunk_clone(strongswan_vid));
|
||||
vid = vendor_id_payload_create_data(VENDOR_ID,
|
||||
chunk_clone(strongswan_vid));
|
||||
message->add_payload(message, &vid->payload_interface);
|
||||
}
|
||||
|
||||
@@ -106,7 +107,7 @@ METHOD(task_t, migrate, void,
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_ike_vendor_t *this)
|
||||
{
|
||||
return IKE_VENDOR;
|
||||
return TASK_IKE_VENDOR;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
@@ -138,4 +139,3 @@ ike_vendor_t *ike_vendor_create(ike_sa_t *ike_sa, bool initiator)
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ typedef struct ike_vendor_t ike_vendor_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Vendor ID processing task.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user