diff options
author | Martin Willi <martin@revosec.ch> | 2011-12-06 13:38:27 +0100 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2012-03-20 17:31:13 +0100 |
commit | c64a4b4f8e44cd02b6fae769ecea69b142fc141d (patch) | |
tree | 65ea74daa684b94b30e971d04139a7e847cea8b6 | |
parent | 9ad5b8fa951c294f3f79ffe701cac712a6cf18df (diff) | |
download | strongswan-c64a4b4f8e44cd02b6fae769ecea69b142fc141d.tar.bz2 strongswan-c64a4b4f8e44cd02b6fae769ecea69b142fc141d.tar.xz |
Implemented post-authentication certificate handling for IKEv1
-rw-r--r-- | src/libcharon/Makefile.am | 1 | ||||
-rw-r--r-- | src/libcharon/sa/ike_sa.c | 3 | ||||
-rwxr-xr-x | src/libcharon/sa/task_manager_v1.c | 5 | ||||
-rwxr-xr-x | src/libcharon/sa/tasks/ike_cert_post_v1.c | 346 | ||||
-rw-r--r-- | src/libcharon/sa/tasks/ike_cert_post_v1.h | 53 |
5 files changed, 407 insertions, 1 deletions
diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index d36b5a506..d9e5a54b2 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -84,6 +84,7 @@ sa/tasks/ike_auth.c sa/tasks/ike_auth.h \ sa/tasks/ike_cert_pre.c sa/tasks/ike_cert_pre.h \ sa/tasks/ike_cert_post.c sa/tasks/ike_cert_post.h \ sa/tasks/ike_cert_pre_v1.c sa/tasks/ike_cert_pre_v1.h \ +sa/tasks/ike_cert_post_v1.c sa/tasks/ike_cert_post_v1.h \ sa/tasks/ike_config.c sa/tasks/ike_config.h \ sa/tasks/ike_delete.c sa/tasks/ike_delete.h \ sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 96cbcf10a..47aadc108 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -37,6 +37,7 @@ #include <sa/tasks/ike_cert_pre.h> #include <sa/tasks/ike_cert_pre_v1.h> #include <sa/tasks/ike_cert_post.h> +#include <sa/tasks/ike_cert_post_v1.h> #include <sa/tasks/ike_rekey.h> #include <sa/tasks/ike_reauth.h> #include <sa/tasks/ike_delete.h> @@ -1127,6 +1128,8 @@ METHOD(ike_sa_t, initiate, status_t, this->task_manager->queue_task(this->task_manager, task); task = (task_t*)main_mode_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_cert_post_v1_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_natd_v1_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); } diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 0843db51e..3d8229c05 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -25,7 +25,7 @@ #include <sa/tasks/ike_natd_v1.h> #include <sa/tasks/ike_vendor_v1.h> #include <sa/tasks/ike_cert_pre_v1.h> -#include <sa/tasks/ike_cert_post.h> +#include <sa/tasks/ike_cert_post_v1.h> #include <processing/jobs/retransmit_job.h> #include <processing/jobs/delete_ike_sa_job.h> @@ -270,6 +270,7 @@ METHOD(task_manager_t, initiate, status_t, if (activate_task(this, TASK_MAIN_MODE)) { exchange = ID_PROT; + activate_task(this, TASK_IKE_CERT_POST_V1); activate_task(this, TASK_IKE_NATD_V1); } break; @@ -506,6 +507,8 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)main_mode_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_cert_post_v1_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)ike_natd_v1_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); break; diff --git a/src/libcharon/sa/tasks/ike_cert_post_v1.c b/src/libcharon/sa/tasks/ike_cert_post_v1.c new file mode 100755 index 000000000..517f8c1bf --- /dev/null +++ b/src/libcharon/sa/tasks/ike_cert_post_v1.c @@ -0,0 +1,346 @@ +/* + * 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 "ike_cert_post_v1.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_ike_cert_post_v1_t private_ike_cert_post_v1_t; + +/** + * Private members of a ike_cert_post_v1_t task. + */ +struct private_ike_cert_post_v1_t { + + /** + * Public methods and task_t interface. + */ + ike_cert_post_v1_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_ike_cert_post_v1_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_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: + use = TRUE; + break; + default: + break; + } + break; + } + } + enumerator->destroy(enumerator); + + return use; +} + +/** + * Add certificates to message + */ +static void build_certs(private_ike_cert_post_v1_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_ike_cert_post_v1_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_ike_cert_post_v1_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_ike_cert_post_v1_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_ike_cert_post_v1_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 (!use_certs(this, message)) + { + return SUCCESS; + } + return SUCCESS; + } + default: + return FAILED; + } +} + +METHOD(task_t, get_type, task_type_t, + private_ike_cert_post_v1_t *this) +{ + return TASK_IKE_CERT_POST_V1; +} + +METHOD(task_t, migrate, void, + private_ike_cert_post_v1_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_ike_cert_post_v1_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +ike_cert_post_v1_t *ike_cert_post_v1_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_cert_post_v1_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; +} diff --git a/src/libcharon/sa/tasks/ike_cert_post_v1.h b/src/libcharon/sa/tasks/ike_cert_post_v1.h new file mode 100644 index 000000000..58b7aa78f --- /dev/null +++ b/src/libcharon/sa/tasks/ike_cert_post_v1.h @@ -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 ike_cert_post_v1 ike_cert_post_v1 + * @{ @ingroup tasks + */ + +#ifndef IKE_CERT_POST_V1_H_ +#define IKE_CERT_POST_V1_H_ + +typedef struct ike_cert_post_v1_t ike_cert_post_v1_t; + +#include <library.h> +#include <sa/ike_sa.h> +#include <sa/tasks/task.h> + +/** + * IKE_CERT_POST_V1, IKEv1 certificate processing after authentication. + */ +struct ike_cert_post_v1_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new ike_cert_post_v1 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 ike_cert_post_v1 task to handle by the task_manager + */ +ike_cert_post_v1_t *ike_cert_post_v1_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IKE_CERT_POST_V1_H_ @}*/ |