diff options
Diffstat (limited to 'src/libcharon')
53 files changed, 2003 insertions, 322 deletions
diff --git a/src/libcharon/Android.mk b/src/libcharon/Android.mk index b2d6c3128..b64174f8b 100644 --- a/src/libcharon/Android.mk +++ b/src/libcharon/Android.mk @@ -62,7 +62,7 @@ processing/jobs/start_action_job.c processing/jobs/start_action_job.h \ processing/jobs/roam_job.c processing/jobs/roam_job.h \ processing/jobs/update_sa_job.c processing/jobs/update_sa_job.h \ processing/jobs/inactivity_job.c processing/jobs/inactivity_job.h \ -sa/eap/eap_method.c sa/eap/eap_method.h \ +sa/eap/eap_method.c sa/eap/eap_method.h sa/eap/eap_inner_method.h \ sa/eap/eap_manager.c sa/eap/eap_manager.h \ sa/xauth/xauth_method.c sa/xauth/xauth_method.h \ sa/xauth/xauth_manager.c sa/xauth/xauth_manager.h \ diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 5203890ff..bc25dcf21 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -60,7 +60,7 @@ processing/jobs/start_action_job.c processing/jobs/start_action_job.h \ processing/jobs/roam_job.c processing/jobs/roam_job.h \ processing/jobs/update_sa_job.c processing/jobs/update_sa_job.h \ processing/jobs/inactivity_job.c processing/jobs/inactivity_job.h \ -sa/eap/eap_method.c sa/eap/eap_method.h \ +sa/eap/eap_method.c sa/eap/eap_method.h sa/eap/eap_inner_method.h \ sa/eap/eap_manager.c sa/eap/eap_manager.h \ sa/xauth/xauth_method.c sa/xauth/xauth_method.h \ sa/xauth/xauth_manager.c sa/xauth/xauth_manager.h \ @@ -212,6 +212,13 @@ if MONOLITHIC endif endif +if USE_IPSECKEY + SUBDIRS += plugins/ipseckey +if MONOLITHIC + libcharon_la_LIBADD += plugins/ipseckey/libstrongswan-ipseckey.la +endif +endif + if USE_UPDOWN SUBDIRS += plugins/updown if MONOLITHIC diff --git a/src/libcharon/config/ike_cfg.c b/src/libcharon/config/ike_cfg.c index 5e5fbba42..54a054e40 100644 --- a/src/libcharon/config/ike_cfg.c +++ b/src/libcharon/config/ike_cfg.c @@ -95,6 +95,11 @@ struct private_ike_cfg_t { fragmentation_t fragmentation; /** + * DSCP value to use on sent IKE packets + */ + u_int8_t dscp; + + /** * List of proposals to use */ linked_list_t *proposals; @@ -156,6 +161,12 @@ METHOD(ike_cfg_t, get_other_port, u_int16_t, return this->other_port; } +METHOD(ike_cfg_t, get_dscp, u_int8_t, + private_ike_cfg_t *this) +{ + return this->dscp; +} + METHOD(ike_cfg_t, add_proposal, void, private_ike_cfg_t *this, proposal_t *proposal) { @@ -312,7 +323,7 @@ METHOD(ike_cfg_t, destroy, void, ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap, char *me, bool my_allow_any, u_int16_t my_port, char *other, bool other_allow_any, u_int16_t other_port, - fragmentation_t fragmentation) + fragmentation_t fragmentation, u_int8_t dscp) { private_ike_cfg_t *this; @@ -326,6 +337,7 @@ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap, .get_other_addr = _get_other_addr, .get_my_port = _get_my_port, .get_other_port = _get_other_port, + .get_dscp = _get_dscp, .add_proposal = _add_proposal, .get_proposals = _get_proposals, .select_proposal = _select_proposal, @@ -345,6 +357,7 @@ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap, .other_allow_any = other_allow_any, .my_port = my_port, .other_port = other_port, + .dscp = dscp, .proposals = linked_list_create(), ); diff --git a/src/libcharon/config/ike_cfg.h b/src/libcharon/config/ike_cfg.h index 5a7fae1e9..719ceb9dd 100644 --- a/src/libcharon/config/ike_cfg.h +++ b/src/libcharon/config/ike_cfg.h @@ -108,6 +108,13 @@ struct ike_cfg_t { u_int16_t (*get_other_port)(ike_cfg_t *this); /** + * Get the DSCP value to use for IKE packets send from connections. + * + * @return DSCP value + */ + u_int8_t (*get_dscp)(ike_cfg_t *this); + + /** * Adds a proposal to the list. * * The first added proposal has the highest priority, the last @@ -205,11 +212,12 @@ struct ike_cfg_t { * @param other_allow_any allow override of remote address by any address * @param other_port IKE port to use as dest, 500 uses IKEv2 port floating * @param fragmentation use IKEv1 fragmentation + * @param dscp DSCP value to send IKE packets with * @return ike_cfg_t object. */ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap, char *me, bool my_allow_any, u_int16_t my_port, char *other, bool other_allow_any, u_int16_t other_port, - fragmentation_t fragmentation); + fragmentation_t fragmentation, u_int8_t dscp); #endif /** IKE_CFG_H_ @}*/ diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 28fdda735..ca964d749 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -151,7 +151,7 @@ static payload_rule_t ike_sa_init_r_rules[] = { {SECURITY_ASSOCIATION, 1, 1, FALSE, FALSE}, {KEY_EXCHANGE, 1, 1, FALSE, FALSE}, {NONCE, 1, 1, FALSE, FALSE}, - {CERTIFICATE_REQUEST, 0, 1, FALSE, FALSE}, + {CERTIFICATE_REQUEST, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, {VENDOR_ID, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, }; @@ -181,7 +181,7 @@ static payload_rule_t ike_auth_i_rules[] = { {AUTHENTICATION, 0, 1, TRUE, TRUE}, {ID_INITIATOR, 0, 1, TRUE, FALSE}, {CERTIFICATE, 0, MAX_CERT_PAYLOADS, TRUE, FALSE}, - {CERTIFICATE_REQUEST, 0, 1, TRUE, FALSE}, + {CERTIFICATE_REQUEST, 0, MAX_CERTREQ_PAYLOADS, TRUE, FALSE}, {ID_RESPONDER, 0, 1, TRUE, FALSE}, #ifdef ME {SECURITY_ASSOCIATION, 0, 1, TRUE, FALSE}, diff --git a/src/libcharon/plugins/android/android_service.c b/src/libcharon/plugins/android/android_service.c index 6af35e5df..9b9bcc3f5 100644 --- a/src/libcharon/plugins/android/android_service.c +++ b/src/libcharon/plugins/android/android_service.c @@ -266,7 +266,8 @@ static job_requeue_t initiate(private_android_service_t *this) ike_cfg = ike_cfg_create(IKEV2, TRUE, FALSE, "0.0.0.0", FALSE, charon->socket->get_port(charon->socket, FALSE), - hostname, FALSE, IKEV2_UDP_PORT, FRAGMENTATION_NO); + hostname, FALSE, IKEV2_UDP_PORT, FRAGMENTATION_NO, + 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); peer_cfg = peer_cfg_create("android", ike_cfg, CERT_SEND_IF_ASKED, @@ -386,4 +387,3 @@ android_service_t *android_service_create(android_creds_t *creds) return &this->public; } - diff --git a/src/libcharon/plugins/eap_tnc/eap_tnc.c b/src/libcharon/plugins/eap_tnc/eap_tnc.c index ffa1bae39..7363ade1d 100644 --- a/src/libcharon/plugins/eap_tnc/eap_tnc.c +++ b/src/libcharon/plugins/eap_tnc/eap_tnc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 Andreas Steffen + * Copyright (C) 2010-2013 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -21,6 +21,8 @@ #include <utils/debug.h> #include <daemon.h> +#include <tncifimv.h> + /** * Maximum size of an EAP-TNC message */ @@ -44,15 +46,50 @@ struct private_eap_tnc_t { eap_tnc_t public; /** + * Outer EAP authentication type + */ + eap_type_t auth_type; + + /** * TLS stack, wrapped by EAP helper */ tls_eap_t *tls_eap; + + /** + * TNCCS instance running over EAP-TNC + */ + tnccs_t *tnccs; + }; METHOD(eap_method_t, initiate, status_t, private_eap_tnc_t *this, eap_payload_t **out) { chunk_t data; + u_int32_t auth_type; + + /* Determine TNC Client Authentication Type */ + switch (this->auth_type) + { + case EAP_TLS: + case EAP_TTLS: + case EAP_PEAP: + auth_type = TNC_AUTH_CERT; + break; + case EAP_MD5: + case EAP_MSCHAPV2: + case EAP_GTC: + case EAP_OTP: + auth_type = TNC_AUTH_PASSWORD; + break; + case EAP_SIM: + case EAP_AKA: + auth_type = TNC_AUTH_SIM; + break; + default: + auth_type = TNC_AUTH_UNKNOWN; + } + this->tnccs->set_auth_type(this->tnccs, auth_type); if (this->tls_eap->initiate(this->tls_eap, &data) == NEED_MORE) { @@ -122,6 +159,18 @@ METHOD(eap_method_t, destroy, void, free(this); } +METHOD(eap_inner_method_t, get_auth_type, eap_type_t, + private_eap_tnc_t *this) +{ + return this->auth_type; +} + +METHOD(eap_inner_method_t, set_auth_type, void, + private_eap_tnc_t *this, eap_type_t type) +{ + this->auth_type = type; +} + /** * Generic private constructor */ @@ -132,19 +181,22 @@ static eap_tnc_t *eap_tnc_create(identification_t *server, int max_msg_count; char* protocol; tnccs_type_t type; - tnccs_t *tnccs; INIT(this, .public = { - .eap_method = { - .initiate = _initiate, - .process = _process, - .get_type = _get_type, - .is_mutual = _is_mutual, - .get_msk = _get_msk, - .get_identifier = _get_identifier, - .set_identifier = _set_identifier, - .destroy = _destroy, + .eap_inner_method = { + .eap_method = { + .initiate = _initiate, + .process = _process, + .get_type = _get_type, + .is_mutual = _is_mutual, + .get_msk = _get_msk, + .get_identifier = _get_identifier, + .set_identifier = _set_identifier, + .destroy = _destroy, + }, + .get_auth_type = _get_auth_type, + .set_auth_type = _set_auth_type, }, }, ); @@ -172,10 +224,11 @@ static eap_tnc_t *eap_tnc_create(identification_t *server, free(this); return NULL; } - tnccs = tnc->tnccs->create_instance(tnc->tnccs, type, is_server); - this->tls_eap = tls_eap_create(EAP_TNC, (tls_t*)tnccs, - EAP_TNC_MAX_MESSAGE_LEN, - max_msg_count, FALSE); + this->tnccs = tnc->tnccs->create_instance(tnc->tnccs, type, is_server, + server, peer, TNC_IFT_EAP_1_1); + this->tls_eap = tls_eap_create(EAP_TNC, &this->tnccs->tls, + EAP_TNC_MAX_MESSAGE_LEN, + max_msg_count, FALSE); if (!this->tls_eap) { free(this); diff --git a/src/libcharon/plugins/eap_tnc/eap_tnc.h b/src/libcharon/plugins/eap_tnc/eap_tnc.h index 09abe60fc..8c881f6cf 100644 --- a/src/libcharon/plugins/eap_tnc/eap_tnc.h +++ b/src/libcharon/plugins/eap_tnc/eap_tnc.h @@ -23,7 +23,7 @@ typedef struct eap_tnc_t eap_tnc_t; -#include <sa/eap/eap_method.h> +#include <sa/eap/eap_inner_method.h> /** * Implementation of the eap_method_t interface using EAP-TNC. @@ -31,9 +31,9 @@ typedef struct eap_tnc_t eap_tnc_t; struct eap_tnc_t { /** - * Implemented eap_method_t interface. + * Implemented eap_inner_method_t interface. */ - eap_method_t eap_method; + eap_inner_method_t eap_inner_method; }; /** diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_server.c b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c index 464de17ba..eef8d6682 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_server.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c @@ -20,6 +20,7 @@ #include <daemon.h> #include <sa/eap/eap_method.h> +#include <sa/eap/eap_inner_method.h> typedef struct private_eap_ttls_server_t private_eap_ttls_server_t; @@ -108,8 +109,11 @@ static status_t start_phase2_auth(private_eap_ttls_server_t *this) /** * If configured, start EAP-TNC protocol */ -static status_t start_phase2_tnc(private_eap_ttls_server_t *this) +static status_t start_phase2_tnc(private_eap_ttls_server_t *this, + eap_type_t auth_type) { + eap_inner_method_t *inner_method; + if (this->start_phase2_tnc && lib->settings->get_bool(lib->settings, "%s.plugins.eap-ttls.phase2_tnc", FALSE, charon->name)) { @@ -121,6 +125,9 @@ static status_t start_phase2_tnc(private_eap_ttls_server_t *this) DBG1(DBG_IKE, "%N method not available", eap_type_names, EAP_TNC); return FAILED; } + inner_method = (eap_inner_method_t *)this->method; + inner_method->set_auth_type(inner_method, auth_type); + this->start_phase2_tnc = FALSE; if (this->method->initiate(this->method, &this->out) == NEED_MORE) { @@ -237,7 +244,7 @@ METHOD(tls_application_t, process, status_t, if (lib->settings->get_bool(lib->settings, "%s.plugins.eap-ttls.request_peer_auth", FALSE, charon->name)) { - return start_phase2_tnc(this); + return start_phase2_tnc(this, EAP_TLS); } else { @@ -265,7 +272,7 @@ METHOD(tls_application_t, process, status_t, this->method = NULL; /* continue phase2 with EAP-TNC? */ - return start_phase2_tnc(this); + return start_phase2_tnc(this, type); case NEED_MORE: break; case FAILED: diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c index 130c86e48..e6a09a76e 100644 --- a/src/libcharon/plugins/ha/ha_tunnel.c +++ b/src/libcharon/plugins/ha/ha_tunnel.c @@ -205,7 +205,7 @@ static void setup_tunnel(private_ha_tunnel_t *this, /* create config and backend */ ike_cfg = ike_cfg_create(IKEV2, FALSE, FALSE, local, FALSE, charon->socket->get_port(charon->socket, FALSE), - remote, FALSE, IKEV2_UDP_PORT, FRAGMENTATION_NO); + remote, FALSE, IKEV2_UDP_PORT, FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); peer_cfg = peer_cfg_create("ha", ike_cfg, CERT_NEVER_SEND, UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, FALSE, 30, @@ -288,4 +288,3 @@ ha_tunnel_t *ha_tunnel_create(char *local, char *remote, char *secret) return &this->public; } - diff --git a/src/libcharon/plugins/ipseckey/Makefile.am b/src/libcharon/plugins/ipseckey/Makefile.am new file mode 100644 index 000000000..0614017a0 --- /dev/null +++ b/src/libcharon/plugins/ipseckey/Makefile.am @@ -0,0 +1,18 @@ + +INCLUDES = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-ipseckey.la +else +plugin_LTLIBRARIES = libstrongswan-ipseckey.la +endif + +libstrongswan_ipseckey_la_SOURCES = \ + ipseckey_plugin.h ipseckey_plugin.c \ + ipseckey_cred.h ipseckey_cred.c \ + ipseckey.h ipseckey.c + +libstrongswan_ipseckey_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/ipseckey/ipseckey.c b/src/libcharon/plugins/ipseckey/ipseckey.c new file mode 100644 index 000000000..78ae2cc2a --- /dev/null +++ b/src/libcharon/plugins/ipseckey/ipseckey.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * 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 "ipseckey.h" + +#include <library.h> +#include <utils/debug.h> +#include <bio/bio_reader.h> + +typedef struct private_ipseckey_t private_ipseckey_t; + +/** +* private data of the ipseckey +*/ +struct private_ipseckey_t { + + /** + * public functions + */ + ipseckey_t public; + + /** + * Precedence + */ + u_int8_t precedence; + + /** + * Gateway type + */ + u_int8_t gateway_type; + + /** + * Algorithm + */ + u_int8_t algorithm; + + /** + * Gateway + */ + chunk_t gateway; + + /** + * Public key + */ + chunk_t public_key; +}; + +METHOD(ipseckey_t, get_precedence, u_int8_t, + private_ipseckey_t *this) +{ + return this->precedence; +} + +METHOD(ipseckey_t, get_gateway_type, ipseckey_gw_type_t, + private_ipseckey_t *this) +{ + return this->gateway_type; +} + +METHOD(ipseckey_t, get_algorithm, ipseckey_algorithm_t, + private_ipseckey_t *this) +{ + return this->algorithm; +} + +METHOD(ipseckey_t, get_gateway, chunk_t, + private_ipseckey_t *this) +{ + return this->gateway; +} + +METHOD(ipseckey_t, get_public_key, chunk_t, + private_ipseckey_t *this) +{ + return this->public_key; +} + +METHOD(ipseckey_t, destroy, void, + private_ipseckey_t *this) +{ + chunk_free(&this->gateway); + chunk_free(&this->public_key); + free(this); +} + +/* + * See header + */ +ipseckey_t *ipseckey_create_frm_rr(rr_t *rr) +{ + private_ipseckey_t *this; + bio_reader_t *reader = NULL; + u_int8_t label; + chunk_t tmp; + + INIT(this, + .public = { + .get_precedence = _get_precedence, + .get_gateway_type = _get_gateway_type, + .get_algorithm = _get_algorithm, + .get_gateway = _get_gateway, + .get_public_key = _get_public_key, + .destroy = _destroy, + }, + ); + + if (rr->get_type(rr) != RR_TYPE_IPSECKEY) + { + DBG1(DBG_CFG, "unable to create an ipseckey out of an RR " + "whose type is not IPSECKEY"); + free(this); + return NULL; + } + + /** Parse the content (RDATA field) of the RR */ + reader = bio_reader_create(rr->get_rdata(rr)); + if (!reader->read_uint8(reader, &this->precedence) || + !reader->read_uint8(reader, &this->gateway_type) || + !reader->read_uint8(reader, &this->algorithm)) + { + DBG1(DBG_CFG, "ipseckey RR has a wrong format"); + reader->destroy(reader); + free(this); + } + + switch (this->gateway_type) + { + case IPSECKEY_GW_TP_NOT_PRESENT: + break; + + case IPSECKEY_GW_TP_IPV4: + if (!reader->read_data(reader, 4, &this->gateway)) + { + DBG1(DBG_CFG, "ipseckey gateway field does not contain an " + "IPv4 address as expected"); + reader->destroy(reader); + free(this); + return NULL; + } + this->gateway = chunk_clone(this->gateway); + break; + + case IPSECKEY_GW_TP_IPV6: + if (!reader->read_data(reader, 16, &this->gateway)) + { + DBG1(DBG_CFG, "ipseckey gateway field does not contain an " + "IPv6 address as expected"); + reader->destroy(reader); + free(this); + return NULL; + } + this->gateway = chunk_clone(this->gateway); + break; + + case IPSECKEY_GW_TP_WR_ENC_DNAME: + /** + * Uncompressed domain name as defined in RFC 1035 chapter 3. + * + * TODO: Currently we ignore wire encoded domain names. + * + */ + while (reader->read_uint8(reader, &label) && + label != 0 && label < 192) + { + if (!reader->read_data(reader, label, &tmp)) + { + DBG1(DBG_CFG, "wrong wire encoded domain name format " + "in ipseckey gateway field"); + reader->destroy(reader); + free(this); + return NULL; + } + } + break; + + default: + DBG1(DBG_CFG, "unable to parse ipseckey gateway field"); + reader->destroy(reader); + free(this); + return NULL; + } + + if (!reader->read_data(reader, reader->remaining(reader), + &this->public_key)) + { + DBG1(DBG_CFG, "failed to read ipseckey public key field"); + reader->destroy(reader); + chunk_free(&this->gateway); + free(this); + return NULL; + } + this->public_key = chunk_clone(this->public_key); + reader->destroy(reader); + return &this->public; +} + diff --git a/src/libcharon/plugins/ipseckey/ipseckey.h b/src/libcharon/plugins/ipseckey/ipseckey.h new file mode 100644 index 000000000..0afc067a5 --- /dev/null +++ b/src/libcharon/plugins/ipseckey/ipseckey.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * 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 ipseckey_cred_i ipseckey + * @{ @ingroup ipseckey + */ + +#ifndef IPSECKEY_H_ +#define IPSECKEY_H_ + +typedef struct ipseckey_t ipseckey_t; +typedef enum ipseckey_algorithm_t ipseckey_algorithm_t; +typedef enum ipseckey_gw_type_t ipseckey_gw_type_t; + +#include <library.h> + +/** + * IPSECKEY gateway types as defined in RFC 4025. + */ +enum ipseckey_gw_type_t { + /** No gateway is present */ + IPSECKEY_GW_TP_NOT_PRESENT = 0, + /** A 4-byte IPv4 address is present */ + IPSECKEY_GW_TP_IPV4 = 1, + /** A 16-byte IPv6 address is present */ + IPSECKEY_GW_TP_IPV6 = 2, + /** A wire-encoded domain name is present */ + IPSECKEY_GW_TP_WR_ENC_DNAME = 3, +}; + +/** + * IPSECKEY algorithms as defined in RFC 4025. + */ +enum ipseckey_algorithm_t { + /** No key present */ + IPSECKEY_ALGORITHM_NONE = 0, + /** DSA key */ + IPSECKEY_ALGORITHM_DSA = 1, + /** RSA key */ + IPSECKEY_ALGORITHM_RSA = 2, +}; + +/** + * An IPSECKEY. + * + * Represents an IPSECKEY as defined in RFC 4025: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | precedence | gateway type | algorithm | gateway | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------+ + + * ~ gateway ~ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | / + * / public key / + * / / + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-| + * + * + * Note: RFC 4025 defines that the algorithm field has a length of 7 bits. + * We use 8 bits instead, because the use of 7 bits is very uncommon + * in internet protocols and might be an error in RFC 4025 + * (also the BIND DNS server uses 8 bits for the algorithm field of the + * IPSECKEY resource records). + * + */ +struct ipseckey_t { + + /** + * Get the precedence of the IPSECKEY. + * + * @return precedence + */ + u_int8_t (*get_precedence)(ipseckey_t *this); + + /** + * Get the type of the gateway. + * + * The "gateway type" determines the format of the gateway field + * of the IPSECKEY. + * + * @return gateway type + */ + ipseckey_gw_type_t (*get_gateway_type)(ipseckey_t *this); + + /** + * Get the algorithm. + * + * The "algorithm" determines the format of the public key field + * of the IPSECKEY. + * + * @return algorithm + */ + ipseckey_algorithm_t (*get_algorithm)(ipseckey_t *this); + + /** + * Get the content of the gateway field as chunk. + * + * The content is in network byte order and its format depends on the + * gateway type. + * + * The data pointed by the chunk is still owned by the IPSECKEY. + * Clone it if necessary. + * + * @return gateway field as chunk + */ + chunk_t (*get_gateway)(ipseckey_t *this); + + /** + * Get the content of the public key field as chunk. + * + * The format of the public key depends on the algorithm type. + * + * The data pointed by the chunk is still owned by the IPSECKEY. + * Clone it if necessary. + * + * @return public key field as chunk + */ + chunk_t (*get_public_key)(ipseckey_t *this); + + /** + * Destroy the IPSECKEY. + */ + void (*destroy) (ipseckey_t *this); +}; + +/** + * Create an ipseckey instance out of a resource record. + * + * @param rr resource record which contains an IPSECKEY + * @return ipseckey, NULL on failure + */ +ipseckey_t *ipseckey_create_frm_rr(rr_t *rr); + +#endif /** IPSECKEY_H_ @}*/ diff --git a/src/libcharon/plugins/ipseckey/ipseckey_cred.c b/src/libcharon/plugins/ipseckey/ipseckey_cred.c new file mode 100644 index 000000000..e8722f12c --- /dev/null +++ b/src/libcharon/plugins/ipseckey/ipseckey_cred.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * 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. + */ +#define _GNU_SOURCE +#include <stdio.h> +#include <string.h> + +#include "ipseckey_cred.h" +#include "ipseckey.h" + +#include <bio/bio_reader.h> +#include <daemon.h> + +typedef struct private_ipseckey_cred_t private_ipseckey_cred_t; + +/** + * Private data of an ipseckey_cred_t object + */ +struct private_ipseckey_cred_t { + + /** + * Public part + */ + ipseckey_cred_t public; + + /** + * DNS resolver + */ + resolver_t *res; +}; + +/** + * enumerator over certificates + */ +typedef struct { + /** implements enumerator interface */ + enumerator_t public; + /** inner enumerator (enumerates IPSECKEY resource records) */ + enumerator_t *inner; + /** response of the DNS resolver which contains the IPSECKEYs */ + resolver_response_t *response; + /* IPSECKEYs are not valid before this point in time */ + time_t notBefore; + /* IPSECKEYs are not valid after this point in time */ + time_t notAfter; + /* identity to which the IPSECKEY belongs */ + identification_t *identity; +} cert_enumerator_t; + +METHOD(enumerator_t, cert_enumerator_enumerate, bool, + cert_enumerator_t *this, certificate_t **cert) +{ + rr_t *cur_rr = NULL; + ipseckey_t *cur_ipseckey = NULL; + chunk_t pub_key; + public_key_t * key = NULL; + bool supported_ipseckey_found = FALSE; + + /* Get the next supported IPSECKEY using the inner enumerator. */ + while (this->inner->enumerate(this->inner, &cur_rr) && + !supported_ipseckey_found) + { + supported_ipseckey_found = TRUE; + + cur_ipseckey = ipseckey_create_frm_rr(cur_rr); + + if (!cur_ipseckey) + { + DBG1(DBG_CFG, "failed to parse ipseckey - skipping this key"); + supported_ipseckey_found = FALSE; + } + + if (cur_ipseckey && + cur_ipseckey->get_algorithm(cur_ipseckey) != IPSECKEY_ALGORITHM_RSA) + { + DBG1(DBG_CFG, "unsupported ipseckey algorithm -skipping this key"); + cur_ipseckey->destroy(cur_ipseckey); + supported_ipseckey_found = FALSE; + } + } + + if (supported_ipseckey_found) + { + /* + * Wrap the key of the IPSECKEY in a certificate and return this + * certificate. + */ + pub_key = cur_ipseckey->get_public_key(cur_ipseckey); + + key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + BUILD_BLOB_DNSKEY, pub_key, + BUILD_END); + + if (!key) + { + DBG1(DBG_CFG, "failed to create public key from ipseckey"); + cur_ipseckey->destroy(cur_ipseckey); + return FALSE; + } + + *cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, + CERT_TRUSTED_PUBKEY, + BUILD_PUBLIC_KEY, key, + BUILD_SUBJECT, this->identity, + BUILD_NOT_BEFORE_TIME, this->notBefore, + BUILD_NOT_AFTER_TIME, this->notAfter, + BUILD_END); + return TRUE; + } + + return FALSE; +} + +METHOD(enumerator_t, cert_enumerator_destroy, void, + cert_enumerator_t *this) +{ + this->inner->destroy(this->inner); + this->response->destroy(this->response); + free(this); +} + +METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, + private_ipseckey_cred_t *this, certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + char *fqdn = NULL; + resolver_response_t *response = NULL; + rr_set_t *rrset = NULL; + enumerator_t *rrsig_enum = NULL; + rr_t *rrsig = NULL; + bio_reader_t *reader = NULL; + chunk_t ignore; + u_int32_t nBefore, nAfter; + cert_enumerator_t *e; + + if (id && id->get_type(id) == ID_FQDN) + { + /** Query the DNS for the required IPSECKEY RRs */ + + if (0 >= asprintf(&fqdn, "%Y", id)) + { + DBG1(DBG_CFG, "empty FQDN string"); + return enumerator_create_empty(); + } + + DBG1(DBG_CFG, "performing a DNS query for IPSECKEY RRs of '%s'", + fqdn); + response = this->res->query(this->res, fqdn, RR_CLASS_IN, + RR_TYPE_IPSECKEY); + if (!response) + { + DBG1(DBG_CFG, " query for IPSECKEY RRs failed"); + free(fqdn); + return enumerator_create_empty(); + } + + if (!response->has_data(response) || + !response->query_name_exist(response)) + { + DBG1(DBG_CFG, " unable to retrieve IPSECKEY RRs from the DNS"); + response->destroy(response); + free(fqdn); + return enumerator_create_empty(); + } + + if (!(response->get_security_state(response) == SECURE)) + { + DBG1(DBG_CFG, " DNSSEC state of IPSECKEY RRs is not secure"); + response->destroy(response); + free(fqdn); + return enumerator_create_empty(); + } + + free(fqdn); + + /** Determine the validity period of the retrieved IPSECKEYs + * + * We use the "Signature Inception" and "Signature Expiration" field + * of the first RRSIG RR to determine the validity period of the + * IPSECKEY RRs. TODO: Take multiple RRSIGs into account. + */ + rrset = response->get_rr_set(response); + rrsig_enum = rrset->create_rrsig_enumerator(rrset); + if (!rrsig_enum || !rrsig_enum->enumerate(rrsig_enum, &rrsig)) + { + DBG1(DBG_CFG, " unable to determine the validity period of " + "IPSECKEY RRs because no RRSIGs are present"); + DESTROY_IF(rrsig_enum); + response->destroy(response); + return enumerator_create_empty(); + } + + /** + * Parse the RRSIG for its validity period (RFC 4034) + */ + reader = bio_reader_create(rrsig->get_rdata(rrsig)); + reader->read_data(reader, 8, &ignore); + reader->read_uint32(reader, &nAfter); + reader->read_uint32(reader, &nBefore); + reader->destroy(reader); + + /*Create and return an iterator over the retrieved IPSECKEYs */ + INIT(e, + .public = { + .enumerate = (void*)_cert_enumerator_enumerate, + .destroy = _cert_enumerator_destroy, + }, + .inner = response->get_rr_set(response)->create_rr_enumerator( + response->get_rr_set(response)), + .response = response, + .notBefore = nBefore, + .notAfter = nAfter, + .identity = id, + ); + + return &e->public; + } + + + return enumerator_create_empty(); +} + +METHOD(ipseckey_cred_t, destroy, void, + private_ipseckey_cred_t *this) +{ + this->res->destroy(this->res); + free(this); +} + +/** + * Described in header. + */ +ipseckey_cred_t *ipseckey_cred_create(resolver_t *res) +{ + private_ipseckey_cred_t *this; + + INIT(this, + .public = { + .set = { + .create_private_enumerator = (void*)return_null, + .create_cert_enumerator = _create_cert_enumerator, + .create_shared_enumerator = (void*)return_null, + .create_cdp_enumerator = (void*)return_null, + .cache_cert = (void*)nop, + }, + .destroy = _destroy, + }, + .res = res, + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/ipseckey/ipseckey_cred.h b/src/libcharon/plugins/ipseckey/ipseckey_cred.h new file mode 100644 index 000000000..440020f5d --- /dev/null +++ b/src/libcharon/plugins/ipseckey/ipseckey_cred.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * 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 ipseckey_cred_i ipseckey_cred + * @{ @ingroup ipseckey + */ + +#ifndef IPSECKEY_CRED_H_ +#define IPSECKEY_CRED_H_ + +#include <credentials/credential_set.h> +#include <resolver/resolver.h> + +typedef struct ipseckey_cred_t ipseckey_cred_t; + +/** + * IPSECKEY credential set. + * + * The ipseckey credential set contains IPSECKEYs as certificates of type + * pubkey_cert_t. + */ +struct ipseckey_cred_t { + + /** + * Implements credential_set_t interface + */ + credential_set_t set; + + /** + * Destroy the ipseckey_cred. + */ + void (*destroy)(ipseckey_cred_t *this); +}; + +/** + * Create an ipseckey_cred instance which uses the given resolver + * to query the DNS for IPSECKEY resource records. + * + * @param res resolver to use + * @return credential set + */ +ipseckey_cred_t *ipseckey_cred_create(resolver_t *res); + +#endif /** IPSECKEY_CRED_H_ @}*/ diff --git a/src/libcharon/plugins/ipseckey/ipseckey_plugin.c b/src/libcharon/plugins/ipseckey/ipseckey_plugin.c new file mode 100644 index 000000000..6f0f10507 --- /dev/null +++ b/src/libcharon/plugins/ipseckey/ipseckey_plugin.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * 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 "ipseckey_plugin.h" + +#include <daemon.h> +#include "ipseckey_cred.h" + +typedef struct private_ipseckey_plugin_t private_ipseckey_plugin_t; + + +/** + * private data of the ipseckey plugin + */ +struct private_ipseckey_plugin_t { + + /** + * implements plugin interface + */ + ipseckey_plugin_t public; + + /** + * DNS resolver instance + */ + resolver_t *res; + + /** + * credential set + */ + ipseckey_cred_t *cred; + + /** + * IPSECKEY based authentication enabled + */ + bool enabled; +}; + +METHOD(plugin_t, get_name, char*, + private_ipseckey_plugin_t *this) +{ + return "ipseckey"; +} + +METHOD(plugin_t, destroy, void, + private_ipseckey_plugin_t *this) +{ + if (this->enabled) + { + lib->credmgr->remove_set(lib->credmgr, &this->cred->set); + } + this->res->destroy(this->res); + DESTROY_IF(this->cred); + free(this); +} + +/* + * see header file + */ +plugin_t *ipseckey_plugin_create() +{ + private_ipseckey_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .reload = (void*)return_false, + .destroy = _destroy, + }, + }, + .res = lib->resolver->create(lib->resolver), + .enabled = lib->settings->get_bool(lib->settings, + "charon.plugins.ipseckey.enable", FALSE), + ); + + if (!this->res) + { + DBG1(DBG_CFG, "ipseckey_plugin: Failed to create" + "a DNS resolver instance"); + destroy(this); + return NULL; + } + + if (this->enabled) + { + this->cred = ipseckey_cred_create(this->res); + lib->credmgr->add_set(lib->credmgr, &this->cred->set); + } + + return &this->public.plugin; +} + diff --git a/src/libcharon/plugins/ipseckey/ipseckey_plugin.h b/src/libcharon/plugins/ipseckey/ipseckey_plugin.h new file mode 100644 index 000000000..95acc79dd --- /dev/null +++ b/src/libcharon/plugins/ipseckey/ipseckey_plugin.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * 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 ipseckey ipseckey + * @ingroup cplugins + * + * @defgroup ipseckey_plugin ipseckey_plugin + * @{ @ingroup ipseckey + */ + +#ifndef IPSECKEY_PLUGIN_H_ +#define IPSECKEY_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct ipseckey_plugin_t ipseckey_plugin_t; + +/** + * IPSECKEY plugin + * + * The IPSECKEY plugin registers a credential set for IPSECKEYs. + * + * With this credential set it is possible to authenticate tunnel endpoints + * using IPSECKEY resource records which are retrieved from the DNS in a secure + * way (DNSSEC). + */ +struct ipseckey_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** IPSECKEY_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/load_tester/load_tester_config.c b/src/libcharon/plugins/load_tester/load_tester_config.c index 1033eb517..52afe1b0a 100644 --- a/src/libcharon/plugins/load_tester/load_tester_config.c +++ b/src/libcharon/plugins/load_tester/load_tester_config.c @@ -491,7 +491,7 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num) ike_cfg = ike_cfg_create(this->version, TRUE, FALSE, local, FALSE, this->port + num - 1, remote, FALSE, IKEV2_NATT_PORT, - FRAGMENTATION_NO); + FRAGMENTATION_NO, 0); } else { @@ -499,7 +499,7 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num) local, FALSE, charon->socket->get_port(charon->socket, FALSE), remote, FALSE, IKEV2_UDP_PORT, - FRAGMENTATION_NO); + FRAGMENTATION_NO, 0); } ike_cfg->add_proposal(ike_cfg, this->proposal->clone(this->proposal)); peer_cfg = peer_cfg_create("load-test", ike_cfg, diff --git a/src/libcharon/plugins/maemo/maemo_service.c b/src/libcharon/plugins/maemo/maemo_service.c index 806e4cd65..d7539c2da 100644 --- a/src/libcharon/plugins/maemo/maemo_service.c +++ b/src/libcharon/plugins/maemo/maemo_service.c @@ -325,7 +325,8 @@ static gboolean initiate_connection(private_maemo_service_t *this, ike_cfg = ike_cfg_create(IKEV2, TRUE, FALSE, "0.0.0.0", FALSE, charon->socket->get_port(charon->socket, FALSE), - hostname, FALSE, IKEV2_UDP_PORT, FRAGMENTATION_NO); + hostname, FALSE, IKEV2_UDP_PORT, FRAGMENTATION_NO, + 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); peer_cfg = peer_cfg_create(this->current, ike_cfg, @@ -524,4 +525,3 @@ maemo_service_t *maemo_service_create() return &this->public; } - diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c index 73e128abe..2bff70307 100644 --- a/src/libcharon/plugins/medcli/medcli_config.c +++ b/src/libcharon/plugins/medcli/medcli_config.c @@ -105,7 +105,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, ike_cfg = ike_cfg_create(IKEV2, FALSE, FALSE, "0.0.0.0", FALSE, charon->socket->get_port(charon->socket, FALSE), - address, FALSE, IKEV2_UDP_PORT, FRAGMENTATION_NO); + address, FALSE, IKEV2_UDP_PORT, FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); med_cfg = peer_cfg_create( "mediation", ike_cfg, @@ -381,7 +381,7 @@ medcli_config_t *medcli_config_create(database_t *db) "0.0.0.0", FALSE, charon->socket->get_port(charon->socket, FALSE), "0.0.0.0", FALSE, IKEV2_UDP_PORT, - FRAGMENTATION_NO), + FRAGMENTATION_NO, 0), ); this->ike->add_proposal(this->ike, proposal_create_default(PROTO_IKE)); diff --git a/src/libcharon/plugins/medsrv/medsrv_config.c b/src/libcharon/plugins/medsrv/medsrv_config.c index be14380ea..06339220a 100644 --- a/src/libcharon/plugins/medsrv/medsrv_config.c +++ b/src/libcharon/plugins/medsrv/medsrv_config.c @@ -143,10 +143,9 @@ medsrv_config_t *medsrv_config_create(database_t *db) "0.0.0.0", FALSE, charon->socket->get_port(charon->socket, FALSE), "0.0.0.0", FALSE, IKEV2_UDP_PORT, - FRAGMENTATION_NO), + FRAGMENTATION_NO, 0), ); this->ike->add_proposal(this->ike, proposal_create_default(PROTO_IKE)); return &this->public; } - diff --git a/src/libcharon/plugins/socket_default/socket_default_socket.c b/src/libcharon/plugins/socket_default/socket_default_socket.c index 51432c960..c0b744a68 100644 --- a/src/libcharon/plugins/socket_default/socket_default_socket.c +++ b/src/libcharon/plugins/socket_default/socket_default_socket.c @@ -55,6 +55,9 @@ #ifndef SOL_IPV6 #define SOL_IPV6 IPPROTO_IPV6 #endif +#ifndef IPV6_TCLASS +#define IPV6_TCLASS 67 +#endif /* IPV6_RECVPKTINFO is defined in RFC 3542 which obsoletes RFC 2292 that * previously defined IPV6_PKTINFO */ @@ -113,6 +116,26 @@ struct private_socket_default_socket_t { int ipv6_natt; /** + * DSCP value set on IPv4 socket + */ + u_int8_t dscp4; + + /** + * DSCP value set on IPv4 socket for NAT-T (4500 or natt) + */ + u_int8_t dscp4_natt; + + /** + * DSCP value set on IPv6 socket (500 or port) + */ + u_int8_t dscp6; + + /** + * DSCP value set on IPv6 socket for NAT-T (4500 or natt) + */ + u_int8_t dscp6_natt; + + /** * Maximum packet size to receive */ int max_packet; @@ -310,6 +333,7 @@ METHOD(socket_t, sender, status_t, struct msghdr msg; struct cmsghdr *cmsg; struct iovec iov; + u_int8_t *dscp; src = packet->get_source(packet); dst = packet->get_destination(packet); @@ -322,24 +346,34 @@ METHOD(socket_t, sender, status_t, family = dst->get_family(dst); if (sport == 0 || sport == this->port) { - if (family == AF_INET) - { - skt = this->ipv4; - } - else + switch (family) { - skt = this->ipv6; + case AF_INET: + skt = this->ipv4; + dscp = &this->dscp4; + break; + case AF_INET6: + skt = this->ipv6; + dscp = &this->dscp6; + break; + default: + return FAILED; } } else if (sport == this->natt) { - if (family == AF_INET) - { - skt = this->ipv4_natt; - } - else + switch (family) { - skt = this->ipv6_natt; + case AF_INET: + skt = this->ipv4_natt; + dscp = &this->dscp4_natt; + break; + case AF_INET6: + skt = this->ipv6_natt; + dscp = &this->dscp6_natt; + break; + default: + return FAILED; } } else @@ -348,6 +382,43 @@ METHOD(socket_t, sender, status_t, return FAILED; } + /* setting DSCP values per-packet in a cmsg seems not to be supported + * on Linux. We instead setsockopt() before sending it, this should be + * safe as only a single thread calls send(). */ + if (*dscp != packet->get_dscp(packet)) + { + if (family == AF_INET) + { + u_int8_t ds4; + + ds4 = packet->get_dscp(packet) << 2; + if (setsockopt(skt, SOL_IP, IP_TOS, &ds4, sizeof(ds4)) == 0) + { + *dscp = packet->get_dscp(packet); + } + else + { + DBG1(DBG_NET, "unable to set IP_TOS on socket: %s", + strerror(errno)); + } + } + else + { + u_int ds6; + + ds6 = packet->get_dscp(packet) << 2; + if (setsockopt(skt, SOL_IPV6, IPV6_TCLASS, &ds6, sizeof(ds6)) == 0) + { + *dscp = packet->get_dscp(packet); + } + else + { + DBG1(DBG_NET, "unable to set IPV6_TCLASS on socket: %s", + strerror(errno)); + } + } + } + memset(&msg, 0, sizeof(struct msghdr)); msg.msg_name = dst->get_sockaddr(dst);; msg.msg_namelen = *dst->get_sockaddr_len(dst); @@ -433,22 +504,24 @@ static int open_socket(private_socket_default_socket_t *this, int family, u_int16_t *port) { int on = TRUE; - struct sockaddr_storage addr; + union { + struct sockaddr sockaddr; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } addr; socklen_t addrlen; u_int sol, pktinfo = 0; int skt; memset(&addr, 0, sizeof(addr)); - addr.ss_family = family; + addr.sockaddr.sa_family = family; /* precalculate constants depending on address family */ switch (family) { case AF_INET: - { - struct sockaddr_in *sin = (struct sockaddr_in *)&addr; - htoun32(&sin->sin_addr.s_addr, INADDR_ANY); - htoun16(&sin->sin_port, *port); - addrlen = sizeof(struct sockaddr_in); + addr.sin.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin.sin_port = htons(*port); + addrlen = sizeof(addr.sin); sol = SOL_IP; #ifdef IP_PKTINFO pktinfo = IP_PKTINFO; @@ -456,17 +529,13 @@ static int open_socket(private_socket_default_socket_t *this, pktinfo = IP_RECVDSTADDR; #endif break; - } case AF_INET6: - { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr; - memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any)); - htoun16(&sin6->sin6_port, *port); - addrlen = sizeof(struct sockaddr_in6); + memcpy(&addr.sin6.sin6_addr, &in6addr_any, sizeof(in6addr_any)); + addr.sin6.sin6_port = htons(*port); + addrlen = sizeof(addr.sin6); sol = SOL_IPV6; pktinfo = IPV6_RECVPKTINFO; break; - } default: return 0; } @@ -485,7 +554,7 @@ static int open_socket(private_socket_default_socket_t *this, } /* bind the socket */ - if (bind(skt, (struct sockaddr *)&addr, addrlen) < 0) + if (bind(skt, &addr.sockaddr, addrlen) < 0) { DBG1(DBG_NET, "unable to bind socket: %s", strerror(errno)); close(skt); @@ -495,7 +564,7 @@ static int open_socket(private_socket_default_socket_t *this, /* retrieve randomly allocated port if needed */ if (*port == 0) { - if (getsockname(skt, (struct sockaddr *)&addr, &addrlen) < 0) + if (getsockname(skt, &addr.sockaddr, &addrlen) < 0) { DBG1(DBG_NET, "unable to determine port: %s", strerror(errno)); close(skt); @@ -504,17 +573,11 @@ static int open_socket(private_socket_default_socket_t *this, switch (family) { case AF_INET: - { - struct sockaddr_in *sin = (struct sockaddr_in *)&addr; - *port = untoh16(&sin->sin_port); + *port = ntohs(addr.sin.sin_port); break; - } case AF_INET6: - { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr; - *port = untoh16(&sin6->sin6_port); + *port = ntohs(addr.sin6.sin6_port); break; - } } } @@ -642,4 +705,3 @@ socket_default_socket_t *socket_default_socket_create() return &this->public; } - diff --git a/src/libcharon/plugins/sql/sql_config.c b/src/libcharon/plugins/sql/sql_config.c index 37bd86671..c3471a078 100644 --- a/src/libcharon/plugins/sql/sql_config.c +++ b/src/libcharon/plugins/sql/sql_config.c @@ -262,7 +262,7 @@ static ike_cfg_t *build_ike_cfg(private_sql_config_t *this, enumerator_t *e, local, FALSE, charon->socket->get_port(charon->socket, FALSE), remote, FALSE, IKEV2_UDP_PORT, - FRAGMENTATION_NO); + FRAGMENTATION_NO, 0); add_ike_proposals(this, ike_cfg, id); return ike_cfg; } @@ -620,4 +620,3 @@ sql_config_t *sql_config_create(database_t *db) return &this->public; } - diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index ed10bdb9f..deff25878 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -234,7 +234,8 @@ static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg msg->add_conn.other.address, msg->add_conn.other.allow_any, msg->add_conn.other.ikeport, - msg->add_conn.fragmentation); + msg->add_conn.fragmentation, + msg->add_conn.ikedscp); add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL); return ike_cfg; } diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c index 2771f0146..e31616cf8 100644 --- a/src/libcharon/plugins/stroke/stroke_socket.c +++ b/src/libcharon/plugins/stroke/stroke_socket.c @@ -516,11 +516,18 @@ static void stroke_loglevel(private_stroke_socket_t *this, DBG1(DBG_CFG, "received stroke: loglevel %d for %s", msg->loglevel.level, msg->loglevel.type); - group = enum_from_name(debug_names, msg->loglevel.type); - if ((int)group < 0) + if (strcaseeq(msg->loglevel.type, "any")) { - fprintf(out, "invalid type (%s)!\n", msg->loglevel.type); - return; + group = DBG_ANY; + } + else + { + group = enum_from_name(debug_names, msg->loglevel.type); + if ((int)group < 0) + { + fprintf(out, "invalid type (%s)!\n", msg->loglevel.type); + return; + } } charon->set_level(charon, group, msg->loglevel.level); } diff --git a/src/libcharon/plugins/tnc_imc/Makefile.am b/src/libcharon/plugins/tnc_imc/Makefile.am index 5e2c30df9..eba280690 100644 --- a/src/libcharon/plugins/tnc_imc/Makefile.am +++ b/src/libcharon/plugins/tnc_imc/Makefile.am @@ -4,7 +4,8 @@ INCLUDES = \ -I$(top_srcdir)/src/libhydra \ -I$(top_srcdir)/src/libcharon \ -I$(top_srcdir)/src/libtncif \ - -I$(top_srcdir)/src/libtnccs + -I$(top_srcdir)/src/libtnccs \ + -I$(top_srcdir)/src/libtls AM_CFLAGS = -rdynamic diff --git a/src/libcharon/plugins/tnc_imv/Makefile.am b/src/libcharon/plugins/tnc_imv/Makefile.am index eca3b377b..90b3507ce 100644 --- a/src/libcharon/plugins/tnc_imv/Makefile.am +++ b/src/libcharon/plugins/tnc_imv/Makefile.am @@ -4,7 +4,8 @@ INCLUDES = \ -I$(top_srcdir)/src/libhydra \ -I$(top_srcdir)/src/libcharon \ -I$(top_srcdir)/src/libtncif \ - -I$(top_srcdir)/src/libtnccs + -I$(top_srcdir)/src/libtnccs \ + -I$(top_srcdir)/src/libtls AM_CFLAGS = -rdynamic diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c index 39939d34e..422c28bc9 100644 --- a/src/libcharon/plugins/tnc_pdp/tnc_pdp.c +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c @@ -378,7 +378,10 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request, } this->connections->add(this->connections, nas_id, user_name, peer, method); - method->initiate(method, &out); + if (method->initiate(method, &out) == NEED_MORE) + { + send_response(this, request, code, out, group, msk, source); + } } else { @@ -428,16 +431,16 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request, in->get_identifier(in)); } charon->bus->set_sa(charon->bus, NULL); + send_response(this, request, code, out, group, msk, source); + this->connections->unlock(this->connections); } - send_response(this, request, code, out, group, msk, source); - out->destroy(out); - if (code == RMC_ACCESS_ACCEPT || code == RMC_ACCESS_REJECT) { this->connections->remove(this->connections, nas_id, user_name); } + out->destroy(out); end: free(message.ptr); in->destroy(in); @@ -648,4 +651,3 @@ tnc_pdp_t *tnc_pdp_create(u_int16_t port) return &this->public; } - diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c index 0a960635b..f789c31d2 100644 --- a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c @@ -17,6 +17,15 @@ #include <collections/linked_list.h> #include <utils/debug.h> +#include <threading/rwlock.h> +#include <processing/jobs/callback_job.h> + +#include <daemon.h> + +/** + * Default PDP connection timeout, in s + */ +#define DEFAULT_TIMEOUT 30 typedef struct private_tnc_pdp_connections_t private_tnc_pdp_connections_t; typedef struct entry_t entry_t; @@ -32,9 +41,19 @@ struct private_tnc_pdp_connections_t { tnc_pdp_connections_t public; /** - * List of TNC PEP RADIUS Connections + * TNC PEP RADIUS Connections */ linked_list_t *list; + + /** + * Lock to access PEP connection list + */ + rwlock_t *lock; + + /** + * Connection timeout before we kill non-completed connections, in s + */ + int timeout; }; /** @@ -61,6 +80,11 @@ struct entry_t { * IKE SA used for bus communication */ ike_sa_t *ike_sa; + + /** + * Timestamp this entry has been created + */ + time_t created; }; /** @@ -105,6 +129,35 @@ static void dbg_nas_user(chunk_t nas_id, chunk_t user_name, bool not, char *op) } } +/** + * Check if any connection has timed out + */ +static job_requeue_t check_timeouts(private_tnc_pdp_connections_t *this) +{ + enumerator_t *enumerator; + entry_t *entry; + time_t now; + + now = time_monotonic(NULL); + + this->lock->write_lock(this->lock); + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->created + this->timeout <= now) + { + DBG1(DBG_CFG, "RADIUS connection timed out after %d seconds", + this->timeout); + this->list->remove_at(this->list, enumerator); + free_entry(entry); + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return JOB_REQUEUE_NONE; +} + METHOD(tnc_pdp_connections_t, add, void, private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name, identification_t *peer, eap_method_t *method) @@ -120,6 +173,7 @@ METHOD(tnc_pdp_connections_t, add, void, ike_sa_id->destroy(ike_sa_id); ike_sa->set_other_id(ike_sa, peer); + this->lock->read_lock(this->lock); enumerator = this->list->create_enumerator(this->list); while (enumerator->enumerate(enumerator, &entry)) { @@ -131,20 +185,33 @@ METHOD(tnc_pdp_connections_t, add, void, DBG1(DBG_CFG, "removed stale RADIUS connection"); entry->method = method; entry->ike_sa = ike_sa; + entry->created = time_monotonic(NULL); break; } } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); if (!found) { - entry = malloc_thing(entry_t); - entry->nas_id = chunk_clone(nas_id); - entry->user_name = chunk_clone(user_name); - entry->method = method; - entry->ike_sa = ike_sa; + INIT(entry, + .nas_id = chunk_clone(nas_id), + .user_name = chunk_clone(user_name), + .method = method, + .ike_sa = ike_sa, + .created = time_monotonic(NULL), + ); + this->lock->write_lock(this->lock); this->list->insert_last(this->list, entry); + this->lock->unlock(this->lock); } + + /* schedule timeout checking */ + lib->scheduler->schedule_job_ms(lib->scheduler, + (job_t*)callback_job_create((callback_job_cb_t)check_timeouts, + this, NULL, (callback_job_cancel_t)return_false), + this->timeout * 1000); + dbg_nas_user(nas_id, user_name, FALSE, "created"); } @@ -154,6 +221,7 @@ METHOD(tnc_pdp_connections_t, remove_, void, enumerator_t *enumerator; entry_t *entry; + this->lock->write_lock(this->lock); enumerator = this->list->create_enumerator(this->list); while (enumerator->enumerate(enumerator, &entry)) { @@ -166,6 +234,7 @@ METHOD(tnc_pdp_connections_t, remove_, void, } } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); } METHOD(tnc_pdp_connections_t, get_state, eap_method_t*, @@ -176,6 +245,7 @@ METHOD(tnc_pdp_connections_t, get_state, eap_method_t*, entry_t *entry; eap_method_t *found = NULL; + this->lock->read_lock(this->lock); enumerator = this->list->create_enumerator(this->list); while (enumerator->enumerate(enumerator, &entry)) { @@ -187,14 +257,25 @@ METHOD(tnc_pdp_connections_t, get_state, eap_method_t*, } } enumerator->destroy(enumerator); + if (!found) + { + this->lock->unlock(this->lock); + } dbg_nas_user(nas_id, user_name, !found, "found"); return found; } +METHOD(tnc_pdp_connections_t, unlock, void, + private_tnc_pdp_connections_t *this) +{ + this->lock->unlock(this->lock); +} + METHOD(tnc_pdp_connections_t, destroy, void, private_tnc_pdp_connections_t *this) { + this->lock->destroy(this->lock); this->list->destroy_function(this->list, (void*)free_entry); free(this); } @@ -211,11 +292,14 @@ tnc_pdp_connections_t *tnc_pdp_connections_create(void) .add = _add, .remove = _remove_, .get_state = _get_state, + .unlock = _unlock, .destroy = _destroy, }, .list = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + .timeout = lib->settings->get_int(lib->settings, + "%s.plugins.tnc-pdp.timeout", DEFAULT_TIMEOUT, charon->name), ); return &this->public; } - diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h index 16492020e..442f29ce9 100644 --- a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h @@ -53,7 +53,10 @@ struct tnc_pdp_connections_t { chunk_t user_name); /** - * Get the EAP method and IKE_SA of a registered TNC PEP RADIUS Connection + * Get the EAP method and IKE_SA of a registered TNC PEP RADIUS Connection. + * + * If this call succeeds, the connection manager is locked. Call unlock + * after using the return objects. * * @param nas_id NAS identifier of Policy Enforcement Point * @param user_name User name of TNC Client @@ -64,6 +67,11 @@ struct tnc_pdp_connections_t { chunk_t user_name, ike_sa_t **ike_sa); /** + * Unlock connections after successfully calling get_state(). + */ + void (*unlock)(tnc_pdp_connections_t *this); + + /** * Destroys a tnc_pdp_connections_t object. */ void (*destroy)(tnc_pdp_connections_t *this); diff --git a/src/libcharon/plugins/tnc_tnccs/Makefile.am b/src/libcharon/plugins/tnc_tnccs/Makefile.am index c7fc02f7c..9ee9e86ad 100644 --- a/src/libcharon/plugins/tnc_tnccs/Makefile.am +++ b/src/libcharon/plugins/tnc_tnccs/Makefile.am @@ -1,6 +1,7 @@ INCLUDES = \ -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libtls \ -I$(top_srcdir)/src/libtncif \ -I$(top_srcdir)/src/libtnccs diff --git a/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c b/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c index 0b623d6ff..6ddda594d 100644 --- a/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c +++ b/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 Andreas Steffen + * Copyright (C) 2010-2013 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -20,7 +20,13 @@ #include <tnc/imc/imc_manager.h> #include <tnc/imv/imv_manager.h> +#include <tncif_identity.h> + +#include <tls.h> + #include <utils/debug.h> +#include <pen/pen.h> +#include <bio/bio_writer.h> #include <collections/linked_list.h> #include <threading/rwlock.h> @@ -158,7 +164,9 @@ METHOD(tnccs_manager_t, remove_method, void, } METHOD(tnccs_manager_t, create_instance, tnccs_t*, - private_tnc_tnccs_manager_t *this, tnccs_type_t type, bool is_server) + private_tnc_tnccs_manager_t *this, tnccs_type_t type, bool is_server, + identification_t *server, identification_t *peer, + tnc_ift_type_t transport) { enumerator_t *enumerator; tnccs_entry_t *entry; @@ -170,7 +178,7 @@ METHOD(tnccs_manager_t, create_instance, tnccs_t*, { if (type == entry->type) { - protocol = entry->constructor(is_server); + protocol = entry->constructor(is_server, server, peer, transport); if (protocol) { break; @@ -442,6 +450,44 @@ static TNC_Result str_attribute(TNC_UInt32 buffer_len, } } +/** + * Write the value of a TNC identity list into the buffer + */ +static TNC_Result identity_attribute(TNC_UInt32 buffer_len, + TNC_BufferReference buffer, + TNC_UInt32 *value_len, + linked_list_t *list) +{ + bio_writer_t *writer; + enumerator_t *enumerator; + u_int32_t count; + chunk_t value; + tncif_identity_t *tnc_id; + TNC_Result result = TNC_RESULT_INVALID_PARAMETER; + + count = list->get_count(list); + writer = bio_writer_create(4 + TNCIF_IDENTITY_MIN_SIZE * count); + writer->write_uint32(writer, count); + + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &tnc_id)) + { + tnc_id->build(tnc_id, writer); + } + enumerator->destroy(enumerator); + + value = writer->get_buf(writer); + *value_len = value.len; + if (buffer && buffer_len >= value.len) + { + memcpy(buffer, value.ptr, value.len); + result = TNC_RESULT_SUCCESS; + } + writer->destroy(writer); + + return result; +} + METHOD(tnccs_manager_t, get_attribute, TNC_Result, private_tnc_tnccs_manager_t *this, bool is_imc, TNC_UInt32 imcv_id, @@ -487,6 +533,7 @@ METHOD(tnccs_manager_t, get_attribute, TNC_Result, /* these attributes are supported */ case TNC_ATTRIBUTEID_PRIMARY_IMV_ID: + case TNC_ATTRIBUTEID_AR_IDENTITIES: attribute_match = TRUE; break; @@ -616,15 +663,111 @@ METHOD(tnccs_manager_t, get_attribute, TNC_Result, version = "1.0"; break; default: - return TNC_RESULT_INVALID_PARAMETER; + return TNC_RESULT_INVALID_PARAMETER; } return str_attribute(buffer_len, buffer, value_len, version); } case TNC_ATTRIBUTEID_IFT_PROTOCOL: - return str_attribute(buffer_len, buffer, value_len, - "IF-T for Tunneled EAP"); + { + char *protocol; + + switch (entry->tnccs->get_transport(entry->tnccs)) + { + case TNC_IFT_EAP_1_0: + case TNC_IFT_EAP_1_1: + case TNC_IFT_EAP_2_0: + protocol = "IF-T for Tunneled EAP"; + break; + case TNC_IFT_TLS_1_0: + case TNC_IFT_TLS_2_0: + protocol = "IF-T for TLS"; + break; + default: + return TNC_RESULT_INVALID_PARAMETER; + } + return str_attribute(buffer_len, buffer, value_len, protocol); + } case TNC_ATTRIBUTEID_IFT_VERSION: - return str_attribute(buffer_len, buffer, value_len, "1.1"); + { + char *version; + + switch (entry->tnccs->get_transport(entry->tnccs)) + { + case TNC_IFT_EAP_1_0: + case TNC_IFT_TLS_1_0: + version = "1.0"; + break; + case TNC_IFT_EAP_1_1: + version = "1.1"; + break; + case TNC_IFT_EAP_2_0: + case TNC_IFT_TLS_2_0: + version = "2.0"; + break; + default: + return TNC_RESULT_INVALID_PARAMETER; + } + return str_attribute(buffer_len, buffer, value_len, version); + } + case TNC_ATTRIBUTEID_AR_IDENTITIES: + { + linked_list_t *list; + identification_t *peer; + tnccs_t *tnccs; + tncif_identity_t *tnc_id; + u_int32_t id_type, subject_type; + TNC_Result result; + + list = linked_list_create(); + tnccs = entry->tnccs; + peer = tnccs->tls.get_peer_id(&tnccs->tls); + if (peer) + { + switch (peer->get_type(peer)) + { + case ID_IPV4_ADDR: + id_type = TNC_ID_IPV4_ADDR; + subject_type = TNC_SUBJECT_MACHINE; + break; + case ID_IPV6_ADDR: + id_type = TNC_ID_IPV6_ADDR; + subject_type = TNC_SUBJECT_MACHINE; + break; + case ID_FQDN: + id_type = TNC_ID_USER_NAME; + subject_type = TNC_SUBJECT_USER; + break; + case ID_RFC822_ADDR: + id_type = TNC_ID_RFC822_ADDR; + subject_type = TNC_SUBJECT_USER; + break; + case ID_DER_ASN1_DN: + id_type = TNC_ID_DER_ASN1_DN; + subject_type = TNC_SUBJECT_USER; + break; + case ID_DER_ASN1_GN: + id_type = TNC_ID_DER_ASN1_GN; + subject_type = TNC_SUBJECT_UNKNOWN; + break; + default: + id_type = TNC_ID_UNKNOWN; + subject_type = TNC_SUBJECT_UNKNOWN; + } + if (id_type != TNC_ID_UNKNOWN) + { + tnc_id = tncif_identity_create( + pen_type_create(PEN_TCG, id_type), + peer->get_encoding(peer), + pen_type_create(PEN_TCG, subject_type), + pen_type_create(PEN_TCG, + tnccs->get_auth_type(tnccs))); + list->insert_last(list, tnc_id); + } + } + result = identity_attribute(buffer_len, buffer, value_len, list); + list->destroy_offset(list, offsetof(tncif_identity_t, destroy)); + return result; + } default: return TNC_RESULT_INVALID_PARAMETER; } diff --git a/src/libcharon/plugins/tnccs_11/tnccs_11.c b/src/libcharon/plugins/tnccs_11/tnccs_11.c index cfc29d6ab..53817c710 100644 --- a/src/libcharon/plugins/tnccs_11/tnccs_11.c +++ b/src/libcharon/plugins/tnccs_11/tnccs_11.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 Andreas Steffen + * Copyright (C) 2010-2013 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -43,9 +43,9 @@ typedef struct private_tnccs_11_t private_tnccs_11_t; struct private_tnccs_11_t { /** - * Public tls_t interface. + * Public tnccs_t interface. */ - tls_t public; + tnccs_t public; /** * TNCC if TRUE, TNCS if FALSE @@ -53,6 +53,26 @@ struct private_tnccs_11_t { bool is_server; /** + * Server identity + */ + identification_t *server; + + /** + * Client identity + */ + identification_t *peer; + + /** + * Underlying TNC IF-T transport protocol + */ + tnc_ift_type_t transport; + + /** + * Type of TNC client authentication + */ + u_int32_t auth_type; + + /** * Connection ID assigned to this TNCCS connection */ TNC_ConnectionID connection_id; @@ -495,6 +515,18 @@ METHOD(tls_t, is_server, bool, return this->is_server; } +METHOD(tls_t, get_server_id, identification_t*, + private_tnccs_11_t *this) +{ + return this->server; +} + +METHOD(tls_t, get_peer_id, identification_t*, + private_tnccs_11_t *this) +{ + return this->peer; +} + METHOD(tls_t, get_purpose, tls_purpose_t, private_tnccs_11_t *this) { @@ -528,29 +560,69 @@ METHOD(tls_t, destroy, void, { tnc->tnccs->remove_connection(tnc->tnccs, this->connection_id, this->is_server); + this->server->destroy(this->server); + this->peer->destroy(this->peer); this->mutex->destroy(this->mutex); DESTROY_IF(this->batch); free(this); } +METHOD(tnccs_t, get_transport, tnc_ift_type_t, + private_tnccs_11_t *this) +{ + return this->transport; +} + +METHOD(tnccs_t, set_transport, void, + private_tnccs_11_t *this, tnc_ift_type_t transport) +{ + this->transport = transport; +} + +METHOD(tnccs_t, get_auth_type, u_int32_t, + private_tnccs_11_t *this) +{ + return this->auth_type; +} + +METHOD(tnccs_t, set_auth_type, void, + private_tnccs_11_t *this, u_int32_t auth_type) +{ + this->auth_type = auth_type; +} + /** * See header */ -tls_t *tnccs_11_create(bool is_server) +tnccs_t* tnccs_11_create(bool is_server, + identification_t *server, + identification_t *peer, + tnc_ift_type_t transport) { private_tnccs_11_t *this; INIT(this, .public = { - .process = _process, - .build = _build, - .is_server = _is_server, - .get_purpose = _get_purpose, - .is_complete = _is_complete, - .get_eap_msk = _get_eap_msk, - .destroy = _destroy, + .tls = { + .process = _process, + .build = _build, + .is_server = _is_server, + .get_server_id = _get_server_id, + .get_peer_id = _get_peer_id, + .get_purpose = _get_purpose, + .is_complete = _is_complete, + .get_eap_msk = _get_eap_msk, + .destroy = _destroy, + }, + .get_transport = _get_transport, + .set_transport = _set_transport, + .get_auth_type = _get_auth_type, + .set_auth_type = _set_auth_type, }, .is_server = is_server, + .server = server->clone(server), + .peer = peer->clone(peer), + .transport = transport, .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .max_msg_len = lib->settings->get_int(lib->settings, "%s.plugins.tnccs-11.max_message_size", 45000, diff --git a/src/libcharon/plugins/tnccs_11/tnccs_11.h b/src/libcharon/plugins/tnccs_11/tnccs_11.h index 7331fc8cd..531ebb611 100644 --- a/src/libcharon/plugins/tnccs_11/tnccs_11.h +++ b/src/libcharon/plugins/tnccs_11/tnccs_11.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2010-2013 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -23,14 +23,20 @@ #include <library.h> -#include <tls.h> +#include <tnc/tnccs/tnccs.h> /** * Create an instance of the TNC IF-TNCCS 1.1 protocol handler. * - * @param is_server TRUE to act as TNC Server, FALSE for TNC Client - * @return TNC_IF_TNCCS 1.1 protocol stack + * @param is_server TRUE to act as TNC Server, FALSE for TNC Client + * @param server Server identity + * @param peer Client identity + * @param transport Underlying IF-T transport protocol + * @return TNC_IF_TNCCS 1.1 protocol stack */ -tls_t *tnccs_11_create(bool is_server); +tnccs_t* tnccs_11_create(bool is_server, + identification_t *server, + identification_t *peer, + tnc_ift_type_t transport); #endif /** TNCCS_11_H_ @}*/ diff --git a/src/libcharon/plugins/tnccs_11/tnccs_11_plugin.c b/src/libcharon/plugins/tnccs_11/tnccs_11_plugin.c index cd95afb1e..f534af008 100644 --- a/src/libcharon/plugins/tnccs_11/tnccs_11_plugin.c +++ b/src/libcharon/plugins/tnccs_11/tnccs_11_plugin.c @@ -30,8 +30,6 @@ METHOD(plugin_t, get_features, int, static plugin_feature_t f[] = { PLUGIN_CALLBACK(tnccs_method_register, tnccs_11_create), PLUGIN_PROVIDE(CUSTOM, "tnccs-1.1"), - PLUGIN_DEPENDS(EAP_SERVER, EAP_TNC), - PLUGIN_DEPENDS(EAP_PEER, EAP_TNC), PLUGIN_DEPENDS(CUSTOM, "tnccs-manager"), }; *features = f; @@ -61,4 +59,3 @@ plugin_t *tnccs_11_plugin_create() return &this->plugin; } - diff --git a/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.c b/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.c index 3a2c70f5a..b1f6d1eaa 100644 --- a/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.c +++ b/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.c @@ -386,6 +386,13 @@ static status_t process_tnc_msg(private_pb_tnc_batch_t *this) } else { + if (msg_type == PB_MSG_EXPERIMENTAL && noskip_flag) + { + DBG1(DBG_TNC, "reject PB-Experimental message with NOSKIP flag set"); + msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, + PB_ERROR_UNSUPPORTED_MANDATORY_MSG, this->offset); + goto fatal; + } if (pb_tnc_msg_infos[msg_type].has_noskip_flag != TRUE_OR_FALSE && pb_tnc_msg_infos[msg_type].has_noskip_flag != noskip_flag) { diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c index 2d2c1316b..aa5e9c723 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c @@ -166,6 +166,7 @@ METHOD(pb_tnc_msg_t, process, status_t, { DBG1(DBG_TNC, "PA Subtype 0x%08x is reserved", PA_RESERVED_SUBTYPE); *offset = 4; + return FAILED; } return SUCCESS; diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c index 63d94b94d..2ef8dd6cd 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c @@ -66,24 +66,24 @@ struct private_pb_remediation_parameters_msg_t { pb_tnc_msg_type_t type; /** - * Remediation Parameters Vendor ID + * Remediation Parameters Type */ - u_int32_t vendor_id; + pen_type_t parameters_type; /** - * Remediation Parameters Type + * Remediation Parameters */ - u_int32_t parameters_type; + chunk_t parameters; /** - * Remediation Parameters string + * Remediation String */ - chunk_t remediation_string; + chunk_t string; /** - * Language code + * Remediation Language Code */ - chunk_t language_code; + chunk_t lang_code; /** * Encoded message @@ -113,10 +113,9 @@ METHOD(pb_tnc_msg_t, build, void, return; } writer = bio_writer_create(64); - writer->write_uint32(writer, this->vendor_id); - writer->write_uint32(writer, this->parameters_type); - writer->write_data32(writer, this->remediation_string); - writer->write_data8 (writer, this->language_code); + writer->write_uint32(writer, this->parameters_type.vendor_id); + writer->write_uint32(writer, this->parameters_type.type); + writer->write_data32(writer, this->parameters); this->encoding = writer->get_buf(writer); this->encoding = chunk_clone(this->encoding); @@ -127,83 +126,103 @@ METHOD(pb_tnc_msg_t, process, status_t, private_pb_remediation_parameters_msg_t *this, u_int32_t *offset) { bio_reader_t *reader; + u_int8_t reserved; + status_t status = SUCCESS; + u_char *pos; + + *offset = 0; /* process message */ reader = bio_reader_create(this->encoding); - reader->read_uint32(reader, &this->vendor_id); - reader->read_uint32(reader, &this->parameters_type); + reader->read_uint8 (reader, &reserved); + reader->read_uint24(reader, &this->parameters_type.vendor_id); + reader->read_uint32(reader, &this->parameters_type.type); + reader->read_data (reader, reader->remaining(reader), &this->parameters); - if (!reader->read_data32(reader, &this->remediation_string)) + this->parameters = chunk_clone(this->parameters); + reader->destroy(reader); + + if (this->parameters_type.vendor_id == PEN_IETF && + this->parameters_type.type == PB_REMEDIATION_STRING) { - DBG1(DBG_TNC, "could not parse remediation string"); - reader->destroy(reader); + reader = bio_reader_create(this->parameters); + status = FAILED; *offset = 8; - return FAILED; - }; - this->remediation_string = chunk_clone(this->remediation_string); - if (this->remediation_string.len && - this->remediation_string.ptr[this->remediation_string.len-1] == '\0') - { - DBG1(DBG_TNC, "remediation string must not be null terminated"); + if (!reader->read_data32(reader, &this->string)) + { + DBG1(DBG_TNC, "insufficient data for remediation string"); + goto end; + }; + *offset += 4; + + pos = memchr(this->string.ptr, '\0', this->string.len); + if (pos) + { + DBG1(DBG_TNC, "nul termination in remediation string"); + *offset += (pos - this->string.ptr); + goto end; + } + *offset += this->string.len; + + if (!reader->read_data8(reader, &this->lang_code)) + { + DBG1(DBG_TNC, "insufficient data for remediation string lang code"); + goto end; + }; + *offset += 1; + + pos = memchr(this->lang_code.ptr, '\0', this->lang_code.len); + + if (pos) + { + DBG1(DBG_TNC, "nul termination in remediation string lang code"); + *offset += (pos - this->lang_code.ptr); + goto end; + } + status = SUCCESS; + +end: reader->destroy(reader); - *offset = 11 + this->remediation_string.len; - return FAILED; } - - if (!reader->read_data8(reader, &this->language_code)) - { - DBG1(DBG_TNC, "could not parse language code"); - reader->destroy(reader); - *offset = 12 + this->remediation_string.len; - return FAILED; - }; - this->language_code = chunk_clone(this->language_code); - reader->destroy(reader); - - if (this->language_code.len && - this->language_code.ptr[this->language_code.len-1] == '\0') - { - DBG1(DBG_TNC, "language code must not be null terminated"); - *offset = 12 + this->remediation_string.len + this->language_code.len; - return FAILED; - } - - return SUCCESS; + return status; } METHOD(pb_tnc_msg_t, destroy, void, private_pb_remediation_parameters_msg_t *this) { free(this->encoding.ptr); - free(this->remediation_string.ptr); - free(this->language_code.ptr); + free(this->parameters.ptr); free(this); } -METHOD(pb_remediation_parameters_msg_t, get_vendor_id, u_int32_t, - private_pb_remediation_parameters_msg_t *this, u_int32_t *type) +METHOD(pb_remediation_parameters_msg_t, get_parameters_type, pen_type_t, + private_pb_remediation_parameters_msg_t *this) { - *type = this->parameters_type; - return this->vendor_id; + return this->parameters_type; } -METHOD(pb_remediation_parameters_msg_t, get_remediation_string, chunk_t, +METHOD(pb_remediation_parameters_msg_t, get_parameters, chunk_t, private_pb_remediation_parameters_msg_t *this) { - return this->remediation_string; + return this->parameters; } -METHOD(pb_remediation_parameters_msg_t, get_language_code, chunk_t, - private_pb_remediation_parameters_msg_t *this) +METHOD(pb_remediation_parameters_msg_t, get_string, chunk_t, + private_pb_remediation_parameters_msg_t *this, chunk_t *lang_code) { - return this->language_code; + if (lang_code) + { + *lang_code = this->lang_code; + } + return this->string; } /** * See header */ -pb_tnc_msg_t *pb_remediation_parameters_msg_create_from_data(chunk_t data) +pb_tnc_msg_t* pb_remediation_parameters_msg_create(pen_type_t parameters_type, + chunk_t parameters) { private_pb_remediation_parameters_msg_t *this; @@ -216,24 +235,56 @@ pb_tnc_msg_t *pb_remediation_parameters_msg_create_from_data(chunk_t data) .process = _process, .destroy = _destroy, }, - .get_vendor_id = _get_vendor_id, - .get_remediation_string = _get_remediation_string, - .get_language_code = _get_language_code, + .get_parameters_type = _get_parameters_type, + .get_parameters = _get_parameters, + .get_uri = _get_parameters, + .get_string = _get_string, }, - .type = PB_MSG_REASON_STRING, - .encoding = chunk_clone(data), + .type = PB_MSG_REMEDIATION_PARAMETERS, + .parameters_type = parameters_type, + .parameters = chunk_clone(parameters), ); return &this->public.pb_interface; } /** + * Described in header. + */ +pb_tnc_msg_t* pb_remediation_parameters_msg_create_from_uri(chunk_t uri) +{ + pen_type_t type = { PEN_IETF, PB_REMEDIATION_URI }; + + return pb_remediation_parameters_msg_create(type, uri); +} + +/** + * Described in header. + */ +pb_tnc_msg_t* pb_remediation_parameters_msg_create_from_string(chunk_t string, + chunk_t lang_code) +{ + pb_tnc_msg_t *msg; + bio_writer_t *writer; + pen_type_t type = { PEN_IETF, PB_REMEDIATION_STRING }; + + /* limit language code to 255 octets */ + lang_code.len = min(255, lang_code.len); + + writer = bio_writer_create(4 + string.len + 1 + lang_code.len); + writer->write_data32(writer, string); + writer->write_data8 (writer, lang_code); + + msg = pb_remediation_parameters_msg_create(type, writer->get_buf(writer)); + writer->destroy(writer); + + return msg; +} + +/** * See header */ -pb_tnc_msg_t* pb_remediation_parameters_msg_create(u_int32_t vendor_id, - u_int32_t type, - chunk_t remediation_string, - chunk_t language_code) +pb_tnc_msg_t *pb_remediation_parameters_msg_create_from_data(chunk_t data) { private_pb_remediation_parameters_msg_t *this; @@ -246,16 +297,15 @@ pb_tnc_msg_t* pb_remediation_parameters_msg_create(u_int32_t vendor_id, .process = _process, .destroy = _destroy, }, - .get_vendor_id = _get_vendor_id, - .get_remediation_string = _get_remediation_string, - .get_language_code = _get_language_code, + .get_parameters_type = _get_parameters_type, + .get_parameters = _get_parameters, + .get_uri = _get_parameters, + .get_string = _get_string, }, - .type = PB_MSG_REASON_STRING, - .vendor_id = vendor_id, - .parameters_type = type, - .remediation_string = chunk_clone(remediation_string), - .language_code = chunk_clone(language_code), + .type = PB_MSG_REMEDIATION_PARAMETERS, + .encoding = chunk_clone(data), ); return &this->public.pb_interface; } + diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.h b/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.h index 258d495ec..f3a1c1009 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.h +++ b/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2011-2013 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -26,6 +26,8 @@ typedef struct pb_remediation_parameters_msg_t pb_remediation_parameters_msg_t; #include "pb_tnc_msg.h" +#include <pen/pen.h> + /** * PB-TNC Remediation Parameter Types as defined in section 4.8.1 of RFC 5793 */ @@ -50,41 +52,61 @@ struct pb_remediation_parameters_msg_t { pb_tnc_msg_t pb_interface; /** - * Get Remediation Parameters Vendor ID and Type + * Get the Remediation Parameters Type (Vendor ID and Type) * - * @param type Remediation Parameters Type - * @return Remediation Parameters Vendor ID + * @return Remediation Parameters Type */ - u_int32_t (*get_vendor_id)(pb_remediation_parameters_msg_t *this, - u_int32_t *type); + pen_type_t (*get_parameters_type)(pb_remediation_parameters_msg_t *this); /** - * Get Remediation String + * Get the Remediation Parameters * - * @return Remediation String + * @return Remediation Parameters */ - chunk_t (*get_remediation_string)(pb_remediation_parameters_msg_t *this); + chunk_t (*get_parameters)(pb_remediation_parameters_msg_t *this); /** - * Get Reason String Language Code + * Get the Remediation URI * - * @return Language Code + * @return Remediation URI */ - chunk_t (*get_language_code)(pb_remediation_parameters_msg_t *this); + chunk_t (*get_uri)(pb_remediation_parameters_msg_t *this); + + /** + * Get the Remediation String + * + * @param lang_code Optional Language Code + * @return Remediation String + */ + chunk_t (*get_string)(pb_remediation_parameters_msg_t *this, + chunk_t *lang_code); + }; /** - * Create a PB-Remediation-Parameters message from parameters + * Create a general PB-Remediation-Parameters message + * + * @param parameters_type Remediation Parameters Type + * @param parameters Remediation Parameters + */ +pb_tnc_msg_t* pb_remediation_parameters_msg_create(pen_type_t parameters_type, + chunk_t parameters); + +/** + * Create a PB-Remediation-Parameters message of IETF Type Remediation URI + * + * @param uri Remediation URI + */ +pb_tnc_msg_t* pb_remediation_parameters_msg_create_from_uri(chunk_t uri); + +/** + * Create a PB-Remediation-Parameters message of IETF Type Remediation String * - * @param vendor_id Remediation Parameters Vendor ID - * @param type Remediation Parameters Type - * @param remediation_string Remediation String - * @param language_code Language Code + * @param string Remediation String + * @param lang_code Remediation String Language Code */ -pb_tnc_msg_t* pb_remediation_parameters_msg_create(u_int32_t vendor_id, - u_int32_t type, - chunk_t remediation_string, - chunk_t language_code); +pb_tnc_msg_t* pb_remediation_parameters_msg_create_from_string(chunk_t string, + chunk_t lang_code); /** * Create an unprocessed PB-Remediation-Parameters message from raw data diff --git a/src/libcharon/plugins/tnccs_20/tnccs_20.c b/src/libcharon/plugins/tnccs_20/tnccs_20.c index 6239b152d..29a161e69 100644 --- a/src/libcharon/plugins/tnccs_20/tnccs_20.c +++ b/src/libcharon/plugins/tnccs_20/tnccs_20.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 Sansar Choinyanbuu - * Copyright (C) 2010-2012 Andreas Steffen + * Copyright (C) 2010-2013 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -48,9 +48,9 @@ typedef struct private_tnccs_20_t private_tnccs_20_t; struct private_tnccs_20_t { /** - * Public tls_t interface. + * Public tnccs_t interface. */ - tls_t public; + tnccs_t public; /** * TNCC if TRUE, TNCS if FALSE @@ -58,6 +58,26 @@ struct private_tnccs_20_t { bool is_server; /** + * Server identity + */ + identification_t *server; + + /** + * Client identity + */ + identification_t *peer; + + /** + * Underlying TNC IF-T transport protocol + */ + tnc_ift_type_t transport; + + /** + * Type of TNC client authentication + */ + u_int32_t auth_type; + + /** * PB-TNC State Machine */ pb_tnc_state_machine_t *state_machine; @@ -291,7 +311,36 @@ static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg) } case PB_MSG_REMEDIATION_PARAMETERS: { - /* TODO : Remediation parameters message processing */ + pb_remediation_parameters_msg_t *rem_msg; + pen_type_t parameters_type; + chunk_t parameters, string, lang_code; + + rem_msg = (pb_remediation_parameters_msg_t*)msg; + parameters_type = rem_msg->get_parameters_type(rem_msg); + parameters = rem_msg->get_parameters(rem_msg); + + if (parameters_type.vendor_id == PEN_IETF) + { + switch (parameters_type.type) + { + case PB_REMEDIATION_URI: + DBG1(DBG_TNC, "remediation uri: %.*s", + parameters.len, parameters.ptr); + break; + case PB_REMEDIATION_STRING: + string = rem_msg->get_string(rem_msg, &lang_code); + DBG1(DBG_TNC, "remediation string: [%.*s]\n%.*s", + lang_code.len, lang_code.ptr, + string.len, string.ptr); + break; + default: + DBG1(DBG_TNC, "remediation parameters: %B", ¶meters); + } + } + else + { + DBG1(DBG_TNC, "remediation parameters: %B", ¶meters); + } break; } case PB_MSG_ERROR: @@ -356,9 +405,12 @@ static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg) lang_msg = (pb_language_preference_msg_t*)msg; lang = lang_msg->get_language_preference(lang_msg); - DBG2(DBG_TNC, "setting language preference to '%.*s'", - (int)lang.len, lang.ptr); - this->recs->set_preferred_language(this->recs, lang); + if (this->recs) + { + DBG2(DBG_TNC, "setting language preference to '%.*s'", + (int)lang.len, lang.ptr); + this->recs->set_preferred_language(this->recs, lang); + } break; } case PB_MSG_REASON_STRING: @@ -759,6 +811,18 @@ METHOD(tls_t, is_server, bool, return this->is_server; } +METHOD(tls_t, get_server_id, identification_t*, + private_tnccs_20_t *this) +{ + return this->server; +} + +METHOD(tls_t, get_peer_id, identification_t*, + private_tnccs_20_t *this) +{ + return this->peer; +} + METHOD(tls_t, get_purpose, tls_purpose_t, private_tnccs_20_t *this) { @@ -792,6 +856,8 @@ METHOD(tls_t, destroy, void, { tnc->tnccs->remove_connection(tnc->tnccs, this->connection_id, this->is_server); + this->server->destroy(this->server); + this->peer->destroy(this->peer); this->state_machine->destroy(this->state_machine); this->mutex->destroy(this->mutex); this->messages->destroy_offset(this->messages, @@ -799,24 +865,62 @@ METHOD(tls_t, destroy, void, free(this); } +METHOD(tnccs_t, get_transport, tnc_ift_type_t, + private_tnccs_20_t *this) +{ + return this->transport; +} + +METHOD(tnccs_t, set_transport, void, + private_tnccs_20_t *this, tnc_ift_type_t transport) +{ + this->transport = transport; +} + +METHOD(tnccs_t, get_auth_type, u_int32_t, + private_tnccs_20_t *this) +{ + return this->auth_type; +} + +METHOD(tnccs_t, set_auth_type, void, + private_tnccs_20_t *this, u_int32_t auth_type) +{ + this->auth_type = auth_type; +} + /** * See header */ -tls_t *tnccs_20_create(bool is_server) +tnccs_t* tnccs_20_create(bool is_server, + identification_t *server, + identification_t *peer, + tnc_ift_type_t transport) { private_tnccs_20_t *this; INIT(this, .public = { - .process = _process, - .build = _build, - .is_server = _is_server, - .get_purpose = _get_purpose, - .is_complete = _is_complete, - .get_eap_msk = _get_eap_msk, - .destroy = _destroy, + .tls = { + .process = _process, + .build = _build, + .is_server = _is_server, + .get_server_id = _get_server_id, + .get_peer_id = _get_peer_id, + .get_purpose = _get_purpose, + .is_complete = _is_complete, + .get_eap_msk = _get_eap_msk, + .destroy = _destroy, + }, + .get_transport = _get_transport, + .set_transport = _set_transport, + .get_auth_type = _get_auth_type, + .set_auth_type = _set_auth_type, }, .is_server = is_server, + .server = server->clone(server), + .peer = peer->clone(peer), + .transport = transport, .state_machine = pb_tnc_state_machine_create(is_server), .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .messages = linked_list_create(), diff --git a/src/libcharon/plugins/tnccs_20/tnccs_20.h b/src/libcharon/plugins/tnccs_20/tnccs_20.h index 400d1dc12..314935069 100644 --- a/src/libcharon/plugins/tnccs_20/tnccs_20.h +++ b/src/libcharon/plugins/tnccs_20/tnccs_20.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2010-2013 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -23,14 +23,20 @@ #include <library.h> -#include <tls.h> +#include <tnc/tnccs/tnccs.h> /** * Create an instance of the TNC IF-TNCCS 2.0 protocol handler. * - * @param is_server TRUE to act as TNC Server, FALSE for TNC Client - * @return TNC_IF_TNCCS 2.0 protocol stack + * @param is_server TRUE to act as TNC Server, FALSE for TNC Client + * @param server Server identity + * @param peer Client identity + * @param transport Underlying IF-T transport protocol + * @return TNC_IF_TNCCS 2.0 protocol stack */ -tls_t *tnccs_20_create(bool is_server); +tnccs_t* tnccs_20_create(bool is_server, + identification_t *server, + identification_t *peer, + tnc_ift_type_t transport); #endif /** TNCCS_20_H_ @}*/ diff --git a/src/libcharon/plugins/tnccs_20/tnccs_20_plugin.c b/src/libcharon/plugins/tnccs_20/tnccs_20_plugin.c index 4f419ecf0..f74306c8c 100644 --- a/src/libcharon/plugins/tnccs_20/tnccs_20_plugin.c +++ b/src/libcharon/plugins/tnccs_20/tnccs_20_plugin.c @@ -30,8 +30,6 @@ METHOD(plugin_t, get_features, int, static plugin_feature_t f[] = { PLUGIN_CALLBACK(tnccs_method_register, tnccs_20_create), PLUGIN_PROVIDE(CUSTOM, "tnccs-2.0"), - PLUGIN_DEPENDS(EAP_SERVER, EAP_TNC), - PLUGIN_DEPENDS(EAP_PEER, EAP_TNC), PLUGIN_DEPENDS(CUSTOM, "tnccs-manager"), }; *features = f; @@ -61,4 +59,3 @@ plugin_t *tnccs_20_plugin_create() return &this->plugin; } - diff --git a/src/libcharon/plugins/tnccs_dynamic/tnccs_dynamic.c b/src/libcharon/plugins/tnccs_dynamic/tnccs_dynamic.c index 03795a947..d4fc6a6f7 100644 --- a/src/libcharon/plugins/tnccs_dynamic/tnccs_dynamic.c +++ b/src/libcharon/plugins/tnccs_dynamic/tnccs_dynamic.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2013 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -27,14 +27,35 @@ typedef struct private_tnccs_dynamic_t private_tnccs_dynamic_t; struct private_tnccs_dynamic_t { /** - * Public tls_t interface. + * Public tnccs_t interface. */ - tls_t public; + tnccs_t public; + + /** + * Server identity + */ + identification_t *server; + + /** + * Client identity + */ + identification_t *peer; /** * Detected TNC IF-TNCCS stack */ tls_t *tls; + + /** + * Underlying TNC IF-T transport protocol + */ + tnc_ift_type_t transport; + + /** + * Type of TNC client authentication + */ + u_int32_t auth_type; + }; /** @@ -66,6 +87,7 @@ METHOD(tls_t, process, status_t, private_tnccs_dynamic_t *this, void *buf, size_t buflen) { tnccs_type_t type; + tnccs_t *tnccs; if (!this->tls) { @@ -76,12 +98,15 @@ METHOD(tls_t, process, status_t, type = determine_tnccs_protocol(*(char*)buf); DBG1(DBG_TNC, "%N protocol detected dynamically", tnccs_type_names, type); - this->tls = (tls_t*)tnc->tnccs->create_instance(tnc->tnccs, type, TRUE); - if (!this->tls) + tnccs = tnc->tnccs->create_instance(tnc->tnccs, type, TRUE, + this->server, this->peer, this->transport); + if (!tnccs) { DBG1(DBG_TNC, "N% protocol not supported", tnccs_type_names, type); return FAILED; } + tnccs->set_auth_type(tnccs, this->auth_type); + this->tls = &tnccs->tls; } return this->tls->process(this->tls, buf, buflen); } @@ -98,6 +123,18 @@ METHOD(tls_t, is_server, bool, return TRUE; } +METHOD(tls_t, get_server_id, identification_t*, + private_tnccs_dynamic_t *this) +{ + return this->server; +} + +METHOD(tls_t, get_peer_id, identification_t*, + private_tnccs_dynamic_t *this) +{ + return this->peer; +} + METHOD(tls_t, get_purpose, tls_purpose_t, private_tnccs_dynamic_t *this) { @@ -120,26 +157,66 @@ METHOD(tls_t, destroy, void, private_tnccs_dynamic_t *this) { DESTROY_IF(this->tls); + this->server->destroy(this->server); + this->peer->destroy(this->peer); free(this); } +METHOD(tnccs_t, get_transport, tnc_ift_type_t, + private_tnccs_dynamic_t *this) +{ + return this->transport; +} + +METHOD(tnccs_t, set_transport, void, + private_tnccs_dynamic_t *this, tnc_ift_type_t transport) +{ + this->transport = transport; +} + +METHOD(tnccs_t, get_auth_type, u_int32_t, + private_tnccs_dynamic_t *this) +{ + return this->auth_type; +} + +METHOD(tnccs_t, set_auth_type, void, + private_tnccs_dynamic_t *this, u_int32_t auth_type) +{ + this->auth_type = auth_type; +} + /** * See header */ -tls_t *tnccs_dynamic_create(bool is_server) +tnccs_t* tnccs_dynamic_create(bool is_server, + identification_t *server, + identification_t *peer, + tnc_ift_type_t transport) { private_tnccs_dynamic_t *this; INIT(this, .public = { - .process = _process, - .build = _build, - .is_server = _is_server, - .get_purpose = _get_purpose, - .is_complete = _is_complete, - .get_eap_msk = _get_eap_msk, - .destroy = _destroy, + .tls = { + .process = _process, + .build = _build, + .is_server = _is_server, + .get_server_id = _get_server_id, + .get_peer_id = _get_peer_id, + .get_purpose = _get_purpose, + .is_complete = _is_complete, + .get_eap_msk = _get_eap_msk, + .destroy = _destroy, + }, + .get_transport = _get_transport, + .set_transport = _set_transport, + .get_auth_type = _get_auth_type, + .set_auth_type = _set_auth_type, }, + .server = server->clone(server), + .peer = peer->clone(peer), + .transport = transport, ); return &this->public; diff --git a/src/libcharon/plugins/tnccs_dynamic/tnccs_dynamic.h b/src/libcharon/plugins/tnccs_dynamic/tnccs_dynamic.h index 42410b17f..e4cff74b8 100644 --- a/src/libcharon/plugins/tnccs_dynamic/tnccs_dynamic.h +++ b/src/libcharon/plugins/tnccs_dynamic/tnccs_dynamic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2013 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -23,14 +23,20 @@ #include <library.h> -#include <tls.h> +#include <tnc/tnccs/tnccs.h> /** * Create an instance of a dynamic TNC IF-TNCCS protocol handler. * - * @param is_server TRUE to act as TNC Server, FALSE for TNC Client - * @return dynamic TNC IF-TNCCS protocol stack + * @param is_server TRUE to act as TNC Server, FALSE for TNC Client + * @param server Server identity + * @param peer Client identity + * @param transport Underlying IF-T transport protocol + * @return dynamic TNC IF-TNCCS protocol stack */ -tls_t *tnccs_dynamic_create(bool is_server); +tnccs_t* tnccs_dynamic_create(bool is_server, + identification_t *server, + identification_t *peer, + tnc_ift_type_t transport); #endif /** TNCCS_DYNAMIC_H_ @}*/ diff --git a/src/libcharon/plugins/tnccs_dynamic/tnccs_dynamic_plugin.c b/src/libcharon/plugins/tnccs_dynamic/tnccs_dynamic_plugin.c index 6f581c543..aac57813a 100644 --- a/src/libcharon/plugins/tnccs_dynamic/tnccs_dynamic_plugin.c +++ b/src/libcharon/plugins/tnccs_dynamic/tnccs_dynamic_plugin.c @@ -32,8 +32,6 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(CUSTOM, "tnccs-dynamic"), PLUGIN_DEPENDS(CUSTOM, "tnccs-1.1"), PLUGIN_DEPENDS(CUSTOM, "tnccs-2.0"), - PLUGIN_DEPENDS(EAP_SERVER, EAP_TNC), - PLUGIN_DEPENDS(EAP_PEER, EAP_TNC), }; *features = f; return countof(f); @@ -62,4 +60,3 @@ plugin_t *tnccs_dynamic_plugin_create() return &this->plugin; } - diff --git a/src/libcharon/plugins/uci/uci_config.c b/src/libcharon/plugins/uci/uci_config.c index b7df65d1c..b58d120c1 100644 --- a/src/libcharon/plugins/uci/uci_config.c +++ b/src/libcharon/plugins/uci/uci_config.c @@ -156,7 +156,7 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, local_addr, FALSE, charon->socket->get_port(charon->socket, FALSE), remote_addr, FALSE, IKEV2_UDP_PORT, - FRAGMENTATION_NO); + FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, create_proposal(ike_proposal, PROTO_IKE)); this->peer_cfg = peer_cfg_create( name, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_NO, @@ -255,7 +255,7 @@ METHOD(enumerator_t, ike_enumerator_enumerate, bool, local_addr, FALSE, charon->socket->get_port(charon->socket, FALSE), remote_addr, FALSE, IKEV2_UDP_PORT, - FRAGMENTATION_NO); + FRAGMENTATION_NO, 0); this->ike_cfg->add_proposal(this->ike_cfg, create_proposal(ike_proposal, PROTO_IKE)); diff --git a/src/libcharon/sa/eap/eap_inner_method.h b/src/libcharon/sa/eap/eap_inner_method.h new file mode 100644 index 000000000..500852965 --- /dev/null +++ b/src/libcharon/sa/eap/eap_inner_method.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013 Andreas Steffen + * HSR 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 eap_inner_method eap_inner_method + * @{ @ingroup eap + */ + +#ifndef EAP_INNER_METHOD_H_ +#define EAP_INNER_METHOD_H_ + +typedef struct eap_inner_method_t eap_inner_method_t; + +#include <library.h> + +#include "eap_method.h" + +/** + * Interface of a weak inner EAP method like EAP-TNC or PT-EAP + * that must be encapsulated in a strong TLS-based EAP method + */ +struct eap_inner_method_t { + + /* + * Public EAP method interface + */ + eap_method_t eap_method; + + /* + * Get type of outer EAP authentication method + * + * @return outer EAP authentication type + */ + eap_type_t (*get_auth_type)(eap_inner_method_t *this); + + /* + * Set type of outer EAP Client/Server authentication + * + * @param type outer EAP authentication type + */ + void (*set_auth_type)(eap_inner_method_t *this, eap_type_t type); + +}; + +#endif /** EAP_INNER_METHOD_H_ @}*/ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 4029db11d..0157599c1 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -900,7 +900,7 @@ METHOD(ike_sa_t, update_hosts, void, else { /* update our address in any case */ - if (!me->equals(me, this->my_host)) + if (force && !me->equals(me, this->my_host)) { set_my_host(this, me->clone(me)); update = TRUE; @@ -909,7 +909,8 @@ METHOD(ike_sa_t, update_hosts, void, if (!other->equals(other, this->other_host)) { /* update others address if we are NOT NATed */ - if (force || !has_condition(this, COND_NAT_HERE)) + if ((has_condition(this, COND_NAT_THERE) && + !has_condition(this, COND_NAT_HERE)) || force ) { set_other_host(this, other->clone(other)); update = TRUE; @@ -939,14 +940,38 @@ METHOD(ike_sa_t, update_hosts, void, } } +/** + * Set configured DSCP value on packet + */ +static void set_dscp(private_ike_sa_t *this, packet_t *packet) +{ + ike_cfg_t *ike_cfg; + + /* prefer IKE config on peer_cfg, as its selection is more accurate + * then the initial IKE config */ + if (this->peer_cfg) + { + ike_cfg = this->peer_cfg->get_ike_cfg(this->peer_cfg); + } + else + { + ike_cfg = this->ike_cfg; + } + if (ike_cfg) + { + packet->set_dscp(packet, ike_cfg->get_dscp(ike_cfg)); + } +} + 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 */ + { /* already encoded in task, but set DSCP value */ *packet = message->get_packet(message); + set_dscp(this, *packet); return SUCCESS; } this->stats[STAT_OUTBOUND] = time_monotonic(NULL); @@ -955,6 +980,7 @@ METHOD(ike_sa_t, generate_message, status_t, status = message->generate(message, this->keymat, packet); if (status == SUCCESS) { + set_dscp(this, *packet); charon->bus->message(charon->bus, message, FALSE, FALSE); } return status; @@ -1225,24 +1251,6 @@ METHOD(ike_sa_t, process_message, status_t, { /* do not handle messages in passive state */ return FAILED; } - switch (message->get_exchange_type(message)) - { - case ID_PROT: - case AGGRESSIVE: - case IKE_SA_INIT: - case IKE_AUTH: - if (this->state != IKE_CREATED && - this->state != IKE_CONNECTING && - message->get_first_payload_type(message) != FRAGMENT_V1) - { - DBG1(DBG_IKE, "ignoring %N in established IKE_SA state", - exchange_type_names, message->get_exchange_type(message)); - return FAILED; - } - break; - default: - break; - } if (message->get_major_version(message) != this->version) { DBG1(DBG_IKE, "ignoring %N IKEv%u exchange on %N SA", diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 2ac8c3123..c5e6bf4bd 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -108,9 +108,9 @@ struct entry_t { identification_t *other_id; /** - * message ID currently processing, if any + * message ID or hash of currently processing message, -1 if none */ - u_int32_t message_id; + u_int32_t processing; }; /** @@ -135,23 +135,12 @@ static status_t entry_destroy(entry_t *this) */ static entry_t *entry_create() { - entry_t *this = malloc_thing(entry_t); - - this->waiting_threads = 0; - this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT); - - /* we set checkout flag when we really give it out */ - this->checked_out = FALSE; - this->driveout_new_threads = FALSE; - this->driveout_waiting_threads = FALSE; - this->message_id = -1; - this->init_hash = chunk_empty; - this->other = NULL; - this->half_open = FALSE; - this->my_id = NULL; - this->other_id = NULL; - this->ike_sa_id = NULL; - this->ike_sa = NULL; + entry_t *this; + + INIT(this, + .condvar = condvar_create(CONDVAR_TYPE_DEFAULT), + .processing = -1, + ); return this; } @@ -1171,6 +1160,20 @@ METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*, return ike_sa; } +/** + * Get the message ID or message hash to detect early retransmissions + */ +static u_int32_t get_message_id_or_hash(message_t *message) +{ + /* Use the message ID, or the message hash in IKEv1 Main/Aggressive mode */ + if (message->get_major_version(message) == IKEV1_MAJOR_VERSION && + message->get_message_id(message) == 0) + { + return chunk_hash(message->get_packet_data(message)); + } + return message->get_message_id(message); +} + METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, private_ike_sa_manager_t* this, message_t *message) { @@ -1246,7 +1249,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, entry->checked_out = TRUE; unlock_single_segment(this, segment); - entry->message_id = message->get_message_id(message); + entry->processing = get_message_id_or_hash(message); entry->init_hash = hash; DBG2(DBG_MGR, "created IKE_SA %s[%u]", @@ -1290,12 +1293,11 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, if (get_entry_by_id(this, id, &entry, &segment) == SUCCESS) { - /* only check out in IKEv2 if we are not already processing it */ - if (message->get_request(message) && - message->get_message_id(message) == entry->message_id) + /* only check out if we are not already processing it. */ + if (entry->processing == get_message_id_or_hash(message)) { DBG1(DBG_MGR, "ignoring request with ID %u, already processing", - entry->message_id); + entry->processing); } else if (wait_for_entry(this, entry, segment)) { @@ -1305,7 +1307,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, entry->checked_out = TRUE; if (message->get_first_payload_type(message) != FRAGMENT_V1) { - entry->message_id = message->get_message_id(message); + entry->processing = get_message_id_or_hash(message); } if (ike_id->get_responder_spi(ike_id) == 0) { @@ -1564,7 +1566,7 @@ METHOD(ike_sa_manager_t, checkin, void, entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa)); /* signal waiting threads */ entry->checked_out = FALSE; - entry->message_id = -1; + entry->processing = -1; /* check if this SA is half-open */ if (entry->half_open && ike_sa->get_state(ike_sa) != IKE_CONNECTING) { @@ -1782,6 +1784,7 @@ METHOD(ike_sa_manager_t, check_uniqueness, bool, { DBG1(DBG_IKE, "destroying duplicate IKE_SA for peer '%Y', " "received INITIAL_CONTACT", other); + charon->bus->ike_updown(charon->bus, duplicate, FALSE); checkin_and_destroy(this, duplicate); continue; } diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 8a4761d5c..7a84d1cef 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1471,6 +1471,21 @@ METHOD(task_manager_t, process_message, status_t, charon->bus->alert(charon->bus, ALERT_RETRANSMIT_RECEIVE, msg); return SUCCESS; } + + /* reject Main/Agressive Modes once established */ + if (msg->get_exchange_type(msg) == ID_PROT || + msg->get_exchange_type(msg) == AGGRESSIVE) + { + if (this->ike_sa->get_state(this->ike_sa) != IKE_CREATED && + this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING && + msg->get_first_payload_type(msg) != FRAGMENT_V1) + { + DBG1(DBG_IKE, "ignoring %N in established IKE_SA state", + exchange_type_names, msg->get_exchange_type(msg)); + return FAILED; + } + } + if (msg->get_exchange_type(msg) == TRANSACTION && this->active_tasks->get_count(this->active_tasks)) { /* main mode not yet complete, queue XAuth/Mode config tasks */ @@ -2030,4 +2045,3 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) return &this->public; } - diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index ea0117c54..29d8d830e 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1123,6 +1123,18 @@ METHOD(task_manager_t, process_message, status_t, { if (mid == this->responding.mid) { + /* reject initial messages once established */ + if (msg->get_exchange_type(msg) == IKE_SA_INIT || + msg->get_exchange_type(msg) == IKE_AUTH) + { + if (this->ike_sa->get_state(this->ike_sa) != IKE_CREATED && + this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING) + { + DBG1(DBG_IKE, "ignoring %N in established IKE_SA state", + exchange_type_names, msg->get_exchange_type(msg)); + return FAILED; + } + } if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED || this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING || msg->get_exchange_type(msg) != IKE_SA_INIT) diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c index eb3972c29..32c0e8c4a 100644 --- a/src/libcharon/sa/ikev2/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -18,6 +18,7 @@ #include "child_create.h" #include <daemon.h> +#include <hydra.h> #include <sa/ikev2/keymat_v2.h> #include <crypto/diffie_hellman.h> #include <credentials/certificates/x509.h> @@ -615,6 +616,7 @@ static void build_payloads(private_child_create_t *this, message_t *message) nonce_payload_t *nonce_payload; ke_payload_t *ke_payload; ts_payload_t *ts_payload; + kernel_feature_t features; /* add SA payload */ if (this->initiator) @@ -661,6 +663,13 @@ static void build_payloads(private_child_create_t *this, message_t *message) default: break; } + + features = hydra->kernel_interface->get_features(hydra->kernel_interface); + if (!(features & KERNEL_ESP_V3_TFC)) + { + message->add_notify(message, FALSE, ESP_TFC_PADDING_NOT_SUPPORTED, + chunk_empty); + } } /** diff --git a/src/libcharon/sa/ikev2/tasks/ike_dpd.c b/src/libcharon/sa/ikev2/tasks/ike_dpd.c index 28ccc2efe..7a33f7938 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_dpd.c +++ b/src/libcharon/sa/ikev2/tasks/ike_dpd.c @@ -37,12 +37,6 @@ METHOD(task_t, return_need_more, status_t, return NEED_MORE; } -METHOD(task_t, return_success, status_t, - private_ike_dpd_t *this, message_t *message) -{ - return SUCCESS; -} - METHOD(task_t, get_type, task_type_t, private_ike_dpd_t *this) { @@ -82,11 +76,11 @@ ike_dpd_t *ike_dpd_create(bool initiator) if (initiator) { this->public.task.build = _return_need_more; - this->public.task.process = _return_success; + this->public.task.process = (void*)return_success; } else { - this->public.task.build = _return_success; + this->public.task.build = (void*)return_success; this->public.task.process = _return_need_more; } |