summaryrefslogtreecommitdiff
path: root/src/charon/sa
diff options
context:
space:
mode:
Diffstat (limited to 'src/charon/sa')
-rw-r--r--src/charon/sa/authenticators/authenticator.c47
-rw-r--r--src/charon/sa/authenticators/authenticator.h75
-rw-r--r--src/charon/sa/authenticators/eap/eap_aka.c1440
-rw-r--r--src/charon/sa/authenticators/eap/eap_aka.h141
-rw-r--r--src/charon/sa/authenticators/eap/eap_identity.c135
-rw-r--r--src/charon/sa/authenticators/eap/eap_identity.h59
-rw-r--r--src/charon/sa/authenticators/eap/eap_manager.c172
-rw-r--r--src/charon/sa/authenticators/eap/eap_manager.h84
-rw-r--r--src/charon/sa/authenticators/eap/eap_md5.c282
-rw-r--r--src/charon/sa/authenticators/eap/eap_md5.h59
-rw-r--r--src/charon/sa/authenticators/eap/eap_method.c189
-rw-r--r--src/charon/sa/authenticators/eap/eap_method.h107
-rw-r--r--src/charon/sa/authenticators/eap/eap_sim.c1125
-rw-r--r--src/charon/sa/authenticators/eap/eap_sim.h114
-rw-r--r--src/charon/sa/authenticators/eap/sim/eap_sim_file.c288
-rw-r--r--src/charon/sa/authenticators/eap_authenticator.c30
-rw-r--r--src/charon/sa/authenticators/eap_authenticator.h36
-rw-r--r--src/charon/sa/authenticators/psk_authenticator.c85
-rw-r--r--src/charon/sa/authenticators/psk_authenticator.h28
-rw-r--r--src/charon/sa/authenticators/pubkey_authenticator.c225
-rw-r--r--src/charon/sa/authenticators/pubkey_authenticator.h (renamed from src/charon/sa/authenticators/rsa_authenticator.h)41
-rw-r--r--src/charon/sa/authenticators/rsa_authenticator.c160
-rw-r--r--src/charon/sa/child_sa.c169
-rw-r--r--src/charon/sa/child_sa.h103
-rw-r--r--src/charon/sa/connect_manager.c607
-rw-r--r--src/charon/sa/connect_manager.h74
-rw-r--r--src/charon/sa/ike_sa.c779
-rw-r--r--src/charon/sa/ike_sa.h378
-rw-r--r--src/charon/sa/ike_sa_id.c10
-rw-r--r--src/charon/sa/ike_sa_id.h61
-rw-r--r--src/charon/sa/ike_sa_manager.c349
-rw-r--r--src/charon/sa/ike_sa_manager.h85
-rw-r--r--src/charon/sa/mediation_manager.c10
-rw-r--r--src/charon/sa/mediation_manager.h43
-rw-r--r--src/charon/sa/task_manager.c51
-rw-r--r--src/charon/sa/task_manager.h63
-rw-r--r--src/charon/sa/tasks/child_create.c147
-rw-r--r--src/charon/sa/tasks/child_create.h34
-rw-r--r--src/charon/sa/tasks/child_delete.c44
-rw-r--r--src/charon/sa/tasks/child_delete.h28
-rw-r--r--src/charon/sa/tasks/child_rekey.c9
-rw-r--r--src/charon/sa/tasks/child_rekey.h28
-rw-r--r--src/charon/sa/tasks/ike_auth.c165
-rw-r--r--src/charon/sa/tasks/ike_auth.h25
-rw-r--r--src/charon/sa/tasks/ike_auth_lifetime.c9
-rw-r--r--src/charon/sa/tasks/ike_auth_lifetime.h26
-rw-r--r--src/charon/sa/tasks/ike_cert.c366
-rw-r--r--src/charon/sa/tasks/ike_cert_post.c260
-rw-r--r--src/charon/sa/tasks/ike_cert_post.h55
-rw-r--r--src/charon/sa/tasks/ike_cert_pre.c476
-rw-r--r--src/charon/sa/tasks/ike_cert_pre.h (renamed from src/charon/sa/tasks/ike_cert.h)40
-rw-r--r--src/charon/sa/tasks/ike_config.c49
-rw-r--r--src/charon/sa/tasks/ike_config.h25
-rw-r--r--src/charon/sa/tasks/ike_delete.c21
-rw-r--r--src/charon/sa/tasks/ike_delete.h25
-rw-r--r--src/charon/sa/tasks/ike_dpd.c9
-rw-r--r--src/charon/sa/tasks/ike_dpd.h25
-rw-r--r--src/charon/sa/tasks/ike_init.c144
-rw-r--r--src/charon/sa/tasks/ike_init.h28
-rw-r--r--src/charon/sa/tasks/ike_me.c (renamed from src/charon/sa/tasks/ike_p2p.c)300
-rw-r--r--src/charon/sa/tasks/ike_me.h (renamed from src/charon/sa/tasks/ike_p2p.h)72
-rw-r--r--src/charon/sa/tasks/ike_mobike.c64
-rw-r--r--src/charon/sa/tasks/ike_mobike.h35
-rw-r--r--src/charon/sa/tasks/ike_natd.c45
-rw-r--r--src/charon/sa/tasks/ike_natd.h25
-rw-r--r--src/charon/sa/tasks/ike_reauth.c41
-rw-r--r--src/charon/sa/tasks/ike_reauth.h26
-rw-r--r--src/charon/sa/tasks/ike_rekey.c9
-rw-r--r--src/charon/sa/tasks/ike_rekey.h28
-rw-r--r--src/charon/sa/tasks/task.c18
-rw-r--r--src/charon/sa/tasks/task.h58
71 files changed, 3881 insertions, 6582 deletions
diff --git a/src/charon/sa/authenticators/authenticator.c b/src/charon/sa/authenticators/authenticator.c
index 707aae9ad..c301e4933 100644
--- a/src/charon/sa/authenticators/authenticator.c
+++ b/src/charon/sa/authenticators/authenticator.c
@@ -1,11 +1,5 @@
-/**
- * @file authenticator.c
- *
- * @brief Generic constructor for authenticators.
- *
- */
-
/*
+ * Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -18,13 +12,15 @@
* 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.
+ *
+ * $Id: authenticator.c 4051 2008-06-10 09:08:27Z tobias $
*/
#include <string.h>
#include "authenticator.h"
-#include <sa/authenticators/rsa_authenticator.h>
+#include <sa/authenticators/pubkey_authenticator.h>
#include <sa/authenticators/psk_authenticator.h>
#include <sa/authenticators/eap_authenticator.h>
@@ -33,23 +29,46 @@ ENUM_BEGIN(auth_method_names, AUTH_RSA, AUTH_DSS,
"RSA signature",
"pre-shared key",
"DSS signature");
-ENUM_NEXT(auth_method_names, AUTH_EAP, AUTH_EAP, AUTH_DSS,
+ENUM_NEXT(auth_method_names, AUTH_ECDSA_256, AUTH_ECDSA_521, AUTH_DSS,
+ "ECDSA-256 signature",
+ "ECDSA-384 signature",
+ "ECDSA-521 signature");
+ENUM_NEXT(auth_method_names, AUTH_EAP, AUTH_EAP, AUTH_ECDSA_521,
"EAP");
ENUM_END(auth_method_names, AUTH_EAP);
-/*
+/**
* Described in header.
*/
-authenticator_t *authenticator_create(ike_sa_t *ike_sa, auth_method_t auth_method)
+authenticator_t *authenticator_create(ike_sa_t *ike_sa, config_auth_method_t auth_method)
{
switch (auth_method)
{
+ case CONF_AUTH_PUBKEY:
+ return (authenticator_t*)pubkey_authenticator_create(ike_sa);
+ case CONF_AUTH_PSK:
+ return (authenticator_t*)psk_authenticator_create(ike_sa);
+ case CONF_AUTH_EAP:
+ return (authenticator_t*)eap_authenticator_create(ike_sa);
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * Described in header.
+ */
+authenticator_t *authenticator_create_from_auth_payload(ike_sa_t *ike_sa, auth_payload_t *auth_payload)
+{
+ switch (auth_payload->get_auth_method(auth_payload))
+ {
case AUTH_RSA:
- return (authenticator_t*)rsa_authenticator_create(ike_sa);
+ case AUTH_ECDSA_256:
+ case AUTH_ECDSA_384:
+ case AUTH_ECDSA_521:
+ return (authenticator_t*)pubkey_authenticator_create(ike_sa);
case AUTH_PSK:
return (authenticator_t*)psk_authenticator_create(ike_sa);
- case AUTH_EAP:
- return (authenticator_t*)eap_authenticator_create(ike_sa);
default:
return NULL;
}
diff --git a/src/charon/sa/authenticators/authenticator.h b/src/charon/sa/authenticators/authenticator.h
index c7b0fc81a..3c961d23e 100644
--- a/src/charon/sa/authenticators/authenticator.h
+++ b/src/charon/sa/authenticators/authenticator.h
@@ -1,11 +1,5 @@
-/**
- * @file authenticator.h
- *
- * @brief Interface of authenticator_t.
- *
- */
-
/*
+ * Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -19,6 +13,13 @@
* 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.
+ *
+ * $Id: authenticator.h 4051 2008-06-10 09:08:27Z tobias $
+ */
+
+/**
+ * @defgroup authenticator authenticator
+ * @{ @ingroup authenticators
*/
#ifndef AUTHENTICATOR_H_
@@ -29,12 +30,11 @@ typedef struct authenticator_t authenticator_t;
#include <library.h>
#include <sa/ike_sa.h>
+#include <config/peer_cfg.h>
#include <encoding/payloads/auth_payload.h>
/**
* Method to use for authentication.
- *
- * @ingroup authenticators
*/
enum auth_method_t {
/**
@@ -57,6 +57,21 @@ enum auth_method_t {
AUTH_DSS = 3,
/**
+ * ECDSA with SHA-256 on the P-256 curve as specified in RFC 4754
+ */
+ AUTH_ECDSA_256 = 9,
+
+ /**
+ * ECDSA with SHA-384 on the P-384 curve as specified in RFC 4754
+ */
+ AUTH_ECDSA_384 = 10,
+
+ /**
+ * ECDSA with SHA-512 on the P-521 curve as specified in RFC 4754
+ */
+ AUTH_ECDSA_521 = 11,
+
+ /**
* EAP authentication. This value is never negotiated and therefore
* a value from private use.
*/
@@ -65,29 +80,22 @@ enum auth_method_t {
/**
* enum names for auth_method_t.
- *
- * @ingroup authenticators
*/
extern enum_name_t *auth_method_names;
/**
- * @brief Authenticator interface implemented by the various authenticators.
+ * Authenticator interface implemented by the various authenticators.
*
* Currently the following two AUTH methods are supported:
- * - shared key message integrity code (AUTH_PSK)
- * - RSA digital signature (AUTH_RSA)
- *
- * @b Constructors:
- * - authenticator_create()
- *
- * @ingroup authenticators
+ * - shared key message integrity code
+ * - RSA digital signature
+ * - ECDSA is supported using OpenSSL
*/
struct authenticator_t {
/**
- * @brief Verify a received authentication payload.
+ * Verify a received authentication payload.
*
- * @param this calling object
* @param ike_sa_init binary representation of received ike_sa_init
* @param my_nonce the sent nonce
* @param auth_payload authentication payload to verify
@@ -102,9 +110,8 @@ struct authenticator_t {
chunk_t my_nonce, auth_payload_t *auth_payload);
/**
- * @brief Build an authentication payload to send to the other peer.
+ * Build an authentication payload to send to the other peer.
*
- * @param this calling object
* @param ike_sa_init binary representation of sent ike_sa_init
* @param other_nonce the received nonce
* @param[out] auth_payload the resulting authentication payload
@@ -117,23 +124,29 @@ struct authenticator_t {
chunk_t other_nonce, auth_payload_t **auth_payload);
/**
- * @brief Destroys a authenticator_t object.
- *
- * @param this calling object
+ * Destroys a authenticator_t object.
*/
void (*destroy) (authenticator_t *this);
};
/**
- * @brief Creates an authenticator for the specified auth method.
+ * Creates an authenticator for the specified auth method (as configured).
*
* @param ike_sa associated ike_sa
* @param auth_method authentication method to use for build()/verify()
*
* @return authenticator_t object
- *
- * @ingroup authenticators
*/
-authenticator_t *authenticator_create(ike_sa_t *ike_sa, auth_method_t auth_method);
+authenticator_t *authenticator_create(ike_sa_t *ike_sa, config_auth_method_t auth_method);
+
+/**
+ * Creates an authenticator from the given auth payload.
+ *
+ * @param ike_sa associated ike_sa
+ * @param auth_payload auth payload
+ *
+ * @return authenticator_t object
+ */
+authenticator_t *authenticator_create_from_auth_payload(ike_sa_t *ike_sa, auth_payload_t *auth_payload);
-#endif /* AUTHENTICATOR_H_ */
+#endif /* AUTHENTICATOR_H_ @} */
diff --git a/src/charon/sa/authenticators/eap/eap_aka.c b/src/charon/sa/authenticators/eap/eap_aka.c
deleted file mode 100644
index 8fb1f85cd..000000000
--- a/src/charon/sa/authenticators/eap/eap_aka.c
+++ /dev/null
@@ -1,1440 +0,0 @@
-/**
- * @file eap_aka.c
- *
- * @brief Implementation of eap_aka_t.
- *
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-
-/* The EAP-AKA method uses it's own simple parser for processing EAP-AKA
- * payloads, as the IKEv2 parser is not suitable for that job. There are
- * two simple methods for parsing payloads, read_header() and read_attribute().
- * Every EAP-AKA payload consists of a header and a list of attributes. Those
- * functions mentioned read the data and return the type of the found
- * attribute/EAP-AKA-type. For generating a EAP-AKA message, we have a
- * build_aka_payload(), which builds the whole message from a variable
- * argument list containing its attributes.
- * The processing of messages is split up in various functions:
- * - peer_process() - General processing multiplexer for the peer
- * - peer_process_challenge() - Specific AKA-Challenge processor
- * - peer_process_notification() - Processing of AKA-Notification
- * - server_process() - General processing multiplexer for the server
- * - peer_process_challenge() - Processing of a received Challenge response
- * - peer_process_synchronize() - Process a sequence number synchronization
- * - server_initiate() - Initiation method for the server, calls
- * - server_initiate_challenge() - Initiation of AKA-Challenge
- */
-
-#include <string.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <time.h>
-
-#include "eap_aka.h"
-
-#include <daemon.h>
-#include <library.h>
-#include <utils/randomizer.h>
-#include <crypto/hashers/hasher.h>
-#include <crypto/prfs/fips_prf.h>
-
-/* Use test vectors specified in S.S0055
-#define TEST_VECTORS */
-
-#define RAND_LENGTH 16
-#define RES_LENGTH 16
-#define SQN_LENGTH 6
-#define K_LENGTH 16
-#define MAC_LENGTH 8
-#define CK_LENGTH 16
-#define IK_LENGTH 16
-#define AK_LENGTH 6
-#define AMF_LENGTH 2
-#define FMK_LENGTH 4
-#define AUTN_LENGTH (SQN_LENGTH + AMF_LENGTH + MAC_LENGTH)
-#define AUTS_LENGTH (SQN_LENGTH + MAC_LENGTH)
-#define PAYLOAD_LENGTH 64
-#define MK_LENGTH 20
-#define MSK_LENGTH 64
-#define EMSK_LENGTH 64
-#define KAUTH_LENGTH 16
-#define KENCR_LENGTH 16
-#define AT_MAC_LENGTH 16
-
-#define F1 0x42
-#define F1STAR 0x43
-#define F2 0x44
-#define F3 0x45
-#define F4 0x46
-#define F5 0x47
-#define F5STAR 0x48
-
-ENUM_BEGIN(aka_subtype_names, AKA_CHALLENGE, AKA_IDENTITY,
- "AKA_CHALLENGE",
- "AKA_AUTHENTICATION_REJECT",
- "AKA_3",
- "AKA_SYNCHRONIZATION_FAILURE",
- "AKA_IDENTITY");
-ENUM_NEXT(aka_subtype_names, AKA_NOTIFICATION, AKA_CLIENT_ERROR, AKA_IDENTITY,
- "AKA_NOTIFICATION",
- "AKA_REAUTHENTICATION",
- "AKA_CLIENT_ERROR");
-ENUM_END(aka_subtype_names, AKA_CLIENT_ERROR);
-
-
-ENUM_BEGIN(aka_attribute_names, AT_END, AT_CLIENT_ERROR_CODE,
- "AT_END",
- "AT_0",
- "AT_RAND",
- "AT_AUTN",
- "AT_RES",
- "AT_AUTS",
- "AT_5",
- "AT_PADDING",
- "AT_NONCE_MT",
- "AT_8",
- "AT_9",
- "AT_PERMANENT_ID_REQ",
- "AT_MAC",
- "AT_NOTIFICATION",
- "AT_ANY_ID_REQ",
- "AT_IDENTITY",
- "AT_VERSION_LIST",
- "AT_SELECTED_VERSION",
- "AT_FULLAUTH_ID_REQ",
- "AT_18",
- "AT_COUNTER",
- "AT_COUNTER_TOO_SMALL",
- "AT_NONCE_S",
- "AT_CLIENT_ERROR_CODE");
-ENUM_NEXT(aka_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE,
- "AT_IV",
- "AT_ENCR_DATA",
- "AT_131",
- "AT_NEXT_PSEUDONYM",
- "AT_NEXT_REAUTH_ID",
- "AT_CHECKCODE",
- "AT_RESULT_IND");
-ENUM_END(aka_attribute_names, AT_RESULT_IND);
-
-
-typedef struct private_eap_aka_t private_eap_aka_t;
-
-/**
- * Private data of an eap_aka_t object.
- */
-struct private_eap_aka_t {
-
- /**
- * Public authenticator_t interface.
- */
- eap_aka_t public;
-
- /**
- * ID of the server
- */
- identification_t *server;
-
- /**
- * ID of the peer
- */
- identification_t *peer;
-
- /**
- * Key for EAP MAC
- */
- chunk_t k_auth;
-
- /**
- * Key for EAP encryption
- */
- chunk_t k_encr;
-
- /**
- * MSK
- */
- chunk_t msk;
-
- /**
- * Extendend MSK
- */
- chunk_t emsk;
-
- /**
- * Expected result from client XRES
- */
- chunk_t xres;
-
- /**
- * Shared secret K from ipsec.conf (padded)
- */
- chunk_t k;
-
- /**
- * random value RAND generated by server
- */
- chunk_t rand;
-};
-
-/** Family key, as proposed in S.S0055 */
-static u_int8_t fmk_buf[] = {0x41, 0x48, 0x41, 0x47};
-static chunk_t fmk = chunk_from_buf(fmk_buf);
-
-/** Authentication management field */
-static u_int8_t amf_buf[] = {0x00, 0x01};
-static chunk_t amf = chunk_from_buf(amf_buf);
-
-/** AT_CLIENT_ERROR_CODE AKA attribute */
-static u_int8_t client_error_code_buf[] = {0, 0};
-static chunk_t client_error_code = chunk_from_buf(client_error_code_buf);
-
-/** previously used sqn by peer, next one must be greater */
-static u_int8_t peer_sqn_buf[6];
-static chunk_t peer_sqn = chunk_from_buf(peer_sqn_buf);
-
-/** set SQN to the current time */
-static void update_sqn(u_int8_t *sqn, time_t offset)
-{
- timeval_t time;
- gettimeofday(&time, NULL);
- /* set sqb_sqn to an integer containing seconds followed by most
- * significant useconds */
- time.tv_sec = htonl(time.tv_sec + offset);
- /* usec's are never larger than 0x000f423f, so we shift the 12 first bits */
- time.tv_usec <<= 12;
- time.tv_usec = htonl(time.tv_usec);
- memcpy(sqn, &time.tv_sec, 4);
- memcpy(sqn + 4, &time.tv_usec, 2);
-}
-
-/** initialize peers SQN to the current system time at startup */
-static void __attribute__ ((constructor))init_sqn(void)
-{
- update_sqn(peer_sqn_buf, 0);
-}
-
-/**
- * Binary represnation of the polynom T^160 + T^5 + T^3 + T^2 + 1
- */
-static u_int8_t g[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x2d
-};
-
-/**
- * Predefined random bits from the RAND Corporation book
- */
-static u_int8_t a[] = {
- 0x9d, 0xe9, 0xc9, 0xc8, 0xef, 0xd5, 0x78, 0x11,
- 0x48, 0x23, 0x14, 0x01, 0x90, 0x1f, 0x2d, 0x49,
- 0x3f, 0x4c, 0x63, 0x65
-};
-
-/**
- * Predefined random bits from the RAND Corporation book
- */
-static u_int8_t b[] = {
- 0x75, 0xef, 0xd1, 0x5c, 0x4b, 0x8f, 0x8f, 0x51,
- 0x4e, 0xf3, 0xbc, 0xc3, 0x79, 0x4a, 0x76, 0x5e,
- 0x7e, 0xec, 0x45, 0xe0
-};
-
-/**
- * Multiplicate two mpz_t with bits interpreted as polynoms.
- */
-static void mpz_mul_poly(mpz_t r, mpz_t a, mpz_t b)
-{
- mpz_t bm, rm;
- int current = 0, shifted = 0, shift;
-
- mpz_init_set(bm, b);
- mpz_init_set_ui(rm, 0);
- /* scan through a, for each found bit: */
- while ((current = mpz_scan1(a, current)) != ULONG_MAX)
- {
- /* XOR shifted b into r */
- shift = current - shifted;
- mpz_mul_2exp(bm, bm, shift);
- shifted += shift;
- mpz_xor(rm, rm, bm);
- current++;
- }
-
- mpz_swap(r, rm);
- mpz_clear(rm);
- mpz_clear(bm);
-}
-
-/**
- * Calculate the sum of a + b interpreted as polynoms.
- */
-static void mpz_add_poly(mpz_t res, mpz_t a, mpz_t b)
-{
- /* addition of polynominals is just the XOR */
- mpz_xor(res, a, b);
-}
-
-/**
- * Calculate the remainder of a/b interpreted as polynoms.
- */
-static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b)
-{
- /* Example:
- * a = 10001010
- * b = 00000101
- */
- int a_bit, b_bit, diff;
- mpz_t bm, am;
-
- mpz_init_set(am, a);
- mpz_init(bm);
-
- a_bit = mpz_sizeinbase(a, 2);
- b_bit = mpz_sizeinbase(b, 2);
-
- /* don't do anything if b > a */
- if (a_bit >= b_bit)
- {
- /* shift b left to align up most signaficant "1" to a:
- * a = 10001010
- * b = 10100000
- */
- mpz_mul_2exp(bm, b, a_bit - b_bit);
- do
- {
- /* XOR b into a, this kills the most significant "1":
- * a = 00101010
- */
- mpz_xor(am, am, bm);
- /* find the next most significant "1" in a, and align up b:
- * a = 00101010
- * b = 00101000
- */
- diff = a_bit - mpz_sizeinbase(am, 2);
- mpz_div_2exp(bm, bm, diff);
- a_bit -= diff;
- }
- while (b_bit <= mpz_sizeinbase(bm, 2));
- /* While b is not shifted to its original value */
- }
- /* after another iteration:
- * a = 00000010
- * which is the polynomial modulo
- */
-
- mpz_swap(r, am);
- mpz_clear(am);
- mpz_clear(bm);
-}
-
-/**
- * Step 4 of the various fx() functions:
- * Polynomial whiten calculations
- */
-static void step4(u_int8_t x[])
-{
- mpz_t xm, am, bm, gm;
-
- mpz_init(xm);
- mpz_init(am);
- mpz_init(bm);
- mpz_init(gm);
-
- mpz_import(xm, HASH_SIZE_SHA1, 1, 1, 1, 0, x);
- mpz_import(am, sizeof(a), 1, 1, 1, 0, a);
- mpz_import(bm, sizeof(b), 1, 1, 1, 0, b);
- mpz_import(gm, sizeof(g), 1, 1, 1, 0, g);
-
- mpz_mul_poly(xm, am, xm);
- mpz_add_poly(xm, bm, xm);
- mpz_mod_poly(xm, xm, gm);
-
- mpz_export(x, NULL, 1, HASH_SIZE_SHA1, 1, 0, xm);
-
- mpz_clear(xm);
- mpz_clear(am);
- mpz_clear(bm);
- mpz_clear(gm);
-}
-
-/**
- * Step 3 of the various fx() functions:
- * XOR the key into the SHA1 IV
- */
-static void step3(chunk_t k, chunk_t payload, u_int8_t h[])
-{
- u_int8_t iv[] = {
- 0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA,
- 0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0,
- };
-
- /* XOR key into IV */
- memxor(iv, k.ptr, k.len);
-
- /* hash it with the G() function defined in FIPS 186-2 from fips_prf.h */
- g_sha1(iv, payload, h);
-}
-
-/**
- * Calculation function for f2(), f3(), f4()
- */
-static void fx(u_int8_t f, chunk_t k, chunk_t rand, u_int8_t out[])
-{
- chunk_t payload = chunk_alloca(PAYLOAD_LENGTH);
- u_int8_t h[HASH_SIZE_SHA1];
- u_int8_t i;
-
- for (i = 0; i < 2; i++)
- {
- memset(payload.ptr, 0x5c, payload.len);
- payload.ptr[11] ^= f;
- memxor(payload.ptr + 12, fmk.ptr, fmk.len);
- memxor(payload.ptr + 24, rand.ptr, rand.len);
-
- payload.ptr[3] ^= i;
- payload.ptr[19] ^= i;
- payload.ptr[35] ^= i;
- payload.ptr[51] ^= i;
-
- step3(k, payload, h);
- step4(h);
- memcpy(out + i * 8, h, 8);
- }
-}
-
-/**
- * Calculation function of f1() and f1star()
- */
-static void f1x(u_int8_t f, chunk_t k, chunk_t rand, chunk_t sqn,
- chunk_t amf, u_int8_t mac[])
-{
- /* generate MAC = f1(FMK, SQN, RAND, AMF)
- * K is loaded into hashers IV; FMK, RAND, SQN, AMF are XORed in a 512-bit
- * payload which gets hashed
- */
- chunk_t payload = chunk_alloca(PAYLOAD_LENGTH);
- u_int8_t h[HASH_SIZE_SHA1];
-
- memset(payload.ptr, 0x5c, PAYLOAD_LENGTH);
- payload.ptr[11] ^= f;
- memxor(payload.ptr + 12, fmk.ptr, fmk.len);
- memxor(payload.ptr + 16, rand.ptr, rand.len);
- memxor(payload.ptr + 34, sqn.ptr, sqn.len);
- memxor(payload.ptr + 42, amf.ptr, amf.len);
-
- step3(k, payload, h);
- step4(h);
- memcpy(mac, h, MAC_LENGTH);
-}
-
-/**
- * Calculation function of f5() and f5star()
- */
-static void f5x(u_int8_t f, chunk_t k, chunk_t rand, u_int8_t ak[])
-{
- chunk_t payload = chunk_alloca(PAYLOAD_LENGTH);
- u_int8_t h[HASH_SIZE_SHA1];
-
- memset(payload.ptr, 0x5c, payload.len);
- payload.ptr[11] ^= f;
- memxor(payload.ptr + 12, fmk.ptr, fmk.len);
- memxor(payload.ptr + 16, rand.ptr, rand.len);
-
- step3(k, payload, h);
- step4(h);
- memcpy(ak, h, AK_LENGTH);
-}
-
-/**
- * Calculate the MAC from a RAND, SQN, AMF value using K
- */
-static void f1(chunk_t k, chunk_t rand, chunk_t sqn, chunk_t amf, u_int8_t mac[])
-{
- f1x(F1, k, rand, sqn, amf, mac);
- DBG3(DBG_IKE, "MAC %b", mac, MAC_LENGTH);
-}
-
-/**
- * Calculate the MACS from a RAND, SQN, AMF value using K
- */
-static void f1star(chunk_t k, chunk_t rand, chunk_t sqn, chunk_t amf, u_int8_t macs[])
-{
- f1x(F1STAR, k, rand, sqn, amf, macs);
- DBG3(DBG_IKE, "MACS %b", macs, MAC_LENGTH);
-}
-
-/**
- * Calculate RES from RAND using K
- */
-static void f2(chunk_t k, chunk_t rand, u_int8_t res[])
-{
- fx(F2, k, rand, res);
- DBG3(DBG_IKE, "RES %b", res, RES_LENGTH);
-}
-
-/**
- * Calculate CK from RAND using K
- */
-static void f3(chunk_t k, chunk_t rand, u_int8_t ck[])
-{
- fx(F3, k, rand, ck);
- DBG3(DBG_IKE, "CK %b", ck, CK_LENGTH);
-}
-
-/**
- * Calculate IK from RAND using K
- */
-static void f4(chunk_t k, chunk_t rand, u_int8_t ik[])
-{
- fx(F4, k, rand, ik);
- DBG3(DBG_IKE, "IK %b", ik, IK_LENGTH);
-}
-
-/**
- * Calculate AK from a RAND using K
- */
-static void f5(chunk_t k, chunk_t rand, u_int8_t ak[])
-{
- f5x(F5, k, rand, ak);
- DBG3(DBG_IKE, "AK %b", ak, AK_LENGTH);
-}
-
-/**
- * Calculate AKS from a RAND using K
- */
-static void f5star(chunk_t k, chunk_t rand, u_int8_t aks[])
-{
- f5x(F5STAR, k, rand, aks);
- DBG3(DBG_IKE, "AKS %b", aks, AK_LENGTH);
-}
-
-/**
- * derive the keys needed for EAP_AKA
- */
-static void derive_keys(private_eap_aka_t *this, identification_t *id)
-{
- hasher_t *hasher;
- prf_t *prf;
- chunk_t ck, ik, mk, identity, tmp;
-
- ck = chunk_alloca(CK_LENGTH);
- ik = chunk_alloca(IK_LENGTH);
- mk = chunk_alloca(MK_LENGTH);
- identity = id->get_encoding(id);
-
- /* MK = SHA1( Identity | IK | CK ) */
- f3(this->k, this->rand, ck.ptr);
- f4(this->k, this->rand, ik.ptr);
- DBG3(DBG_IKE, "Identity %B", &identity);
- tmp = chunk_cata("ccc", identity, ik, ck);
- DBG3(DBG_IKE, "Identity|IK|CK %B", &tmp);
- hasher = hasher_create(HASH_SHA1);
- hasher->get_hash(hasher, tmp, mk.ptr);
- hasher->destroy(hasher);
-
- /* K_encr | K_auth | MSK | EMSK = prf(0) | prf(0)
- * FIPS PRF has 320 bit block size, we need 160 byte for keys
- * => run prf four times */
- prf = prf_create(PRF_FIPS_SHA1_160);
- prf->set_key(prf, mk);
- tmp = chunk_alloca(prf->get_block_size(prf) * 4);
- prf->get_bytes(prf, chunk_empty, tmp.ptr);
- prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 1);
- prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 2);
- prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 3);
- prf->destroy(prf);
- chunk_free(&this->k_encr);
- chunk_free(&this->k_auth);
- chunk_free(&this->msk);
- chunk_free(&this->emsk);
- chunk_split(tmp, "aaaa", 16, &this->k_encr, 16, &this->k_auth,
- 64, &this->msk, 64, &this->emsk);
- DBG3(DBG_IKE, "MK %B", &mk);
- DBG3(DBG_IKE, "PRF res %B", &tmp);
- DBG3(DBG_IKE, "K_encr %B", &this->k_encr);
- DBG3(DBG_IKE, "K_auth %B", &this->k_auth);
- DBG3(DBG_IKE, "MSK %B", &this->msk);
- DBG3(DBG_IKE, "EMSK %B", &this->emsk);
-}
-
-/*
- * Get a shared key from ipsec.secrets.
- * We use the standard keys as used in preshared key authentication. As
- * these keys have an undefined length, we:
- * - strip them if they are longer
- * - fill them up with '\0' if they are shorter
- */
-static status_t load_key(identification_t *me, identification_t *other, chunk_t *k)
-{
- chunk_t shared_key;
-
- if (charon->credentials->get_eap_key(charon->credentials, me,
- other, &shared_key) != SUCCESS)
- {
- return NOT_FOUND;
- }
- chunk_free(k);
- *k = chunk_alloc(K_LENGTH);
- memset(k->ptr, '\0', k->len);
- memcpy(k->ptr, shared_key.ptr, min(shared_key.len, k->len));
- chunk_free(&shared_key);
- return SUCCESS;
-}
-
-/**
- * skip EAP_AKA header in message and returns its AKA subtype
- */
-static aka_subtype_t read_header(chunk_t *message)
-{
- aka_subtype_t type;
-
- if (message->len < 8)
- {
- *message = chunk_empty;
- return 0;
- }
- type = *(message->ptr + 5);
- *message = chunk_skip(*message, 8);
- return type;
-}
-
-/**
- * read the next attribute from the chunk data
- */
-static aka_attribute_t read_attribute(chunk_t *data, chunk_t *attr_data)
-{
- aka_attribute_t attribute;
- size_t length;
-
- DBG3(DBG_IKE, "reading attribute from %B", data);
-
- if (data->len < 2)
- {
- return AT_END;
- }
- /* read attribute and length */
- attribute = *data->ptr++;
- length = *data->ptr++ * 4 - 2;
- data->len -= 2;
- DBG3(DBG_IKE, "found attribute %N with length %d",
- aka_attribute_names, attribute, length);
- if (length > data->len)
- {
- return AT_END;
- }
- /* apply attribute value to attr_data */
- attr_data->len = length;
- attr_data->ptr = data->ptr;
- /* update data to point to next attribute */
- *data = chunk_skip(*data, length);
- return attribute;
-}
-
-/**
- * Build an AKA payload from different attributes.
- * The variable argument takes an aka_attribute_t
- * followed by its data in a chunk.
- */
-static eap_payload_t *build_aka_payload(private_eap_aka_t *this, eap_code_t code,
- u_int8_t identifier, aka_subtype_t type, ...)
-{
- chunk_t message = chunk_alloca(512); /* is enought for all current messages */
- chunk_t pos = message;
- eap_payload_t *payload;
- va_list args;
- aka_attribute_t attr;
- u_int8_t *mac_pos = NULL;
-
- /* write EAP header, skip length bytes */
- *pos.ptr++ = code;
- *pos.ptr++ = identifier;
- pos.ptr += 2;
- pos.len -= 4;
- /* write AKA header with type and subtype, null reserved bytes */
- *pos.ptr++ = EAP_AKA;
- *pos.ptr++ = type;
- *pos.ptr++ = 0;
- *pos.ptr++ = 0;
- pos.len -= 4;
-
- va_start(args, type);
- while ((attr = va_arg(args, aka_attribute_t)) != AT_END)
- {
- chunk_t data = va_arg(args, chunk_t);
-
- DBG3(DBG_IKE, "building %N %B", aka_attribute_names, attr, &data);
-
- /* write attribute header */
- *pos.ptr++ = attr;
- pos.len--;
-
- switch (attr)
- {
- case AT_RES:
- {
- /* attribute length in 4byte words */
- *pos.ptr = data.len/4 + 1;
- pos = chunk_skip(pos, 1);
- /* RES length in bits */
- *(u_int16_t*)pos.ptr = htons(data.len * 8);
- pos = chunk_skip(pos, sizeof(u_int16_t));
- memcpy(pos.ptr, data.ptr, data.len);
- pos = chunk_skip(pos, data.len);
- break;
- }
- case AT_AUTN:
- case AT_RAND:
- {
- *pos.ptr++ = data.len/4 + 1; pos.len--;
- *pos.ptr++ = 0; pos.len--;
- *pos.ptr++ = 0; pos.len--;
- memcpy(pos.ptr, data.ptr, data.len);
- pos = chunk_skip(pos, data.len);
- break;
- }
- case AT_MAC:
- {
- *pos.ptr++ = 5; pos.len--;
- *pos.ptr++ = 0; pos.len--;
- *pos.ptr++ = 0; pos.len--;
- mac_pos = pos.ptr;
- /* MAC is calculated over message including zeroed AT_MAC attribute */
- memset(mac_pos, 0, AT_MAC_LENGTH);
- pos.ptr += AT_MAC_LENGTH;
- pos.len -= AT_MAC_LENGTH;
- break;
- }
- default:
- {
- /* length is data length in 4-bytes + 1 for header */
- *pos.ptr = data.len/4 + 1;
- pos = chunk_skip(pos, 1);
- memcpy(pos.ptr, data.ptr, data.len);
- pos = chunk_skip(pos, data.len);
- }
- }
- }
- va_end(args);
-
- /* calculate message length, write into header */
- message.len = pos.ptr - message.ptr;
- *(u_int16_t*)(message.ptr + 2) = htons(message.len);
-
- /* create MAC if AT_MAC attribte was included */
- if (mac_pos)
- {
- signer_t *signer = signer_create(AUTH_HMAC_SHA1_128);
- signer->set_key(signer, this->k_auth);
- DBG3(DBG_IKE, "AT_MAC signature of %B", &message);
- DBG3(DBG_IKE, "using key %B", &this->k_auth);
- signer->get_signature(signer, message, mac_pos);
- DBG3(DBG_IKE, "is %b", mac_pos, AT_MAC_LENGTH);
- signer->destroy(signer);
- }
-
- /* payload constructor takes data with some bytes skipped */
- payload = eap_payload_create_data(message);
-
- DBG3(DBG_IKE, "created EAP message %B", &message);
- return payload;
-}
-
-/**
- * Initiate a AKA-Challenge using SQN
- */
-static status_t server_initiate_challenge(private_eap_aka_t *this, chunk_t sqn, eap_payload_t **out)
-{
- randomizer_t *randomizer;
- status_t status;
- chunk_t mac, ak, autn;
-
- mac = chunk_alloca(MAC_LENGTH);
- ak = chunk_alloca(AK_LENGTH);
- chunk_free(&this->rand);
- chunk_free(&this->xres);
-
- /* generate RAND:
- * we use our standard randomizer, not f0() proposed in S.S0055
- */
- randomizer = randomizer_create();
- status = randomizer->allocate_pseudo_random_bytes(randomizer, RAND_LENGTH, &this->rand);
- randomizer->destroy(randomizer);
- if (status != SUCCESS)
- {
- DBG1(DBG_IKE, "generating RAND for EAP-AKA authentication failed");
- return FAILED;
- }
-
-# ifdef TEST_VECTORS
- /* Test vector for RAND */
- u_int8_t test_rand[] = {
- 0x4b,0x05,0x2b,0x20,0xe2,0xa0,0x6c,0x8f,
- 0xf7,0x00,0xda,0x51,0x2b,0x4e,0x11,0x1e,
- };
- memcpy(this->rand.ptr, test_rand, this->rand.len);
-# endif /* TEST_VECTORS */
-
- /* Get the shared key K: */
- if (load_key(this->server, this->peer, &this->k) != SUCCESS)
- {
- DBG1(DBG_IKE, "no shared key found for IDs '%D' - '%D' to authenticate "
- "with EAP-AKA", this->server, this->peer);
- return FAILED;
- }
-
-# ifdef TEST_VECTORS
- /* Test vector for K */
- u_int8_t test_k[] = {
- 0xad,0x1b,0x5a,0x15,0x9b,0xe8,0x6b,0x2c,
- 0xa6,0x6c,0x7a,0xe4,0x0b,0xba,0x9b,0x9d,
- };
- memcpy(this->k.ptr, test_k, this->k.len);
-# endif /* TEST_VECTORS */
-
- /* generate MAC */
- f1(this->k, this->rand, sqn, amf, mac.ptr);
-
- /* generate AK */
- f5(this->k, this->rand, ak.ptr);
-
- /* precalculate XRES as expected from client */
- this->xres = chunk_alloc(RES_LENGTH);
- f2(this->k, this->rand, this->xres.ptr);
-
- /* calculate AUTN = (SQN xor AK) || AMF || MAC */
- autn = chunk_cata("ccc", sqn, amf, mac);
- memxor(autn.ptr, ak.ptr, ak.len);
- DBG3(DBG_IKE, "AUTN %B", &autn);
-
-
- /* derive K_encr, K_auth, MSK, EMSK */
- derive_keys(this, this->peer);
-
- /* build payload */
- *out = build_aka_payload(this, EAP_REQUEST, 0, AKA_CHALLENGE,
- AT_RAND, this->rand, AT_AUTN, autn, AT_MAC,
- chunk_empty, AT_END);
- return NEED_MORE;
-}
-
-/**
- * Implementation of eap_method_t.initiate for an EAP_AKA server
- */
-static status_t server_initiate(private_eap_aka_t *this, eap_payload_t **out)
-{
- chunk_t sqn = chunk_alloca(SQN_LENGTH);
-
- /* we use an offset of 3 minutes to tolerate clock inaccuracy
- * without the need to synchronize sequence numbers */
- update_sqn(sqn.ptr, 180);
-
-# ifdef TEST_VECTORS
- /* Test vector for SQN */
- u_int8_t test_sqn[] = {0x00,0x00,0x00,0x00,0x00,0x01};
- memcpy(sqn.ptr, test_sqn, sqn.len);
-# endif /* TEST_VECTORS */
-
- return server_initiate_challenge(this, sqn, out);
-}
-
-static status_t server_process_synchronize(private_eap_aka_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- chunk_t attr, auts = chunk_empty, pos, message, macs, xmacs, sqn, aks, amf;
- u_int i;
-
- message = in->get_data(in);
- pos = message;
- read_header(&pos);
-
- /* iterate over attributes */
- while (TRUE)
- {
- aka_attribute_t attribute = read_attribute(&pos, &attr);
- switch (attribute)
- {
- case AT_END:
- break;
- case AT_AUTS:
- auts = attr;
- continue;
- default:
- if (attribute >= 0 && attribute <= 127)
- {
- DBG1(DBG_IKE, "found non skippable attribute %N",
- aka_attribute_names, attribute);
- return FAILED;
- }
- DBG1(DBG_IKE, "ignoring skippable attribute %N",
- aka_attribute_names, attribute);
- continue;
- }
- break;
- }
-
- if (auts.len != AUTS_LENGTH)
- {
- DBG1(DBG_IKE, "synchronization request didn't contain useable AUTS");
- return FAILED;
- }
-
- chunk_split(auts, "mm", SQN_LENGTH, &sqn, MAC_LENGTH, &macs);
- aks = chunk_alloca(AK_LENGTH);
- f5star(this->k, this->rand, aks.ptr);
- /* decrypt serial number by XORing AKS */
- memxor(sqn.ptr, aks.ptr, aks.len);
-
- /* verify MACS */
- xmacs = chunk_alloca(MAC_LENGTH);
- amf = chunk_alloca(AMF_LENGTH);
- /* an AMF of zero is used for MACS calculation */
- memset(amf.ptr, 0, amf.len);
- f1star(this->k, this->rand, sqn, amf, xmacs.ptr);
- if (!chunk_equals(macs, xmacs))
- {
- DBG1(DBG_IKE, "received MACS does not match XMACS");
- DBG3(DBG_IKE, "MACS %B XMACS %B", &macs, &xmacs);
- return FAILED;
- }
-
- /* retry the challenge with the received SQN + 1*/
- for (i = SQN_LENGTH - 1; i >= 0; i--)
- {
- if (++sqn.ptr[i] != 0)
- {
- break;
- }
- }
- return server_initiate_challenge(this, sqn, out);
-}
-
-/**
- * process an AKA_Challenge response
- */
-static status_t server_process_challenge(private_eap_aka_t *this, eap_payload_t *in)
-{
- chunk_t attr, res = chunk_empty, at_mac = chunk_empty, pos, message;
-
- message = in->get_data(in);
- pos = message;
- read_header(&pos);
-
- /* iterate over attributes */
- while (TRUE)
- {
- aka_attribute_t attribute = read_attribute(&pos, &attr);
- switch (attribute)
- {
- case AT_END:
- break;
- case AT_RES:
- res = attr;
- if (attr.len == 2 + RES_LENGTH &&
- *(u_int16_t*)attr.ptr == htons(RES_LENGTH * 8))
- {
- res = chunk_skip(attr, 2);
- }
- continue;
-
- case AT_MAC:
- attr = chunk_skip(attr, 2);
- at_mac = chunk_clonea(attr);
- /* zero MAC in message for MAC verification */
- memset(attr.ptr, 0, attr.len);
- continue;
- default:
- if (attribute >= 0 && attribute <= 127)
- {
- DBG1(DBG_IKE, "found non skippable attribute %N",
- aka_attribute_names, attribute);
- return FAILED;
- }
- DBG1(DBG_IKE, "ignoring skippable attribute %N",
- aka_attribute_names, attribute);
- continue;
- }
- break;
- }
-
- /* verify EAP message MAC AT_MAC */
- {
- bool valid;
- signer_t *signer = signer_create(AUTH_HMAC_SHA1_128);
- signer->set_key(signer, this->k_auth);
- DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message);
- DBG3(DBG_IKE, "using key %B", &this->k_auth);
- valid = signer->verify_signature(signer, message, at_mac);
- signer->destroy(signer);
- if (!valid)
- {
- DBG1(DBG_IKE, "MAC in AT_MAC attribute verification failed");
- return FAILED;
- }
- }
-
- /* compare received RES against stored precalculated XRES */
- if (!chunk_equals(res, this->xres))
- {
- DBG1(DBG_IKE, "received RES does not match XRES");
- DBG3(DBG_IKE, "RES %Bb XRES %B", &res, &this->xres);
- return FAILED;
- }
- return SUCCESS;
-}
-
-/**
- * Implementation of eap_method_t.process for EAP_AKA servers
- */
-static status_t server_process(private_eap_aka_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- chunk_t message;
- aka_subtype_t type;
-
- message = in->get_data(in);
- type = read_header(&message);
-
- DBG3(DBG_IKE, "received EAP message %B", &message);
-
- switch (type)
- {
- case AKA_CHALLENGE:
- {
- return server_process_challenge(this, in);
- }
- case AKA_AUTHENTICATION_REJECT:
- case AKA_CLIENT_ERROR:
- {
- DBG1(DBG_IKE, "received %N, authentication failed",
- aka_subtype_names, type);
- return FAILED;
- }
- case AKA_SYNCHRONIZATION_FAILURE:
- {
- DBG1(DBG_IKE, "received %N, retrying with received SQN",
- aka_subtype_names, type);
- return server_process_synchronize(this, in, out);
- }
- default:
- DBG1(DBG_IKE, "received unknown AKA subtype %N, authentication failed",
- aka_subtype_names, type);
- return FAILED;
- }
-}
-
-/**
- * Process an incoming AKA-Challenge client side
- */
-static status_t peer_process_challenge(private_eap_aka_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- chunk_t attr = chunk_empty;
- chunk_t autn = chunk_empty, at_mac = chunk_empty;
- chunk_t ak, sqn, sqn_ak, mac, xmac, res, amf, message, pos;
- u_int8_t identifier;
-
- ak = chunk_alloca(AK_LENGTH);
- xmac = chunk_alloca(MAC_LENGTH);
- res = chunk_alloca(RES_LENGTH);
- chunk_free(&this->rand);
-
- message = in->get_data(in);
- pos = message;
- read_header(&pos);
- identifier = in->get_identifier(in);
-
- DBG3(DBG_IKE, "reading attributes from %B", &pos);
-
- /* iterate over attributes */
- while (TRUE)
- {
- aka_attribute_t attribute = read_attribute(&pos, &attr);
- switch (attribute)
- {
- case AT_END:
- break;
- case AT_RAND:
- this->rand = chunk_clone(chunk_skip(attr, 2));
- continue;
- case AT_AUTN:
- autn = chunk_skip(attr, 2);
- continue;
- case AT_MAC:
- attr = chunk_skip(attr, 2);
- at_mac = chunk_clonea(attr);
- /* set MAC in message to zero for own MAC verification */
- memset(attr.ptr, 0, attr.len);
- continue;
- default:
- if (attribute >= 0 && attribute <= 127)
- {
- /* non skippable attribute, abort */
- *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR,
- AT_CLIENT_ERROR_CODE, client_error_code, AT_END);
- DBG1(DBG_IKE, "found non skippable attribute %N, sending %N %d",
- aka_attribute_names, attribute,
- aka_attribute_names, AT_CLIENT_ERROR_CODE, 0);
- return NEED_MORE;
- }
- DBG1(DBG_IKE, "ignoring skippable attribute %N",
- aka_attribute_names, attribute);
- continue;
- }
- break;
- }
-
- if (this->rand.len != RAND_LENGTH || autn.len != AUTN_LENGTH)
- {
- /* required attributes wrong/not found, abort */
- *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR,
- AT_CLIENT_ERROR_CODE, client_error_code, AT_END);
- DBG1(DBG_IKE, "could not find valid RAND/AUTN attribute, sending %N %d",
- aka_attribute_names, AT_CLIENT_ERROR_CODE, 0);
- return NEED_MORE;
- }
-
- DBG3(DBG_IKE, "using autn %B", &autn);
- /* split up AUTN = SQN xor AK | AMF | MAC */
- chunk_split(autn, "mmm", SQN_LENGTH, &sqn_ak, AMF_LENGTH, &amf, MAC_LENGTH, &mac);
-
- /* Get the shared key K: */
- chunk_free(&this->k);
- if (load_key(this->peer, this->server, &this->k) != SUCCESS)
- {
- *out = build_aka_payload(this, EAP_RESPONSE, identifier,
- AKA_AUTHENTICATION_REJECT, AT_END);
- DBG3(DBG_IKE, "no shared key found for IDs '%D' - '%D' to authenticate "
- "with EAP-AKA, sending %N", this->peer, this->server,
- aka_subtype_names, AKA_AUTHENTICATION_REJECT);
- return NEED_MORE;
- }
- DBG3(DBG_IKE, "using K %B", &this->k);
-# ifdef TEST_VECTORS
- /* Test vector for K */
- u_int8_t test_k[] = {
- 0xad,0x1b,0x5a,0x15,0x9b,0xe8,0x6b,0x2c,
- 0xa6,0x6c,0x7a,0xe4,0x0b,0xba,0x9b,0x9d,
- };
- memcpy(this->k.ptr, test_k, this->k.len);
-# endif /* TEST_VECTORS */
-
- /* calculate anonymity key AK */
- f5(this->k, this->rand, ak.ptr);
- DBG3(DBG_IKE, "using rand %B", &this->rand);
- DBG3(DBG_IKE, "using ak %B", &ak);
- /* XOR AK into SQN to decrypt it */
-
- sqn = chunk_clonea(sqn_ak);
-
- DBG3(DBG_IKE, "using ak xor sqn %B", &sqn_ak);
- memxor(sqn.ptr, ak.ptr, sqn.len);
- DBG3(DBG_IKE, "using sqn %B", &sqn);
-
- /* calculate expected MAC and compare against received one */
- f1(this->k, this->rand, sqn, amf, xmac.ptr);
- if (!chunk_equals(mac, xmac))
- {
- *out = build_aka_payload(this, EAP_RESPONSE, identifier,
- AKA_AUTHENTICATION_REJECT, AT_END);
- DBG1(DBG_IKE, "received MAC does not match XMAC, sending %N",
- aka_subtype_names, AKA_AUTHENTICATION_REJECT);
- DBG3(DBG_IKE, "MAC %B\nXMAC %B", &mac, &xmac);
- return NEED_MORE;
- }
-
-#if SEQ_CHECK
- if (memcmp(peer_sqn.ptr, sqn.ptr, sqn.len) >= 0)
- {
- /* sequence number invalid. send AUTS */
- chunk_t auts, macs, aks, amf;
-
- macs = chunk_alloca(MAC_LENGTH);
- aks = chunk_alloca(AK_LENGTH);
- amf = chunk_alloca(AMF_LENGTH);
-
- /* AMF is set to zero in AKA_SYNCHRONIZATION_FAILURE */
- memset(amf.ptr, 0, amf.len);
- /* AKS = f5*(RAND) */
- f5star(this->k, this->rand, aks.ptr);
- /* MACS = f1*(RAND) */
- f1star(this->k, this->rand, peer_sqn, amf, macs.ptr);
- /* AUTS = SQN xor AKS | MACS */
- memxor(aks.ptr, peer_sqn.ptr, aks.len);
- auts = chunk_cata("cc", aks, macs);
-
- *out = build_aka_payload(this, EAP_RESPONSE, identifier,
- AKA_SYNCHRONIZATION_FAILURE,
- AT_AUTS, auts, AT_END);
- DBG1(DBG_IKE, "received SQN invalid, sending %N",
- aka_subtype_names, AKA_SYNCHRONIZATION_FAILURE);
- DBG3(DBG_IKE, "received SQN %B\ncurrent SQN %B", &sqn, &peer_sqn);
- return NEED_MORE;
- }
-#endif /* SEQ_CHECK */
-
- /* derive K_encr, K_auth, MSK, EMSK */
- derive_keys(this, this->peer);
-
- /* verify EAP message MAC AT_MAC */
- {
- bool valid;
- signer_t *signer = signer_create(AUTH_HMAC_SHA1_128);
- signer->set_key(signer, this->k_auth);
-
- DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message);
- DBG3(DBG_IKE, "using key %B", &this->k_auth);
- valid = signer->verify_signature(signer, message, at_mac);
- signer->destroy(signer);
- if (!valid)
- {
- *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR,
- AT_CLIENT_ERROR_CODE, client_error_code, AT_END);
- DBG1(DBG_IKE, "MAC in AT_MAC attribute verification "
- "failed, sending %N %d", aka_attribute_names,
- AT_CLIENT_ERROR_CODE, 0);
- return NEED_MORE;
- }
- }
-
- /* update stored SQN to the received one */
- memcpy(peer_sqn.ptr, sqn.ptr, sqn.len);
-
- /* calculate RES */
- f2(this->k, this->rand, res.ptr);
-
- /* build response */
- *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CHALLENGE,
- AT_RES, res, AT_MAC, chunk_empty, AT_END);
- return NEED_MORE;
-}
-
-/**
- * Process an incoming AKA-Notification as client
- */
-static status_t peer_process_notification(private_eap_aka_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- chunk_t message, pos, attr;
- u_int8_t identifier;
-
- message = in->get_data(in);
- pos = message;
- read_header(&pos);
- identifier = in->get_identifier(in);
-
- DBG3(DBG_IKE, "reading attributes from %B", &pos);
-
- /* iterate over attributes */
- while (TRUE)
- {
- aka_attribute_t attribute = read_attribute(&pos, &attr);
- switch (attribute)
- {
- case AT_END:
- break;
- case AT_NOTIFICATION:
- {
- u_int16_t code;
-
- if (attr.len != 2)
- {
- DBG1(DBG_IKE, "received invalid AKA notification, ignored");
- continue;
- }
- code = ntohs(*(u_int16_t*)attr.ptr);
- switch (code)
- {
- case 0:
- DBG1(DBG_IKE, "received AKA notification 'general "
- "failure after authentication' (%d)", code);
- return FAILED;
- case 16384:
- DBG1(DBG_IKE, "received AKA notification 'general "
- "failure' (%d)", code);
- return FAILED;
- case 32768:
- DBG1(DBG_IKE, "received AKA notification 'successfully "
- "authenticated' (%d)", code);
- continue;
- case 1026:
- DBG1(DBG_IKE, "received AKA notification 'access "
- "temporarily denied' (%d)", code);
- return FAILED;
- case 1031:
- DBG1(DBG_IKE, "received AKA notification 'not "
- "subscribed to service' (%d)", code);
- return FAILED;
- default:
- DBG1(DBG_IKE, "received AKA notification code %d, "
- "ignored", code);
- continue;
- }
- }
- default:
- if (attribute >= 0 && attribute <= 127)
- {
- DBG1(DBG_IKE, "ignoring non-skippable attribute %N in %N",
- aka_attribute_names, attribute, aka_subtype_names,
- AKA_NOTIFICATION);
- }
- else
- {
- DBG1(DBG_IKE, "ignoring skippable attribute %N",
- aka_attribute_names, attribute);
- }
- continue;
- }
- break;
- }
- return NEED_MORE;
-}
-
-/**
- * Implementation of eap_method_t.process for an EAP_AKA peer
- */
-static status_t peer_process(private_eap_aka_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- aka_subtype_t type;
- chunk_t message;
- u_int8_t identifier;
-
- message = in->get_data(in);
- type = read_header(&message);
- identifier = in->get_identifier(in);
-
- DBG3(DBG_IKE, "received EAP message %B", &message);
-
- switch (type)
- {
- case AKA_CHALLENGE:
- {
- return peer_process_challenge(this, in, out);
- }
- case AKA_NOTIFICATION:
- {
- return peer_process_notification(this, in, out);
- }
- default:
- {
- *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR,
- AT_CLIENT_ERROR_CODE, client_error_code, AT_END);
- DBG1(DBG_IKE, "received unsupported %N request, sending %N %d",
- aka_subtype_names, type,
- aka_attribute_names, AT_CLIENT_ERROR_CODE, 0);
- return NEED_MORE;
- }
- }
-}
-
-/**
- * Implementation of eap_method_t.initiate for an EAP AKA peer
- */
-static status_t peer_initiate(private_eap_aka_t *this, eap_payload_t **out)
-{
- /* peer never initiates */
- return FAILED;
-}
-
-/**
- * Implementation of eap_method_t.get_type.
- */
-static eap_type_t get_type(private_eap_aka_t *this, u_int32_t *vendor)
-{
- *vendor = 0;
- return EAP_AKA;
-}
-
-/**
- * Implementation of eap_method_t.get_msk.
- */
-static status_t get_msk(private_eap_aka_t *this, chunk_t *msk)
-{
- if (this->msk.ptr)
- {
- *msk = this->msk;
- return SUCCESS;
- }
- return FAILED;
-}
-
-/**
- * Implementation of eap_method_t.is_mutual.
- */
-static bool is_mutual(private_eap_aka_t *this)
-{
- return TRUE;
-}
-
-/**
- * Implementation of eap_method_t.destroy.
- */
-static void destroy(private_eap_aka_t *this)
-{
- chunk_free(&this->k_encr);
- chunk_free(&this->k_auth);
- chunk_free(&this->msk);
- chunk_free(&this->emsk);
- chunk_free(&this->xres);
- chunk_free(&this->k);
- chunk_free(&this->rand);
- free(this);
-}
-
-/*
- * Described in header.
- */
-eap_aka_t *eap_create(eap_role_t role,
- identification_t *server, identification_t *peer)
-{
- private_eap_aka_t *this = malloc_thing(private_eap_aka_t);
-
- /* public functions */
- switch (role)
- {
- case EAP_SERVER:
- this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))server_initiate;
- this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))server_process;
- break;
- case EAP_PEER:
- this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))peer_initiate;
- this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))peer_process;
- break;
- default:
- free(this);
- return NULL;
- }
- this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type;
- this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
- this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
- this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
-
- /* private data */
- this->server = server;
- this->peer = peer;
- this->k_encr = chunk_empty;
- this->k_auth = chunk_empty;
- this->msk = chunk_empty;
- this->emsk = chunk_empty;
- this->xres = chunk_empty;
- this->k = chunk_empty;
- this->rand = chunk_empty;
-
- return &this->public;
-}
diff --git a/src/charon/sa/authenticators/eap/eap_aka.h b/src/charon/sa/authenticators/eap/eap_aka.h
deleted file mode 100644
index a886863be..000000000
--- a/src/charon/sa/authenticators/eap/eap_aka.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/**
- * @file eap_aka.h
- *
- * @brief Interface of eap_aka_t.
- *
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#ifndef EAP_AKA_H_
-#define EAP_AKA_H_
-
-typedef struct eap_aka_t eap_aka_t;
-typedef enum aka_subtype_t aka_subtype_t;
-typedef enum aka_attribute_t aka_attribute_t;
-
-#include <sa/authenticators/eap/eap_method.h>
-
-
-/**
- * Subtypes of AKA messages
- */
-enum aka_subtype_t {
- AKA_CHALLENGE = 1,
- AKA_AUTHENTICATION_REJECT = 2,
- AKA_SYNCHRONIZATION_FAILURE = 4,
- AKA_IDENTITY = 5,
- AKA_NOTIFICATION = 12,
- AKA_REAUTHENTICATION = 13,
- AKA_CLIENT_ERROR = 14,
-};
-
-/**
- * enum names for aka_subtype_t
- */
-extern enum_name_t *aka_subtype_names;
-
-/**
- * Attribute types in AKA messages
- */
-enum aka_attribute_t {
- /** defines the end of attribute list */
- AT_END = -1,
- AT_RAND = 1,
- AT_AUTN = 2,
- AT_RES = 3,
- AT_AUTS = 4,
- AT_PADDING = 6,
- AT_NONCE_MT = 7,
- AT_PERMANENT_ID_REQ = 10,
- AT_MAC = 11,
- AT_NOTIFICATION = 12,
- AT_ANY_ID_REQ = 13,
- AT_IDENTITY = 14,
- AT_VERSION_LIST = 15,
- AT_SELECTED_VERSION = 16,
- AT_FULLAUTH_ID_REQ = 17,
- AT_COUNTER = 19,
- AT_COUNTER_TOO_SMALL = 20,
- AT_NONCE_S = 21,
- AT_CLIENT_ERROR_CODE = 22,
- AT_IV = 129,
- AT_ENCR_DATA = 130,
- AT_NEXT_PSEUDONYM = 132,
- AT_NEXT_REAUTH_ID = 133,
- AT_CHECKCODE = 134,
- AT_RESULT_IND = 135,
-};
-
-/**
- * enum names for aka_attribute_t
- */
-extern enum_name_t *aka_attribute_names;
-
-/** check SEQ values as client for validity, disabled by default */
-#ifndef SEQ_CHECK
-# define SEQ_CHECK 0
-#endif
-
-/**
- * @brief Implementation of the eap_method_t interface using EAP-AKA.
- *
- * EAP-AKA uses 3rd generation mobile phone standard authentication
- * mechanism for authentication. It is a mutual authentication
- * mechanism which establishs a shared key and therefore supports EAP_ONLY
- * authentication. This implementation follows the standard of the
- * 3GPP2 (S.S0055) and not the one of 3GGP.
- * The shared key used for authentication is from ipsec.secrets. The
- * peers ID is used to query it.
- * The AKA mechanism uses sequence numbers to detect replay attacks. The
- * peer stores the sequence number normally in a USIM and accepts
- * incremental sequence numbers (incremental for lifetime of the USIM). To
- * prevent a complex sequence number management, this implementation uses
- * a sequence number derived from time. It is initialized to the startup
- * time of the daemon. As long as the (UTC) time of the system is not
- * turned back while the daemon is not running, this method is secure.
- * To enable time based SEQs, #define SEQ_CHECK as 1. Default is to accept
- * any SEQ numbers. This allows an attacker to do replay attacks. But since
- * the server has proven his identity via IKE, such an attack is only
- * possible between server and AAA (if any).
- *
- * @b Constructors:
- * - eap_aka_create()
- * - eap_client_create() using eap_method EAP_AKA
- *
- * @ingroup eap
- */
-struct eap_aka_t {
-
- /**
- * Implemented eap_method_t interface.
- */
- eap_method_t eap_method_interface;
-};
-
-/**
- * @brief Creates the EAP method EAP-AKA.
- *
- * @param server ID of the EAP server
- * @param peer ID of the EAP client
- * @return eap_aka_t object
- *
- * @ingroup eap
- */
-eap_aka_t *eap_create(eap_role_t role,
- identification_t *server, identification_t *peer);
-
-#endif /* EAP_AKA_H_ */
diff --git a/src/charon/sa/authenticators/eap/eap_identity.c b/src/charon/sa/authenticators/eap/eap_identity.c
deleted file mode 100644
index 12a8bf7cc..000000000
--- a/src/charon/sa/authenticators/eap/eap_identity.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/**
- * @file eap_identity.c
- *
- * @brief Implementation of eap_identity_t.
- *
- */
-
-/*
- * Copyright (C) 2007 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "eap_identity.h"
-
-#include <daemon.h>
-#include <library.h>
-
-typedef struct private_eap_identity_t private_eap_identity_t;
-
-/**
- * Private data of an eap_identity_t object.
- */
-struct private_eap_identity_t {
-
- /**
- * Public authenticator_t interface.
- */
- eap_identity_t public;
-
- /**
- * ID of the peer
- */
- identification_t *peer;
-};
-
-/**
- * Implementation of eap_method_t.process for the peer
- */
-static status_t process(private_eap_identity_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- chunk_t id, hdr;
-
- hdr = chunk_alloca(5);
- id = this->peer->get_encoding(this->peer);
-
- *(hdr.ptr + 0) = EAP_RESPONSE;
- *(hdr.ptr + 1) = in->get_identifier(in);
- *(u_int16_t*)(hdr.ptr + 2) = htons(hdr.len + id.len);
- *(hdr.ptr + 4) = EAP_IDENTITY;
-
- *out = eap_payload_create_data(chunk_cata("cc", hdr, id));
- return SUCCESS;
-
-}
-
-/**
- * Implementation of eap_method_t.initiate for the peer
- */
-static status_t initiate(private_eap_identity_t *this, eap_payload_t **out)
-{
- /* peer never initiates */
- return FAILED;
-}
-
-/**
- * Implementation of eap_method_t.get_type.
- */
-static eap_type_t get_type(private_eap_identity_t *this)
-{
- return EAP_IDENTITY;
-}
-
-/**
- * Implementation of eap_method_t.get_msk.
- */
-static status_t get_msk(private_eap_identity_t *this, chunk_t *msk)
-{
- return FAILED;
-}
-
-/**
- * Implementation of eap_method_t.is_mutual.
- */
-static bool is_mutual(private_eap_identity_t *this)
-{
- return FALSE;
-}
-
-/**
- * Implementation of eap_method_t.destroy.
- */
-static void destroy(private_eap_identity_t *this)
-{
- free(this);
-}
-
-/*
- * Described in header.
- */
-eap_identity_t *eap_create(eap_role_t role,
- identification_t *server, identification_t *peer)
-{
- private_eap_identity_t *this;
-
- if (role != EAP_PEER)
- {
- return NULL;
- }
-
- this = malloc_thing(private_eap_identity_t);
-
- /* public functions */
- this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate;
- this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process;
- this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*))get_type;
- this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
- this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
- this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
-
- /* private data */
- this->peer = peer;
-
- return &this->public;
-}
diff --git a/src/charon/sa/authenticators/eap/eap_identity.h b/src/charon/sa/authenticators/eap/eap_identity.h
deleted file mode 100644
index 20f0f0b67..000000000
--- a/src/charon/sa/authenticators/eap/eap_identity.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * @file eap_identity.h
- *
- * @brief Interface of eap_identity_t.
- *
- */
-
-/*
- * Copyright (C) 2007 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#ifndef EAP_IDENTITY_H_
-#define EAP_IDENTITY_H_
-
-typedef struct eap_identity_t eap_identity_t;
-
-#include <sa/authenticators/eap/eap_method.h>
-
-/**
- * @brief Implementation of the eap_method_t interface using EAP Identity.
- *
- * @b Constructors:
- * - eap_identity_create()
- * - eap_client_create() using eap_method EAP_IDENTITY
- *
- * @ingroup eap
- */
-struct eap_identity_t {
-
- /**
- * Implemented eap_method_t interface.
- */
- eap_method_t eap_method_interface;
-};
-
-/**
- * @brief Creates the EAP method EAP Identity.
- *
- * @param server ID of the EAP server
- * @param peer ID of the EAP client
- * @return eap_identity_t object
- *
- * @ingroup eap
- */
-eap_identity_t *eap_create(eap_role_t role,
- identification_t *server, identification_t *peer);
-
-#endif /* EAP_IDENTITY_H_ */
diff --git a/src/charon/sa/authenticators/eap/eap_manager.c b/src/charon/sa/authenticators/eap/eap_manager.c
new file mode 100644
index 000000000..44d84156c
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_manager.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * $Id: eap_manager.c 3589 2008-03-13 14:14:44Z martin $
+ */
+
+#include "eap_manager.h"
+
+#include <pthread.h>
+
+#include <utils/linked_list.h>
+
+typedef struct private_eap_manager_t private_eap_manager_t;
+typedef struct eap_entry_t eap_entry_t;
+
+/**
+ * EAP constructor entry
+ */
+struct eap_entry_t {
+
+ /**
+ * EAP method type, vendor specific if vendor is set
+ */
+ eap_type_t type;
+
+ /**
+ * vendor ID, 0 for default EAP methods
+ */
+ u_int32_t vendor;
+
+ /**
+ * Role of the method returned by the constructor, EAP_SERVER or EAP_PEER
+ */
+ eap_role_t role;
+
+ /**
+ * constructor function to create instance
+ */
+ eap_constructor_t constructor;
+};
+
+/**
+ * private data of eap_manager
+ */
+struct private_eap_manager_t {
+
+ /**
+ * public functions
+ */
+ eap_manager_t public;
+
+ /**
+ * list of eap_entry_t's
+ */
+ linked_list_t *methods;
+
+ /**
+ * mutex to lock methods
+ */
+ pthread_mutex_t mutex;
+};
+
+/**
+ * Implementation of eap_manager_t.add_method.
+ */
+static void add_method(private_eap_manager_t *this, eap_type_t type,
+ u_int32_t vendor, eap_role_t role,
+ eap_constructor_t constructor)
+{
+ eap_entry_t *entry = malloc_thing(eap_entry_t);
+
+ entry->type = type;
+ entry->vendor = vendor;
+ entry->role = role;
+ entry->constructor = constructor;
+
+ pthread_mutex_lock(&this->mutex);
+ this->methods->insert_last(this->methods, entry);
+ pthread_mutex_unlock(&this->mutex);
+}
+
+/**
+ * Implementation of eap_manager_t.remove_method.
+ */
+static void remove_method(private_eap_manager_t *this, eap_constructor_t constructor)
+{
+ enumerator_t *enumerator;
+ eap_entry_t *entry;
+
+ pthread_mutex_lock(&this->mutex);
+ enumerator = this->methods->create_enumerator(this->methods);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (constructor == entry->constructor)
+ {
+ this->methods->remove_at(this->methods, enumerator);
+ free(entry);
+ }
+ }
+ enumerator->destroy(enumerator);
+ pthread_mutex_unlock(&this->mutex);
+}
+
+/**
+ * Implementation of eap_manager_t.create_instance.
+ */
+static eap_method_t* create_instance(private_eap_manager_t *this,
+ eap_type_t type, u_int32_t vendor,
+ eap_role_t role, identification_t *server,
+ identification_t *peer)
+{
+ enumerator_t *enumerator;
+ eap_entry_t *entry;
+ eap_method_t *method = NULL;
+
+ pthread_mutex_lock(&this->mutex);
+ enumerator = this->methods->create_enumerator(this->methods);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (type == entry->type && vendor == entry->vendor &&
+ role == entry->role)
+ {
+ method = entry->constructor(server, peer);
+ if (method)
+ {
+ break;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ pthread_mutex_unlock(&this->mutex);
+ return method;
+}
+
+/**
+ * Implementation of 2008_t.destroy
+ */
+static void destroy(private_eap_manager_t *this)
+{
+ this->methods->destroy_function(this->methods, free);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+eap_manager_t *eap_manager_create()
+{
+ private_eap_manager_t *this = malloc_thing(private_eap_manager_t);
+
+ this->public.add_method = (void(*)(eap_manager_t*, eap_type_t type, u_int32_t vendor, eap_role_t role, eap_constructor_t constructor))add_method;
+ this->public.remove_method = (void(*)(eap_manager_t*, eap_constructor_t constructor))remove_method;
+ this->public.create_instance = (eap_method_t*(*)(eap_manager_t*, eap_type_t type, u_int32_t vendor, eap_role_t role, identification_t*,identification_t*))create_instance;
+ this->public.destroy = (void(*)(eap_manager_t*))destroy;
+
+ this->methods = linked_list_create();
+ pthread_mutex_init(&this->mutex, NULL);
+
+ return &this->public;
+}
+
diff --git a/src/charon/sa/authenticators/eap/eap_manager.h b/src/charon/sa/authenticators/eap/eap_manager.h
new file mode 100644
index 000000000..74bfa1f51
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_manager.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * $Id: eap_manager.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup eap_manager eap_manager
+ * @{ @ingroup eap
+ */
+
+#ifndef EAP_MANAGER_H_
+#define EAP_MANAGER_H_
+
+#include <sa/authenticators/eap/eap_method.h>
+
+typedef struct eap_manager_t eap_manager_t;
+
+/**
+ * The EAP manager manages all EAP implementations and creates instances.
+ *
+ * A plugin registers it's implemented EAP method at the manager by
+ * providing type and a contructor function. The manager then instanciates
+ * eap_method_t instances through the provided constructor to handle
+ * EAP authentication.
+ */
+struct eap_manager_t {
+
+ /**
+ * Register a EAP method implementation.
+ *
+ * @param method vendor specific method, if vendor != 0
+ * @param vendor vendor ID, 0 for non-vendor (default) EAP methods
+ * @param role EAP role of the registered method
+ * @param constructor constructor function, returns an eap_method_t
+ */
+ void (*add_method)(eap_manager_t *this, eap_type_t type, u_int32_t vendor,
+ eap_role_t role, eap_constructor_t constructor);
+
+ /**
+ * Unregister a EAP method implementation using it's constructor.
+ *
+ * @param constructor constructor function to remove, as added in add_method
+ */
+ void (*remove_method)(eap_manager_t *this, eap_constructor_t constructor);
+
+ /**
+ * Create a new EAP method instance.
+ *
+ * @param type type of the EAP method
+ * @param vendor vendor ID, 0 for non-vendor (default) EAP methods
+ * @param role role of EAP method, either EAP_SERVER or EAP_PEER
+ * @param server identity of the server
+ * @param peer identity of the peer (client)
+ * @return EAP method instance, NULL if no constructor found
+ */
+ eap_method_t* (*create_instance)(eap_manager_t *this, eap_type_t type,
+ u_int32_t vendor, eap_role_t role,
+ identification_t *server,
+ identification_t *peer);
+
+ /**
+ * Destroy a eap_manager instance.
+ */
+ void (*destroy)(eap_manager_t *this);
+};
+
+/**
+ * Create a eap_manager instance.
+ */
+eap_manager_t *eap_manager_create();
+
+#endif /* EAP_MANAGER_H_ @}*/
diff --git a/src/charon/sa/authenticators/eap/eap_md5.c b/src/charon/sa/authenticators/eap/eap_md5.c
deleted file mode 100644
index 0ca9fc566..000000000
--- a/src/charon/sa/authenticators/eap/eap_md5.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/**
- * @file eap_md5.c
- *
- * @brief Implementation of eap_md5_t.
- *
- */
-
-/*
- * Copyright (C) 2007 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "eap_md5.h"
-
-#include <daemon.h>
-#include <library.h>
-
-typedef struct private_eap_md5_t private_eap_md5_t;
-
-/**
- * Private data of an eap_md5_t object.
- */
-struct private_eap_md5_t {
-
- /**
- * Public authenticator_t interface.
- */
- eap_md5_t public;
-
- /**
- * ID of the server
- */
- identification_t *server;
-
- /**
- * ID of the peer
- */
- identification_t *peer;
-
- /**
- * challenge sent by the server
- */
- chunk_t challenge;
-
- /**
- * EAP message identififier
- */
- u_int8_t identifier;
-};
-
-typedef struct eap_md5_header_t eap_md5_header_t;
-
-/**
- * packed eap MD5 header struct
- */
-struct eap_md5_header_t {
- /** EAP code (REQUEST/RESPONSE) */
- u_int8_t code;
- /** unique message identifier */
- u_int8_t identifier;
- /** length of whole message */
- u_int16_t length;
- /** EAP type */
- u_int8_t type;
- /** length of value (challenge) */
- u_int8_t value_size;
- /** actual value */
- u_int8_t value[];
-} __attribute__((__packed__));
-
-#define CHALLENGE_LEN 16
-#define PAYLOAD_LEN (CHALLENGE_LEN + sizeof(eap_md5_header_t))
-
-/**
- * Hash the challenge string, create response
- */
-static status_t hash_challenge(private_eap_md5_t *this, chunk_t *response)
-{
- chunk_t concat, secret;
- hasher_t *hasher;
-
- if (charon->credentials->get_eap_key(charon->credentials, this->server,
- this->peer, &secret) != SUCCESS)
- {
- DBG1(DBG_IKE, "no EAP key found for hosts '%D' - '%D'",
- this->server, this->peer);
- return NOT_FOUND;
- }
- concat = chunk_cata("cmc", chunk_from_thing(this->identifier),
- secret, this->challenge);
- hasher = hasher_create(HASH_MD5);
- hasher->allocate_hash(hasher, concat, response);
- hasher->destroy(hasher);
- return SUCCESS;
-}
-
-/**
- * Implementation of eap_method_t.initiate for the peer
- */
-static status_t initiate_peer(private_eap_md5_t *this, eap_payload_t **out)
-{
- /* peer never initiates */
- return FAILED;
-}
-
-/**
- * Implementation of eap_method_t.initiate for the server
- */
-static status_t initiate_server(private_eap_md5_t *this, eap_payload_t **out)
-{
- randomizer_t *randomizer;
- status_t status;
- eap_md5_header_t *req;
-
- randomizer = randomizer_create();
- status = randomizer->allocate_pseudo_random_bytes(randomizer, CHALLENGE_LEN,
- &this->challenge);
- randomizer->destroy(randomizer);
- if (status != SUCCESS)
- {
- return FAILED;
- }
-
- req = alloca(PAYLOAD_LEN);
- req->length = htons(PAYLOAD_LEN);
- req->code = EAP_REQUEST;
- req->identifier = this->identifier;
- req->type = EAP_MD5;
- req->value_size = this->challenge.len;
- memcpy(req->value, this->challenge.ptr, this->challenge.len);
-
- *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN));
- return NEED_MORE;
-}
-
-/**
- * Implementation of eap_method_t.process for the peer
- */
-static status_t process_peer(private_eap_md5_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- chunk_t response;
- chunk_t data;
- eap_md5_header_t *req;
-
- this->identifier = in->get_identifier(in);
- data = in->get_data(in);
- this->challenge = chunk_clone(chunk_skip(data, 6));
- if (data.len < 6 || this->challenge.len < *(data.ptr + 5))
- {
- DBG1(DBG_IKE, "received invalid EAP-MD5 message");
- return FAILED;
- }
- if (hash_challenge(this, &response) != SUCCESS)
- {
- return FAILED;
- }
- req = alloca(PAYLOAD_LEN);
- req->length = htons(PAYLOAD_LEN);
- req->code = EAP_RESPONSE;
- req->identifier = this->identifier;
- req->type = EAP_MD5;
- req->value_size = response.len;
- memcpy(req->value, response.ptr, response.len);
- chunk_free(&response);
-
- *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN));
- return NEED_MORE;
-}
-
-/**
- * Implementation of eap_method_t.process for the server
- */
-static status_t process_server(private_eap_md5_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- chunk_t response, expected;
- chunk_t data;
-
- if (this->identifier != in->get_identifier(in))
- {
- DBG1(DBG_IKE, "received invalid EAP-MD5 message");
- return FAILED;
- }
- if (hash_challenge(this, &expected) != SUCCESS)
- {
- return FAILED;
- }
- data = in->get_data(in);
- response = chunk_skip(data, 6);
-
- if (response.len < expected.len ||
- !memeq(response.ptr, expected.ptr, expected.len))
- {
- chunk_free(&expected);
- DBG1(DBG_IKE, "EAP-MD5 verification failed");
- return FAILED;
- }
- chunk_free(&expected);
- return SUCCESS;
-}
-
-/**
- * Implementation of eap_method_t.get_type.
- */
-static eap_type_t get_type(private_eap_md5_t *this, u_int32_t *vendor)
-{
- *vendor = 0;
- return EAP_MD5;
-}
-
-/**
- * Implementation of eap_method_t.get_msk.
- */
-static status_t get_msk(private_eap_md5_t *this, chunk_t *msk)
-{
- return FAILED;
-}
-
-/**
- * Implementation of eap_method_t.is_mutual.
- */
-static bool is_mutual(private_eap_md5_t *this)
-{
- return FALSE;
-}
-
-/**
- * Implementation of eap_method_t.destroy.
- */
-static void destroy(private_eap_md5_t *this)
-{
- chunk_free(&this->challenge);
- free(this);
-}
-
-/*
- * Described in header.
- */
-eap_md5_t *eap_create(eap_role_t role,
- identification_t *server, identification_t *peer)
-{
- private_eap_md5_t *this = malloc_thing(private_eap_md5_t);
-
- /* public functions */
- switch (role)
- {
- case EAP_SERVER:
- this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_server;
- this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_server;
- break;
- case EAP_PEER:
- this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_peer;
- this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_peer;
- break;
- default:
- free(this);
- return NULL;
- }
- this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type;
- this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
- this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
- this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
-
- /* private data */
- this->peer = peer;
- this->server = server;
- this->challenge = chunk_empty;
- this->identifier = random();
-
- return &this->public;
-}
diff --git a/src/charon/sa/authenticators/eap/eap_md5.h b/src/charon/sa/authenticators/eap/eap_md5.h
deleted file mode 100644
index 260210b59..000000000
--- a/src/charon/sa/authenticators/eap/eap_md5.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * @file eap_md5.h
- *
- * @brief Interface of eap_md5_t.
- *
- */
-
-/*
- * Copyright (C) 2007 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#ifndef EAP_MD5_H_
-#define EAP_MD5_H_
-
-typedef struct eap_md5_t eap_md5_t;
-
-#include <sa/authenticators/eap/eap_method.h>
-
-/**
- * @brief Implementation of the eap_method_t interface using EAP-MD5 (CHAP).
- *
- * @b Constructors:
- * - eap_md5_create()
- * - eap_client_create() using eap_method EAP_MD5
- *
- * @ingroup eap
- */
-struct eap_md5_t {
-
- /**
- * Implemented eap_method_t interface.
- */
- eap_method_t eap_method_interface;
-};
-
-/**
- * @brief Creates the EAP method EAP-MD5.
- *
- * @param server ID of the EAP server
- * @param peer ID of the EAP client
- * @return eap_md5_t object
- *
- * @ingroup eap
- */
-eap_md5_t *eap_create(eap_role_t role,
- identification_t *server, identification_t *peer);
-
-#endif /* EAP_MD5_H_ */
diff --git a/src/charon/sa/authenticators/eap/eap_method.c b/src/charon/sa/authenticators/eap/eap_method.c
index 7434ca2a1..5e2db5489 100644
--- a/src/charon/sa/authenticators/eap/eap_method.c
+++ b/src/charon/sa/authenticators/eap/eap_method.c
@@ -1,10 +1,3 @@
-/**
- * @file eap_method.c
- *
- * @brief Generic constructor for eap_methods.
- *
- */
-
/*
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,22 +11,12 @@
* 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.
+ *
+ * $Id: eap_method.c 3589 2008-03-13 14:14:44Z martin $
*/
-#include <string.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <error.h>
-#include <dlfcn.h>
-
#include "eap_method.h"
-#include <daemon.h>
-#include <library.h>
-#include <utils/linked_list.h>
-#include <utils/identification.h>
-
-
ENUM_BEGIN(eap_type_names, EAP_IDENTITY, EAP_TOKEN_CARD,
"EAP_IDENTITY",
"EAP_NOTIFICATION",
@@ -62,171 +45,3 @@ ENUM(eap_role_names, EAP_SERVER, EAP_PEER,
"EAP_PEER",
);
-
-typedef struct module_entry_t module_entry_t;
-
-/**
- * Representation of a loaded module: EAP type, library handle, constructor
- */
-struct module_entry_t {
- eap_type_t type;
- u_int32_t vendor;
- void *handle;
- eap_constructor_t constructor;
-};
-
-/** List of module_entry_t's */
-static linked_list_t *modules = NULL;
-
-/**
- * unload modules at daemon shutdown
- */
-void eap_method_unload()
-{
- if (modules)
- {
- module_entry_t *entry;
-
- while (modules->remove_last(modules, (void**)&entry) == SUCCESS)
- {
- DBG2(DBG_CFG, "unloaded module EAP module %d-%d",
- entry->type, entry->vendor);
- dlclose(entry->handle);
- free(entry);
- }
- modules->destroy(modules);
- modules = NULL;
- }
-}
-
-/**
- * Load EAP modules at daemon startup
- */
-void eap_method_load(char *directory)
-{
- struct dirent* entry;
- DIR* dir;
-
- eap_method_unload();
- modules = linked_list_create();
-
- dir = opendir(directory);
- if (dir == NULL)
- {
- DBG1(DBG_CFG, "error opening EAP modules directory %s", directory);
- return;
- }
-
- DBG1(DBG_CFG, "loading EAP modules from '%s'", directory);
-
- while ((entry = readdir(dir)) != NULL)
- {
- char file[256];
- module_entry_t module, *loaded_module;
- eap_method_t *method;
- identification_t *id;
- char *ending;
-
- snprintf(file, sizeof(file), "%s/%s", directory, entry->d_name);
-
- ending = entry->d_name + strlen(entry->d_name) - 3;
- if (ending <= entry->d_name || !streq(ending, ".so"))
- {
- /* skip anything which does not look like a library */
- DBG2(DBG_CFG, " skipping %s, doesn't look like a library",
- entry->d_name);
- continue;
- }
-
- /* try to load the library */
- module.handle = dlopen(file, RTLD_LAZY);
- if (module.handle == NULL)
- {
- DBG1(DBG_CFG, " opening EAP module %s failed: %s", entry->d_name,
- dlerror());
- continue;
- }
- module.constructor = dlsym(module.handle, "eap_create");
- if (module.constructor == NULL)
- {
- DBG1(DBG_CFG, " EAP module %s has no eap_create() function, skipped",
- entry->d_name);
- dlclose(module.handle);
- continue;
- }
-
- /* get the type implemented in the method, create an instance for it */
- id = identification_create_from_string("john@doe.xyz");
- method = module.constructor(EAP_SERVER, id, id);
- if (method == NULL)
- {
- method = module.constructor(EAP_PEER, id, id);
- }
- id->destroy(id);
- if (method == NULL)
- {
- DBG1(DBG_CFG, " unable to create instance of EAP method %s, skipped",
- entry->d_name);
- dlclose(module.handle);
- continue;
- }
- module.type = method->get_type(method, &module.vendor);
- method->destroy(method);
-
- if (module.vendor)
- {
- DBG1(DBG_CFG, " loaded EAP method %d, vendor %d successfully from %s",
- module.type, module.vendor, entry->d_name);
- }
- else
- {
- DBG1(DBG_CFG, " loaded EAP method %N successfully from %s",
- eap_type_names, module.type, entry->d_name);
- }
-
- loaded_module = malloc_thing(module_entry_t);
- memcpy(loaded_module, &module, sizeof(module));
- modules->insert_last(modules, loaded_module);
- }
- closedir(dir);
-}
-
-/*
- * Described in header.
- */
-eap_method_t *eap_method_create(eap_type_t type, u_int32_t vendor, eap_role_t role,
- identification_t *server, identification_t *peer)
-{
- eap_method_t *method = NULL;
- iterator_t *iterator;
- module_entry_t *entry;
-
- iterator = modules->create_iterator(modules, TRUE);
- while (iterator->iterate(iterator, (void**)&entry))
- {
- if (entry->type == type && entry->vendor == vendor)
- {
- method = entry->constructor(role, server, peer);
- if (method)
- {
- break;
- }
- }
- }
- iterator->destroy(iterator);
-
- if (method == NULL)
- {
- if (vendor)
- {
- DBG1(DBG_CFG, "no vendor %d specific EAP module found for method "
- "%d %N", vendor, type, eap_role_names, role);
- }
- else
- {
- DBG1(DBG_CFG, "no EAP module found for %N %N",
- eap_type_names, type, eap_role_names, role);
- }
- }
- return method;
-}
diff --git a/src/charon/sa/authenticators/eap/eap_method.h b/src/charon/sa/authenticators/eap/eap_method.h
index 8675fd8ec..eda6f545e 100644
--- a/src/charon/sa/authenticators/eap/eap_method.h
+++ b/src/charon/sa/authenticators/eap/eap_method.h
@@ -1,10 +1,3 @@
-/**
- * @file eap_method.h
- *
- * @brief Interface eap_method_t.
- *
- */
-
/*
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: eap_method.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup eap_method eap_method
+ * @{ @ingroup eap
*/
#ifndef EAP_METHOD_H_
@@ -34,8 +34,6 @@ typedef enum eap_code_t eap_code_t;
/**
* Role of an eap_method, SERVER or PEER (client)
- *
- * @ingroup eap
*/
enum eap_role_t {
EAP_SERVER,
@@ -43,15 +41,11 @@ enum eap_role_t {
};
/**
* enum names for eap_role_t.
- *
- * @ingroup eap
*/
extern enum_name_t *eap_role_names;
/**
* EAP types, defines the EAP method implementation
- *
- * @ingroup eap
*/
enum eap_type_t {
EAP_IDENTITY = 1,
@@ -68,15 +62,11 @@ enum eap_type_t {
/**
* enum names for eap_type_t.
- *
- * @ingroup eap
*/
extern enum_name_t *eap_type_names;
/**
* EAP code, type of an EAP message
- *
- * @ingroup eap
*/
enum eap_code_t {
EAP_REQUEST = 1,
@@ -87,14 +77,12 @@ enum eap_code_t {
/**
* enum names for eap_code_t.
- *
- * @ingroup eap
*/
extern enum_name_t *eap_code_names;
/**
- * @brief Interface of an EAP method for server and client side.
+ * Interface of an EAP method for server and client side.
*
* An EAP method initiates an EAP exchange and processes requests and
* responses. An EAP method may need multiple exchanges before succeeding, and
@@ -107,22 +95,16 @@ extern enum_name_t *eap_code_names;
* authentication. Even if a mutual EAP method is used, the traditional
* AUTH payloads are required. Only these include the nonces and messages from
* ike_sa_init and therefore prevent man in the middle attacks.
- *
- * @b Constructors:
- * - eap_method_create()
- *
- * @ingroup eap
*/
struct eap_method_t {
/**
- * @brief Initiate the EAP exchange.
+ * Initiate the EAP exchange.
*
* initiate() is only useable for server implementations, as clients only
* reply to server requests.
* A eap_payload is created in "out" if result is NEED_MORE.
*
- * @param this calling object
* @param out eap_payload to send to the client
* @return
* - NEED_MORE, if an other exchange is required
@@ -131,11 +113,10 @@ struct eap_method_t {
status_t (*initiate) (eap_method_t *this, eap_payload_t **out);
/**
- * @brief Process a received EAP message.
+ * Process a received EAP message.
*
* A eap_payload is created in "out" if result is NEED_MORE.
*
- * @param this calling object
* @param in eap_payload response received
* @param out created eap_payload to send
* @return
@@ -147,31 +128,28 @@ struct eap_method_t {
eap_payload_t **out);
/**
- * @brief Get the EAP type implemented in this method.
+ * Get the EAP type implemented in this method.
*
- * @param this calling object
* @param vendor pointer receiving vendor identifier for type, 0 for none
* @return type of the EAP method
*/
eap_type_t (*get_type) (eap_method_t *this, u_int32_t *vendor);
/**
- * @brief Check if this EAP method authenticates the server.
+ * Check if this EAP method authenticates the server.
*
* Some EAP methods provide mutual authentication and
* allow authentication using only EAP, if the peer supports it.
*
- * @param this calling object
* @return TRUE if methods provides mutual authentication
*/
bool (*is_mutual) (eap_method_t *this);
/**
- * @brief Get the MSK established by this EAP method.
+ * Get the MSK established by this EAP method.
*
* Not all EAP methods establish a shared secret.
*
- * @param this calling object
* @param msk chunk receiving internal stored MSK
* @return
* - SUCCESS, or
@@ -180,68 +158,25 @@ struct eap_method_t {
status_t (*get_msk) (eap_method_t *this, chunk_t *msk);
/**
- * @brief Destroys a eap_method_t object.
- *
- * @param this calling object
+ * Destroys a eap_method_t object.
*/
void (*destroy) (eap_method_t *this);
};
/**
- * @brief Creates an EAP method for a specific type and role.
- *
- * @param eap_type EAP type to use
- * @param eap_vendor vendor identifier if a vendor specifc EAP type is used
- * @param role role of the eap_method, server or peer
- * @param server ID of acting server
- * @param peer ID of involved peer (client)
- * @return eap_method_t object
- *
- * @ingroup eap
- */
-eap_method_t *eap_method_create(eap_type_t eap_type, u_int32_t eap_vendor,
- eap_role_t role, identification_t *server,
- identification_t *peer);
-
-/**
- * @brief (Re-)Load all EAP modules in the EAP modules directory.
- *
- * For security reasons, the directory and all it's modules must be owned
- * by root and must not be writeable by someone else.
- *
- * @param dir directory of the EAP modules
- *
- * @ingroup eap
- */
-void eap_method_load(char *directory);
-
-/**
- * @brief Unload all loaded EAP modules
- *
- * @ingroup eap
- */
-void eap_method_unload();
-
-/**
- * @brief Constructor definition for a pluggable EAP module.
+ * Constructor definition for a pluggable EAP method.
*
* Each EAP module must define a constructor function which will return
- * an initialized object with the methods defined in eap_method_t. The
- * constructor must be named eap_create() and it's signature must be equal
- * to that of eap_constructor_t.
- * A module may implement only a single role. If it does not support the role
- * requested, NULL should be returned. Multiple modules are allowed of the
- * same EAP type to support seperate implementations of peer/server.
+ * an initialized object with the methods defined in eap_method_t.
+ * Constructors for server and peers are identical, to support both roles
+ * of a EAP method, a plugin needs register two constructors in the
+ * eap_manager_t.
*
- * @param role role the module will play, peer or server
* @param server ID of the server to use for credential lookup
* @param peer ID of the peer to use for credential lookup
* @return implementation of the eap_method_t interface
- *
- * @ingroup eap
*/
-typedef eap_method_t *(*eap_constructor_t)(eap_role_t role,
- identification_t *server,
+typedef eap_method_t *(*eap_constructor_t)(identification_t *server,
identification_t *peer);
-#endif /* EAP_METHOD_H_ */
+#endif /* EAP_METHOD_H_ @} */
diff --git a/src/charon/sa/authenticators/eap/eap_sim.c b/src/charon/sa/authenticators/eap/eap_sim.c
deleted file mode 100644
index 90898fb46..000000000
--- a/src/charon/sa/authenticators/eap/eap_sim.c
+++ /dev/null
@@ -1,1125 +0,0 @@
-/**
- * @file eap_sim.c
- *
- * @brief Implementation of eap_sim_t.
- *
- */
-
-/*
- * Copyright (C) 2007 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "eap_sim.h"
-
-#include <dlfcn.h>
-
-#include <daemon.h>
-#include <library.h>
-
-#define MAX_TRIES 3
-
-/* number of triplets for one authentication */
-#define TRIPLET_COUNT 3
-
-typedef enum sim_subtype_t sim_subtype_t;
-
-/**
- * Subtypes of SIM messages
- */
-enum sim_subtype_t {
- SIM_START = 10,
- SIM_CHALLENGE = 11,
- SIM_NOTIFICATION = 12,
- SIM_CLIENT_ERROR = 14,
-};
-
-ENUM(sim_subtype_names, SIM_START, SIM_CLIENT_ERROR,
- "SIM_START",
- "SIM_CHALLENGE",
- "SIM_NOTIFICATION",
- "SIM_13",
- "SIM_CLIENT_ERROR",
-);
-
-typedef enum sim_attribute_t sim_attribute_t;
-
-/**
- * Attributes in SIM messages
- */
-enum sim_attribute_t {
- /** defines the end of attribute list */
- AT_END = -1,
- AT_RAND = 1,
- AT_AUTN = 2,
- AT_RES = 3,
- AT_AUTS = 4,
- AT_PADDING = 6,
- AT_NONCE_MT = 7,
- AT_PERMANENT_ID_REQ = 10,
- AT_MAC = 11,
- AT_NOTIFICATION = 12,
- AT_ANY_ID_REQ = 13,
- AT_IDENTITY = 14,
- AT_VERSION_LIST = 15,
- AT_SELECTED_VERSION = 16,
- AT_FULLAUTH_ID_REQ = 17,
- AT_COUNTER = 19,
- AT_COUNTER_TOO_SMALL = 20,
- AT_NONCE_S = 21,
- AT_CLIENT_ERROR_CODE = 22,
- AT_IV = 129,
- AT_ENCR_DATA = 130,
- AT_NEXT_PSEUDONYM = 132,
- AT_NEXT_REAUTH_ID = 133,
- AT_CHECKCODE = 134,
- AT_RESULT_IND = 135,
-};
-
-ENUM_BEGIN(sim_attribute_names, AT_END, AT_CLIENT_ERROR_CODE,
- "AT_END",
- "AT_0",
- "AT_RAND",
- "AT_AUTN",
- "AT_RES",
- "AT_AUTS",
- "AT_5",
- "AT_PADDING",
- "AT_NONCE_MT",
- "AT_8",
- "AT_9",
- "AT_PERMANENT_ID_REQ",
- "AT_MAC",
- "AT_NOTIFICATION",
- "AT_ANY_ID_REQ",
- "AT_IDENTITY",
- "AT_VERSION_LIST",
- "AT_SELECTED_VERSION",
- "AT_FULLAUTH_ID_REQ",
- "AT_18",
- "AT_COUNTER",
- "AT_COUNTER_TOO_SMALL",
- "AT_NONCE_S",
- "AT_CLIENT_ERROR_CODE");
-ENUM_NEXT(sim_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE,
- "AT_IV",
- "AT_ENCR_DATA",
- "AT_131",
- "AT_NEXT_PSEUDONYM",
- "AT_NEXT_REAUTH_ID",
- "AT_CHECKCODE",
- "AT_RESULT_IND");
-ENUM_END(sim_attribute_names, AT_RESULT_IND);
-
-
-typedef struct private_eap_sim_t private_eap_sim_t;
-
-/**
- * Private data of an eap_sim_t object.
- */
-struct private_eap_sim_t {
-
- /**
- * Public authenticator_t interface.
- */
- eap_sim_t public;
-
- /**
- * ID of ourself
- */
- identification_t *peer;
-
- /**
- * SIM cardreader function loaded from library
- */
- sim_algo_t alg;
-
- /**
- * libraries get_triplet() function returning a triplet
- */
- sim_get_triplet_t get_triplet;
-
- /**
- * handle of the loaded library
- */
- void *handle;
-
- /**
- * how many times we try to authenticate
- */
- int tries;
-
- /**
- * unique EAP identifier
- */
- u_int8_t identifier;
-
- /**
- * EAP message type this role sends
- */
- u_int8_t type;
-
- /**
- * version this implementation uses
- */
- chunk_t version;
-
- /**
- * version list received from server
- */
- chunk_t version_list;
-
- /**
- * Nonce value used in AT_NONCE_MT
- */
- chunk_t nonce;
-
- /**
- * concatenated SRES values
- */
- chunk_t sreses;
-
- /**
- * k_encr key derived from MK
- */
- chunk_t k_encr;
-
- /**
- * k_auth key derived from MK, used for AT_MAC verification
- */
- chunk_t k_auth;
-
- /**
- * MSK, used for EAP-SIM based IKEv2 authentication
- */
- chunk_t msk;
-
- /**
- * EMSK, extendes MSK for further uses
- */
- chunk_t emsk;
-};
-
-/** length of the AT_NONCE_MT nonce value */
-#define NONCE_LEN 16
-/** length of the AT_MAC value */
-#define MAC_LEN 16
-/** length of the AT_RAND value */
-#define RAND_LEN 16
-/** length of Kc */
-#define KC_LEN 8
-/** length of SRES */
-#define SRES_LEN 4
-/** length of the k_encr key */
-#define KENCR_LEN 16
-/** length of the k_auth key */
-#define KAUTH_LEN 16
-/** length of the MSK */
-#define MSK_LEN 64
-/** length of the EMSK */
-#define EMSK_LEN 64
-
-static char version[] = {0x00,0x01};
-/* client error codes used in AT_CLIENT_ERROR_CODE */
-char client_error_general_buf[] = {0x00, 0x01};
-char client_error_unsupported_buf[] = {0x00, 0x02};
-char client_error_insufficient_buf[] = {0x00, 0x03};
-char client_error_notfresh_buf[] = {0x00, 0x04};
-chunk_t client_error_general = chunk_from_buf(client_error_general_buf);
-chunk_t client_error_unsupported = chunk_from_buf(client_error_unsupported_buf);
-chunk_t client_error_insufficient = chunk_from_buf(client_error_insufficient_buf);
-chunk_t client_error_notfresh = chunk_from_buf(client_error_notfresh_buf);
-
-/**
- * Read EAP and EAP-SIM header, return SIM type
- */
-static sim_subtype_t read_header(chunk_t *message)
-{
- sim_subtype_t type;
-
- if (message->len < 8)
- {
- *message = chunk_empty;
- return 0;
- }
- type = *(message->ptr + 5);
- *message = chunk_skip(*message, 8);
- return type;
-}
-
-/**
- * read the next attribute from the chunk data
- */
-static sim_attribute_t read_attribute(chunk_t *message, chunk_t *data)
-{
- sim_attribute_t attribute;
- size_t length;
-
- DBG3(DBG_IKE, "reading attribute from %B", message);
-
- if (message->len < 2)
- {
- return AT_END;
- }
- attribute = *message->ptr++;
- length = *message->ptr++ * 4 - 2;
- message->len -= 2;
- DBG3(DBG_IKE, "found attribute %N with length %d",
- sim_attribute_names, attribute, length);
-
- if (length > message->len)
- {
- return AT_END;
- }
- data->len = length;
- data->ptr = message->ptr;
- *message = chunk_skip(*message, length);
- return attribute;
-}
-
-/**
- * Build an EAP-SIM payload using a variable length attribute list.
- * The variable argument takes a sim_attribute_t followed by its data in a chunk.
- */
-static eap_payload_t *build_payload(private_eap_sim_t *this, u_int8_t identifier,
- sim_subtype_t type, ...)
-{
- chunk_t message = chunk_alloca(512);
- chunk_t pos = message;
- eap_payload_t *payload;
- va_list args;
- sim_attribute_t attr;
- u_int8_t *mac_pos = NULL;
- chunk_t mac_data = chunk_empty;
-
- /* write EAP header, skip length bytes */
- *pos.ptr++ = this->type;
- *pos.ptr++ = identifier;
- pos.ptr += 2;
- pos.len -= 4;
- /* write SIM header with type and subtype, zero reserved bytes */
- *pos.ptr++ = EAP_SIM;
- *pos.ptr++ = type;
- *pos.ptr++ = 0;
- *pos.ptr++ = 0;
- pos.len -= 4;
-
- va_start(args, type);
- while ((attr = va_arg(args, sim_attribute_t)) != AT_END)
- {
- chunk_t data = va_arg(args, chunk_t);
-
- DBG3(DBG_IKE, "building %N %B", sim_attribute_names, attr, &data);
-
- /* write attribute header */
- *pos.ptr++ = attr;
- pos.len--;
-
- switch (attr)
- {
- case AT_CLIENT_ERROR_CODE:
- case AT_SELECTED_VERSION:
- {
- *pos.ptr = data.len/4 + 1;
- pos = chunk_skip(pos, 1);
- memcpy(pos.ptr, data.ptr, data.len);
- pos = chunk_skip(pos, data.len);
- break;
- }
- case AT_IDENTITY:
- case AT_VERSION_LIST:
- {
- u_int16_t act_len = data.len;
- /* align up to four byte */
- if (data.len % 4)
- {
- chunk_t tmp = chunk_alloca((data.len/4)*4 + 4);
- memset(tmp.ptr, 0, tmp.len);
- memcpy(tmp.ptr, data.ptr, data.len);
- data = tmp;
- }
- *pos.ptr = data.len/4 + 1;
- pos = chunk_skip(pos, 1);
- /* actual length in bytes */
- *(u_int16_t*)pos.ptr = htons(act_len);
- pos = chunk_skip(pos, sizeof(u_int16_t));
- memcpy(pos.ptr, data.ptr, data.len);
- pos = chunk_skip(pos, data.len);
- break;
- }
- case AT_NONCE_MT:
- {
- *pos.ptr = data.len/4 + 1;
- pos = chunk_skip(pos, 1);
- memset(pos.ptr, 0, 2);
- pos = chunk_skip(pos, 2);
- memcpy(pos.ptr, data.ptr, data.len);
- pos = chunk_skip(pos, data.len);
- break;
- }
- case AT_MAC:
- {
- *pos.ptr++ = 5; pos.len--;
- *pos.ptr++ = 0; pos.len--;
- *pos.ptr++ = 0; pos.len--;
- mac_pos = pos.ptr;
- memset(mac_pos, 0, MAC_LEN);
- pos = chunk_skip(pos, MAC_LEN);
- mac_data = data;
- break;
- }
- case AT_RAND:
- {
- *pos.ptr++ = data.len/4 + 1; pos.len--;
- *pos.ptr++ = 0; pos.len--;
- *pos.ptr++ = 0; pos.len--;
- memcpy(pos.ptr, data.ptr, data.len);
- pos = chunk_skip(pos, data.len);
- break;
- }
- default:
- DBG1(DBG_IKE, "no rule to build EAP_SIM attribute %N, skipped",
- sim_attribute_names, attr);
- break;
- }
- }
- va_end(args);
-
- /* calculate message length, write into header */
- message.len = pos.ptr - message.ptr;
- *(u_int16_t*)(message.ptr + 2) = htons(message.len);
-
- /* create MAC if AT_MAC attribte was included. Append supplied va_arg
- * chunk mac_data to "to-sign" chunk */
- if (mac_pos)
- {
- signer_t *signer = signer_create(AUTH_HMAC_SHA1_128);
- signer->set_key(signer, this->k_auth);
- mac_data = chunk_cata("cc", message, mac_data);
- signer->get_signature(signer, mac_data, mac_pos);
- DBG3(DBG_IKE, "AT_MAC signature of %B\n is %b",
- &mac_data, mac_pos, MAC_LEN);
- signer->destroy(signer);
- }
-
- payload = eap_payload_create_data(message);
-
- DBG3(DBG_IKE, "created EAP message %B", &message);
- return payload;
-}
-
-/**
- * process an EAP-SIM/Request/Start message
- */
-static status_t peer_process_start(private_eap_sim_t *this, eap_payload_t *in,
- eap_payload_t **out)
-{
- chunk_t message, data;
- sim_attribute_t attribute, include_id = AT_END;
- u_int8_t identifier;
-
- identifier = in->get_identifier(in);
- message = in->get_data(in);
- read_header(&message);
-
- while ((attribute = read_attribute(&message, &data)) != AT_END)
- {
- switch (attribute)
- {
- case AT_VERSION_LIST:
- {
- /* check if server supports our implementation */
- bool found = FALSE;
- if (data.len > 2)
- {
- /* read actual length first */
- data.len = min(data.len, ntohs(*(u_int16_t*)data.ptr) + 2);
- data = chunk_skip(data, 2);
- chunk_free(&this->version_list);
- this->version_list = chunk_clone(data);
- while (data.len >= this->version.len)
- {
- if (memeq(data.ptr, this->version.ptr, this->version.len))
- {
- found = TRUE;
- break;
- }
- data = chunk_skip(data, this->version.len);
- }
- }
- if (!found)
- {
- DBG1(DBG_IKE, "server does not support EAP_SIM "
- "version number %#B", &this->version);
- *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
- AT_CLIENT_ERROR_CODE, client_error_unsupported,
- AT_END);
- return NEED_MORE;
- }
- break;
- }
- case AT_PERMANENT_ID_REQ:
- case AT_FULLAUTH_ID_REQ:
- case AT_ANY_ID_REQ:
- /* only include AT_IDENTITY if requested */
- include_id = AT_IDENTITY;
- break;
- case AT_NOTIFICATION:
- {
- u_int16_t code = 0;
- if (data.len == 2)
- {
- code = ntohs(*(u_int16_t*)data.ptr);
- }
- if (code <= 32767) /* no success bit */
- {
- DBG1(DBG_IKE, "received %N error %d",
- sim_attribute_names, attribute, code);
- *out = build_payload(this,
- in->get_identifier(in), SIM_CLIENT_ERROR,
- AT_CLIENT_ERROR_CODE, client_error_general,
- AT_END);
- return NEED_MORE;
- }
- else
- {
- DBG1(DBG_IKE, "received %N code %d",
- sim_attribute_names, attribute, code);
- }
- break;
- }
- default:
- DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
- sim_attribute_names, attribute);
- break;
- }
- }
-
- /* build payload. If "include_id" is AT_END, AT_IDENTITY is ommited */
- *out = build_payload(this, identifier, SIM_START,
- AT_SELECTED_VERSION, this->version,
- AT_NONCE_MT, this->nonce,
- include_id, this->peer->get_encoding(this->peer),
- AT_END);
- return NEED_MORE;
-}
-
-/**
- * derive EAP keys from kc
- */
-static void derive_keys(private_eap_sim_t *this, chunk_t kcs)
-{
- chunk_t tmp, mk;
- hasher_t *hasher;
- prf_t *prf;
- int i;
-
- /* build MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
- tmp = chunk_cata("ccccc", this->peer->get_encoding(this->peer), kcs,
- this->nonce, this->version_list, this->version);
- hasher = hasher_create(HASH_SHA1);
- mk = chunk_alloca(hasher->get_hash_size(hasher));
- hasher->get_hash(hasher, tmp, mk.ptr);
- hasher->destroy(hasher);
- DBG3(DBG_IKE, "MK = SHA1(%B\n) = %B", &tmp, &mk);
-
- /* K_encr | K_auth | MSK | EMSK = prf() | prf() | prf() | prf()
- * FIPS PRF has 320 bit block size, we need 160 byte for keys
- * => run prf four times */
- prf = prf_create(PRF_FIPS_SHA1_160);
- prf->set_key(prf, mk);
- tmp = chunk_alloca(prf->get_block_size(prf) * 4);
- for (i = 0; i < 4; i++)
- {
- prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * i);
- }
- prf->destroy(prf);
- chunk_free(&this->k_encr);
- chunk_free(&this->k_auth);
- chunk_free(&this->msk);
- chunk_free(&this->emsk);
- chunk_split(tmp, "aaaa", KENCR_LEN, &this->k_encr, KAUTH_LEN, &this->k_auth,
- MSK_LEN, &this->msk, EMSK_LEN, &this->emsk);
- DBG3(DBG_IKE, "K_encr %B\nK_auth %B\nMSK %B\nEMSK %B",
- &this->k_encr, &this->k_auth, &this->msk, &this->emsk);
-}
-
-/**
- * process an EAP-SIM/Request/Challenge message
- */
-static status_t peer_process_challenge(private_eap_sim_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- chunk_t message, data, tmp, kcs, kc, sreses, sres;
- sim_attribute_t attribute;
- u_int8_t identifier;
- chunk_t mac = chunk_empty, rands = chunk_empty;
- signer_t *signer;
-
- if (this->tries-- <= 0)
- {
- /* give up without notification. This hack is required as some buggy
- * server implementations won't respect our client-error. */
- return FAILED;
- }
-
- identifier = in->get_identifier(in);
- message = in->get_data(in);
- read_header(&message);
-
- while ((attribute = read_attribute(&message, &data)) != AT_END)
- {
- switch (attribute)
- {
- case AT_RAND:
- {
- rands = chunk_skip(data, 2);
- break;
- }
- case AT_MAC:
- {
- /* backup MAC, zero it inline for later verification */
- data = chunk_skip(data, 2);
- mac = chunk_clonea(data);
- memset(data.ptr, 0, data.len);
- break;
- }
- case AT_NOTIFICATION:
- {
- u_int16_t code = 0;
- if (data.len == 2)
- {
- code = ntohs(*(u_int16_t*)data.ptr);
- }
- if (code <= 32767) /* no success bit */
- {
- DBG1(DBG_IKE, "received %N error %d",
- sim_attribute_names, attribute, code);
- *out = build_payload(this,
- in->get_identifier(in), SIM_CLIENT_ERROR,
- AT_CLIENT_ERROR_CODE, client_error_general,
- AT_END);
- return NEED_MORE;
- }
- else
- {
- DBG1(DBG_IKE, "received %N code %d",
- sim_attribute_names, attribute, code);
- }
- break;
- }
- default:
- DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
- sim_attribute_names, attribute);
- break;
- }
- }
-
- /* excepting two or three RAND, each 16 bytes. We require two valid
- * and different RANDs */
- if ((rands.len != 2 * RAND_LEN && rands.len != 3 * RAND_LEN) ||
- memeq(rands.ptr, rands.ptr + RAND_LEN, RAND_LEN))
- {
- DBG1(DBG_IKE, "no valid AT_RAND received");
- *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
- AT_CLIENT_ERROR_CODE, client_error_insufficient,
- AT_END);
- return NEED_MORE;
- }
- if (mac.len != MAC_LEN)
- {
- DBG1(DBG_IKE, "no valid AT_MAC received");
- *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
- AT_CLIENT_ERROR_CODE, client_error_general,
- AT_END);
- return NEED_MORE;
- }
-
- /* get two or three KCs/SRESes from SIM using RANDs */
- kcs = kc = chunk_alloca(rands.len / 2);
- sreses = sres = chunk_alloca(rands.len / 4);
- while (rands.len > 0)
- {
- int kc_len = kc.len, sres_len = sres.len;
-
- if (this->alg(rands.ptr, RAND_LEN, sres.ptr, &sres_len, kc.ptr, &kc_len))
- {
- DBG1(DBG_IKE, "unable to get EAP-SIM triplet");
- *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
- AT_CLIENT_ERROR_CODE, client_error_general,
- AT_END);
- return NEED_MORE;
- }
- DBG3(DBG_IKE, "got triplet for RAND %b\n Kc %b\n SRES %b",
- rands.ptr, RAND_LEN, sres.ptr, sres_len, kc.ptr, kc_len);
- kc = chunk_skip(kc, kc_len);
- sres = chunk_skip(sres, sres_len);
- rands = chunk_skip(rands, RAND_LEN);
- }
-
- derive_keys(this, kcs);
-
- /* verify AT_MAC attribute, signature is over "EAP packet | NONCE_MT" */
- signer = signer_create(AUTH_HMAC_SHA1_128);
- signer->set_key(signer, this->k_auth);
- tmp = chunk_cata("cc", in->get_data(in), this->nonce);
- if (!signer->verify_signature(signer, tmp, mac))
- {
- DBG1(DBG_IKE, "AT_MAC verification failed");
- signer->destroy(signer);
- *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
- AT_CLIENT_ERROR_CODE, client_error_general,
- AT_END);
- return NEED_MORE;
- }
- signer->destroy(signer);
-
- /* build response, AT_MAC is built over "EAP packet | n*SRES" */
- *out = build_payload(this, identifier, SIM_CHALLENGE,
- AT_MAC, sreses,
- AT_END);
- return NEED_MORE;
-}
-
-/**
- * process an EAP-SIM/Response/Challenge message
- */
-static status_t server_process_challenge(private_eap_sim_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- chunk_t message, data;
- sim_attribute_t attribute;
- chunk_t mac = chunk_empty, tmp;
- signer_t *signer;
-
- message = in->get_data(in);
- read_header(&message);
-
- while ((attribute = read_attribute(&message, &data)) != AT_END)
- {
- switch (attribute)
- {
- case AT_MAC:
- /* MAC has two reserved bytes */
- if (data.len == MAC_LEN + 2)
- { /* clone and zero MAC for verification */
- mac = chunk_clonea(chunk_skip(data, 2));
- memset(data.ptr, 0, data.len);
- }
- break;
- default:
- DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
- sim_attribute_names, attribute);
- break;
- }
- }
- if (!mac.ptr)
- {
- DBG1(DBG_IKE, "no valid AT_MAC attribute received");
- return FAILED;
- }
- /* verify AT_MAC attribute, signature is over "EAP packet | n*SRES" */
- signer = signer_create(AUTH_HMAC_SHA1_128);
- signer->set_key(signer, this->k_auth);
- tmp = chunk_cata("cc", in->get_data(in), this->sreses);
- if (!signer->verify_signature(signer, tmp, mac))
- {
- DBG1(DBG_IKE, "AT_MAC verification failed");
- signer->destroy(signer);
- return FAILED;
- }
- signer->destroy(signer);
- return SUCCESS;
-}
-
-/**
- * process an EAP-SIM/Response/Start message
- */
-static status_t server_process_start(private_eap_sim_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- chunk_t message, data;
- sim_attribute_t attribute;
- bool supported = FALSE;
- chunk_t rands, rand, kcs, kc, sreses, sres;
- char id[64];
- int len, i, rand_len, kc_len, sres_len;
-
- message = in->get_data(in);
- read_header(&message);
-
- while ((attribute = read_attribute(&message, &data)) != AT_END)
- {
- switch (attribute)
- {
- case AT_NONCE_MT:
- if (data.len == NONCE_LEN + 2)
- {
- this->nonce = chunk_clone(chunk_skip(data, 2));
- }
- break;
- case AT_SELECTED_VERSION:
- if (chunk_equals(data, this->version))
- {
- supported = TRUE;
- }
- break;
- default:
- DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
- sim_attribute_names, attribute);
- break;
- }
- }
- if (!supported || !this->nonce.ptr)
- {
- DBG1(DBG_IKE, "received incomplete EAP-SIM/Response/Start");
- return FAILED;
- }
- len = snprintf(id, sizeof(id), "%D", this->peer);
- if (len > sizeof(id) || len < 0)
- {
- return FAILED;
- }
-
- /* read triplets from provider */
- rand = rands = chunk_alloca(RAND_LEN * TRIPLET_COUNT);
- kc = kcs = chunk_alloca(KC_LEN * TRIPLET_COUNT);
- sres = sreses = chunk_alloca(SRES_LEN * TRIPLET_COUNT);
- rands.len = 0;
- kcs.len = 0;
- sreses.len = 0;
- for (i = 0; i < TRIPLET_COUNT; i++)
- {
- rand_len = RAND_LEN;
- kc_len = KC_LEN;
- sres_len = SRES_LEN;
- if (this->get_triplet(id, rand.ptr, &rand_len, sres.ptr, &sres_len,
- kc.ptr, &kc_len))
- {
- DBG1(DBG_IKE, "getting EAP-SIM triplet %d failed", i);
- return FAILED;
- }
- rands.len += rand_len;
- kcs.len += kc_len;
- sreses.len += sres_len;
- rand = chunk_skip(rand, rand_len);
- kc = chunk_skip(kc, kc_len);
- sres = chunk_skip(sres, sres_len);
- }
- derive_keys(this, kcs);
-
- /* build MAC over "EAP packet | NONCE_MT" */
- *out = build_payload(this, this->identifier++, SIM_CHALLENGE, AT_RAND,
- rands, AT_MAC, this->nonce, AT_END);
- this->sreses = chunk_clone(sreses);
- return NEED_MORE;
-}
-
-/**
- * process an EAP-SIM/Request/Notification message
- */
-static status_t peer_process_notification(private_eap_sim_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- chunk_t message, data;
- sim_attribute_t attribute;
-
- message = in->get_data(in);
- read_header(&message);
-
- while ((attribute = read_attribute(&message, &data)) != AT_END)
- {
- switch (attribute)
- {
- case AT_NOTIFICATION:
- {
- u_int16_t code = 0;
- if (data.len == 2)
- {
- code = ntohs(*(u_int16_t*)data.ptr);
- }
- if (code <= 32767) /* no success bit */
- {
- DBG1(DBG_IKE, "received %N error %d",
- sim_attribute_names, attribute, code);
- *out = build_payload(this,
- in->get_identifier(in), SIM_CLIENT_ERROR,
- AT_CLIENT_ERROR_CODE, client_error_general,
- AT_END);
- return NEED_MORE;
- }
- else
- {
- DBG1(DBG_IKE, "received %N code %d",
- sim_attribute_names, attribute, code);
- }
- break;
- }
- default:
- DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
- sim_attribute_names, attribute);
- break;
- }
- }
- /* reply with empty notification */
- *out = build_payload(this, in->get_identifier(in), SIM_NOTIFICATION, AT_END);
- return NEED_MORE;
-}
-
-/**
- * Process a client error
- */
-static status_t server_process_client_error(private_eap_sim_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- chunk_t message, data;
- sim_attribute_t attribute;
-
- message = in->get_data(in);
- read_header(&message);
-
- while ((attribute = read_attribute(&message, &data)) != AT_END)
- {
- if (attribute == AT_CLIENT_ERROR_CODE)
- {
- u_int16_t code = 0;
- if (data.len == 2)
- {
- code = ntohs(*(u_int16_t*)data.ptr);
- }
- DBG1(DBG_IKE, "received %N error %d",
- sim_attribute_names, attribute, code);
- }
- else
- {
- DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
- sim_attribute_names, attribute);
- }
- }
- return FAILED;
-}
-
-/**
- * Implementation of eap_method_t.process for the peer
- */
-static status_t peer_process(private_eap_sim_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- sim_subtype_t type;
- chunk_t message;
-
- message = in->get_data(in);
- type = read_header(&message);
-
- switch (type)
- {
- case SIM_START:
- return peer_process_start(this, in, out);
- case SIM_CHALLENGE:
- return peer_process_challenge(this, in, out);
- case SIM_NOTIFICATION:
- return peer_process_notification(this, in, out);
- default:
- DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N",
- sim_subtype_names, type);
- *out = build_payload(this, in->get_identifier(in), SIM_CLIENT_ERROR,
- AT_CLIENT_ERROR_CODE, client_error_general, AT_END);
- return NEED_MORE;
- }
-}
-
-/**
- * Implementation of eap_method_t.process for the server
- */
-static status_t server_process(private_eap_sim_t *this,
- eap_payload_t *in, eap_payload_t **out)
-{
- sim_subtype_t type;
- chunk_t message;
-
- message = in->get_data(in);
- type = read_header(&message);
-
- switch (type)
- {
- case SIM_START:
- return server_process_start(this, in, out);
- case SIM_CHALLENGE:
- return server_process_challenge(this, in, out);
- case SIM_CLIENT_ERROR:
- return server_process_client_error(this, in, out);
- default:
- DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N",
- sim_subtype_names, type);
- return FAILED;
- }
-}
-
-/**
- * Implementation of eap_method_t.initiate for the peer
- */
-static status_t peer_initiate(private_eap_sim_t *this, eap_payload_t **out)
-{
- /* peer never initiates */
- return FAILED;
-}
-
-/**
- * Implementation of eap_method_t.initiate for the server
- */
-static status_t server_initiate(private_eap_sim_t *this, eap_payload_t **out)
-{
- /* version_list to derive MK, no padding */
- this->version_list = chunk_clone(this->version);
- /* build_payloads adds padding itself */
- *out = build_payload(this, this->identifier++, SIM_START,
- AT_VERSION_LIST, this->version, AT_END);
- return NEED_MORE;
-}
-
-/**
- * Implementation of eap_method_t.get_type.
- */
-static eap_type_t get_type(private_eap_sim_t *this, u_int32_t *vendor)
-{
- *vendor = 0;
- return EAP_SIM;
-}
-
-/**
- * Implementation of eap_method_t.get_msk.
- */
-static status_t get_msk(private_eap_sim_t *this, chunk_t *msk)
-{
- if (this->msk.ptr)
- {
- *msk = this->msk;
- return SUCCESS;
- }
- return FAILED;
-}
-
-/**
- * Implementation of eap_method_t.is_mutual.
- */
-static bool is_mutual(private_eap_sim_t *this)
-{
- return TRUE;
-}
-
-/**
- * Implementation of eap_method_t.destroy.
- */
-static void destroy(private_eap_sim_t *this)
-{
- dlclose(this->handle);
- chunk_free(&this->nonce);
- chunk_free(&this->sreses);
- chunk_free(&this->version_list);
- chunk_free(&this->k_auth);
- chunk_free(&this->k_encr);
- chunk_free(&this->msk);
- chunk_free(&this->emsk);
- free(this);
-}
-
-/*
- * Described in header.
- */
-eap_sim_t *eap_create(eap_role_t role,
- identification_t *server, identification_t *peer)
-{
- private_eap_sim_t *this;
- randomizer_t *randomizer;
- void *symbol;
- char *name;
-
- this = malloc_thing(private_eap_sim_t);
- this->alg = NULL;
- this->get_triplet = NULL;
- this->nonce = chunk_empty;
- this->sreses = chunk_empty;
- this->peer = peer;
- this->tries = MAX_TRIES;
- this->version.ptr = version;
- this->version.len = sizeof(version);
- this->version_list = chunk_empty;
- this->k_auth = chunk_empty;
- this->k_encr = chunk_empty;
- this->msk = chunk_empty;
- this->emsk = chunk_empty;
- this->identifier = random();
-
- this->handle = dlopen(SIM_READER_LIB, RTLD_LAZY);
- if (this->handle == NULL)
- {
- DBG1(DBG_IKE, "unable to open SIM reader '%s'", SIM_READER_LIB);
- free(this);
- return NULL;
- }
- switch (role)
- {
- case EAP_PEER:
- name = SIM_READER_ALG;
- break;
- case EAP_SERVER:
- name = SIM_READER_GET_TRIPLET;
- break;
- default:
- free(this);
- return NULL;
- }
- symbol = dlsym(this->handle, name);
- if (symbol == NULL)
- {
- DBG1(DBG_IKE, "unable to open SIM function '%s' in '%s'",
- name, SIM_READER_LIB);
- dlclose(this->handle);
- free(this);
- return NULL;
- }
- switch (role)
- {
- case EAP_SERVER:
- this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))server_initiate;
- this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))server_process;
- this->get_triplet = symbol;
- this->type = EAP_REQUEST;
- break;
- case EAP_PEER:
- this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))peer_initiate;
- this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))peer_process;
- this->alg = symbol;
- this->type = EAP_RESPONSE;
- randomizer = randomizer_create();
- if (randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_LEN,
- &this->nonce))
- {
- DBG1(DBG_IKE, "unable to generate NONCE for EAP_SIM");
- randomizer->destroy(randomizer);
- free(this);
- return NULL;
- }
- randomizer->destroy(randomizer);
- break;
- default:
- free(this);
- return NULL;
- }
- this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type;
- this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
- this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
- this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
-
- return &this->public;
-}
diff --git a/src/charon/sa/authenticators/eap/eap_sim.h b/src/charon/sa/authenticators/eap/eap_sim.h
deleted file mode 100644
index d50cf7397..000000000
--- a/src/charon/sa/authenticators/eap/eap_sim.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * @file eap_sim.h
- *
- * @brief Interface of eap_sim_t.
- *
- */
-
-/*
- * Copyright (C) 2007 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#ifndef EAP_SIM_H_
-#define EAP_SIM_H_
-
-typedef struct eap_sim_t eap_sim_t;
-
-#include <sa/authenticators/eap/eap_method.h>
-
-/** the library containing with the triplet functions */
-#ifndef SIM_READER_LIB
-#error SIM_READER_LIB not specified, use --with-sim-reader option
-#endif /* SIM_READER_LIB */
-
-/**
- * @brief Cardreaders SIM function.
- *
- * @param rand RAND to run algo with
- * @param rand_length length of value in rand
- * @param sres buffer to get SRES
- * @param sres_length size of buffer in sres, returns bytes written to SRES
- * @param kc buffer to get Kc
- * @param kc_length size of buffer in Kc, returns bytes written to Kc
- * @return zero on success
- */
-typedef int (*sim_algo_t)(const unsigned char *rand, int rand_length,
- unsigned char *sres, int *sres_length,
- unsigned char *kc, int *kc_length);
-
-#ifndef SIM_READER_ALG
-/** the SIM_READER_LIB's algorithm, uses sim_algo_t signature */
-#define SIM_READER_ALG "sim_run_alg"
-#endif /* SIM_READER_ALG */
-
-/**
- * @brief Function to get a SIM triplet.
- *
- * @param identity identity (imsi) to get a triplet for
- * @param rand buffer to get RAND
- * @param rand_length size of buffer in rand, returns bytes written to RAND
- * @param sres buffer to get SRES
- * @param sres_length size of buffer in sres, returns bytes written to SRES
- * @param kc buffer to get Kc
- * @param kc_length size of buffer in Kc, returns bytes written to Kc
- * @return zero on success
- */
-typedef int (*sim_get_triplet_t)(char *identity,
- unsigned char *rand, int *rand_length,
- unsigned char *sres, int *sres_length,
- unsigned char *kc, int *kc_length);
-
-#ifndef SIM_READER_GET_TRIPLET
-/** the SIM_READER_LIB's get-triplet function, uses sim_get_triplet_t signature */
-#define SIM_READER_GET_TRIPLET "sim_get_triplet"
-#endif /* SIM_READER_GET_TRIPLET */
-
-/**
- * @brief Implementation of the eap_method_t interface using EAP-SIM.
- *
- * This EAP-SIM client implementation uses another pluggable library to
- * access the SIM card/triplet provider. This module is specified using the
- * SIM_READER_LIB definition. It has to privde a sim_run_alg() function to
- * calculate a triplet (client), and/or a sim_get_triplet() function to get
- * a triplet (server). These functions are named to the SIM_READER_ALG and
- * the SIM_READER_GET_TRIPLET definitions.
- *
- * @b Constructors:
- * - eap_create() of this module
- * - eap_client_create() using eap_method EAP_SIM
- *
- * @ingroup eap
- */
-struct eap_sim_t {
-
- /**
- * Implemented eap_method_t interface.
- */
- eap_method_t eap_method_interface;
-};
-
-/**
- * @brief Creates the EAP method EAP-SIM.
- *
- * @param role role of the module, client/server
- * @param server ID of the EAP server
- * @param peer ID of the EAP client
- * @return eap_sim_t object
- *
- * @ingroup eap
- */
-eap_sim_t *eap_create(eap_role_t role,
- identification_t *server, identification_t *peer);
-
-#endif /* EAP_SIM_H_ */
diff --git a/src/charon/sa/authenticators/eap/sim/eap_sim_file.c b/src/charon/sa/authenticators/eap/sim/eap_sim_file.c
deleted file mode 100644
index 2ab45a578..000000000
--- a/src/charon/sa/authenticators/eap/sim/eap_sim_file.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/**
- * @file eap_sim.h
- *
- * @brief Interface of eap_sim_t.
- *
- */
-
-/*
- * Copyright (C) 2007 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include <daemon.h>
-
-#define IMSI_LEN 64
-#define RAND_LEN 16
-#define SRES_LEN 4
-#define KC_LEN 8
-
-typedef struct triplet_t triplet_t;
-
-struct triplet_t {
- unsigned char imsi[IMSI_LEN];
- unsigned char rand[RAND_LEN];
- unsigned char sres[SRES_LEN];
- unsigned char kc[KC_LEN];
-};
-
-static triplet_t *triplets = NULL;
-static int triplet_count = 0;
-
-#define TRIPLET_FILE IPSEC_CONFDIR "/ipsec.d/triplets.dat"
-
-/**
- * convert a single HEX char to its integer value
- */
-static int hexchr(char chr)
-{
- switch (chr)
- {
- case '0'...'9':
- return chr - '0';
- case 'A'...'F':
- return 10 + chr - 'A';
- case 'a'...'f':
- return 10 + chr - 'a';
- }
- return 0;
-}
-
-/**
- * convert a HEX string into a char array bin, limited by array length len
- */
-static void hex2bin(char *hex, unsigned char *bin, size_t len)
-{
- char *pos;
- int i, even = 1;
-
- pos = hex - 1;
- /* find the end, as we convert bottom up */
- while (TRUE)
- {
- switch (*(pos+1))
- {
- case '0'...'9':
- case 'A'...'F':
- case 'a'...'f':
- pos++;
- continue;
- }
- break;
- }
- /* convert two hex chars into a single bin byte */
- for (i = 0; pos >= hex && i < len; pos--)
- {
- if (even)
- {
- bin[len - 1 - i] = hexchr(*pos);
- }
- else
- {
- bin[len - 1 - i] |= 16 * hexchr(*pos);
- i++;
- }
- even = !even;
- }
-}
-
-/**
- * free up allocated triplets
- */
-static void __attribute__ ((destructor)) free_triplets()
-{
- free(triplets);
-}
-
-/**
- * read the triplets from the file, using freeradius triplet file syntax:
- * http://www.freeradius.org/radiusd/doc/rlm_sim_triplets
- */
-static void __attribute__ ((constructor)) read_triplets()
-{
- char line[512], *data[4], *pos;
- FILE *file;
- int i, nr = 0;
- triplet_t *triplet;
-
- file = fopen(TRIPLET_FILE, "r");
- if (file == NULL)
- {
- DBG1(DBG_CFG, "opening triplet file %s failed: %s",
- TRIPLET_FILE, strerror(errno));
- return;
- }
-
- if (triplets)
- {
- free(triplets);
- triplets = NULL;
- triplet_count = 0;
- }
-
- /* read line by line */
- while (fgets(line, sizeof(line), file))
- {
- nr++;
- /* skip comments, empty lines */
- switch (line[0])
- {
- case '\n':
- case '\r':
- case '#':
- case '\0':
- continue;
- default:
- break;
- }
- /* read comma separated values */
- pos = line;
- for (i = 0; i < 4; i++)
- {
- data[i] = pos;
- pos = strchr(pos, ',');
- if (pos)
- {
- *pos = '\0';
- pos++;
- }
- else if (i != 3)
- {
- DBG1(DBG_CFG, "error in triplet file, line %d", nr);
- fclose(file);
- return;
- }
- }
- /* allocate new triplet */
- triplet_count++;
- triplets = realloc(triplets, triplet_count * sizeof(triplet_t));
- triplet = &triplets[triplet_count - 1];
- memset(triplet, 0, sizeof(triplet_t));
-
- /* convert/copy triplet data */
- for (i = 0; i < IMSI_LEN - 1; i++)
- {
- switch (data[0][i])
- {
- case '\n':
- case '\r':
- case '\0':
- break;
- default:
- triplet->imsi[i] = data[0][i];
- continue;
- }
- break;
- }
- hex2bin(data[1], triplet->rand, RAND_LEN);
- hex2bin(data[2], triplet->sres, SRES_LEN);
- hex2bin(data[3], triplet->kc, KC_LEN);
-
- DBG4(DBG_CFG, "triplet: imsi %b\nrand %b\nsres %b\nkc %b",
- triplet->imsi, IMSI_LEN, triplet->rand, RAND_LEN,
- triplet->sres, SRES_LEN, triplet->kc, KC_LEN);
- }
- fclose(file);
- DBG2(DBG_CFG, "read %d triplets from %s", triplet_count, TRIPLET_FILE);
-}
-
-/**
- * Run the sim algorithm, see eap_sim.h
- */
-int sim_run_alg(const unsigned char *rand, int rand_length,
- unsigned char *sres, int *sres_length,
- unsigned char *kc, int *kc_length)
-{
- int current;
-
- if (rand_length != RAND_LEN ||
- *sres_length < SRES_LEN ||
- *kc_length < KC_LEN)
- {
- return 1;
- }
-
- for (current = 0; current < triplet_count; current++)
- {
- if (memcmp(triplets[current].rand, rand, RAND_LEN) == 0)
- {
- memcpy(sres, triplets[current].sres, SRES_LEN);
- memcpy(kc, triplets[current].kc, KC_LEN);
- *sres_length = SRES_LEN;
- *kc_length = KC_LEN;
- return 0;
- }
- }
- return 2;
-}
-
-/**
- * Get a single triplet, see_eap_sim.h
- */
-int sim_get_triplet(char *imsi,
- unsigned char *rand, int *rand_length,
- unsigned char *sres, int *sres_length,
- unsigned char *kc, int *kc_length)
-{
- int current;
- triplet_t *triplet;
- static int skip = -1;
-
- DBG2(DBG_CFG, "getting triplet for %s", imsi);
-
- if (*rand_length < RAND_LEN ||
- *sres_length < SRES_LEN ||
- *kc_length < KC_LEN)
- {
- return 1;
- }
- if (triplet_count == 0)
- {
- return 2;
- }
- for (current = 0; current < triplet_count; current++)
- {
- triplet = &triplets[current];
-
- if (streq(imsi, triplet->imsi))
- {
- /* skip triplet if already used */
- if (skip >= current)
- {
- continue;
- }
- *rand_length = RAND_LEN;
- *sres_length = SRES_LEN;
- *kc_length = KC_LEN;
- memcpy(rand, triplet->rand, RAND_LEN);
- memcpy(sres, triplet->sres, SRES_LEN);
- memcpy(kc, triplet->kc, KC_LEN);
- /* remember used triplet */
- skip = current;
- return 0;
- }
- }
- if (skip > -1)
- {
- /* no triplet left, reuse triplets */
- skip = -1;
- return sim_get_triplet(imsi, rand, rand_length,
- sres, sres_length, kc, kc_length);
- }
- return 2;
-}
-
diff --git a/src/charon/sa/authenticators/eap_authenticator.c b/src/charon/sa/authenticators/eap_authenticator.c
index edd75da43..95bb5e57f 100644
--- a/src/charon/sa/authenticators/eap_authenticator.c
+++ b/src/charon/sa/authenticators/eap_authenticator.c
@@ -1,10 +1,3 @@
-/**
- * @file eap_authenticator.c
- *
- * @brief Implementation of eap_authenticator_t.
- *
- */
-
/*
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,8 @@
* 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.
+ *
+ * $Id: eap_authenticator.c 3589 2008-03-13 14:14:44Z martin $
*/
#include <string.h>
@@ -160,9 +155,9 @@ static status_t initiate(private_eap_authenticator_t *this, eap_type_t type,
{
DBG1(DBG_IKE, "requesting %N authentication", eap_type_names, type);
}
- this->method = eap_method_create(type, vendor, this->role,
- this->ike_sa->get_my_id(this->ike_sa),
- this->ike_sa->get_other_id(this->ike_sa));
+ this->method = charon->eap->create_instance(charon->eap, type, vendor,
+ this->role, this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa));
if (this->method == NULL)
{
@@ -195,9 +190,11 @@ static status_t process_peer(private_eap_authenticator_t *this,
if (!vendor && type == EAP_IDENTITY)
{
- eap_method_t *method = eap_method_create(type, 0, EAP_PEER,
- this->ike_sa->get_other_id(this->ike_sa),
- this->ike_sa->get_my_id(this->ike_sa));
+ eap_method_t *method;
+
+ method = charon->eap->create_instance(charon->eap, type, 0, EAP_PEER,
+ this->ike_sa->get_other_id(this->ike_sa),
+ this->ike_sa->get_my_id(this->ike_sa));
if (method == NULL || method->process(method, in, out) != SUCCESS)
{
@@ -227,9 +224,10 @@ static status_t process_peer(private_eap_authenticator_t *this,
DBG1(DBG_IKE, "EAP server requested %N authentication",
eap_type_names, type);
}
- this->method = eap_method_create(type, vendor, EAP_PEER,
- this->ike_sa->get_other_id(this->ike_sa),
- this->ike_sa->get_my_id(this->ike_sa));
+ this->method = charon->eap->create_instance(charon->eap,
+ type, vendor, EAP_PEER,
+ this->ike_sa->get_other_id(this->ike_sa),
+ this->ike_sa->get_my_id(this->ike_sa));
if (this->method == NULL)
{
DBG1(DBG_IKE, "EAP server requested unsupported "
diff --git a/src/charon/sa/authenticators/eap_authenticator.h b/src/charon/sa/authenticators/eap_authenticator.h
index cf2180ee3..2dad59fbb 100644
--- a/src/charon/sa/authenticators/eap_authenticator.h
+++ b/src/charon/sa/authenticators/eap_authenticator.h
@@ -1,10 +1,3 @@
-/**
- * @file eap_authenticator.h
- *
- * @brief Interface of eap_authenticator_t.
- *
- */
-
/*
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: eap_authenticator.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup eap_authenticator eap_authenticator
+ * @{ @ingroup authenticators
*/
#ifndef EAP_AUTHENTICATOR_H_
@@ -29,7 +29,7 @@ typedef struct eap_authenticator_t eap_authenticator_t;
#include <encoding/payloads/eap_payload.h>
/**
- * @brief Implementation of the authenticator_t interface using AUTH_EAP.
+ * Implementation of the authenticator_t interface using AUTH_EAP.
*
* Authentication using EAP involves the most complex authenticator. It stays
* alive over multiple ike_auth transactions and handles multiple EAP
@@ -68,11 +68,6 @@ typedef struct eap_authenticator_t eap_authenticator_t;
+--------+ +--------+
@endverbatim
- * @b Constructors:
- * - eap_authenticator_create()
- * - authenticator_create() using auth_method AUTH_EAP
- *
- * @ingroup authenticators
*/
struct eap_authenticator_t {
@@ -82,7 +77,7 @@ struct eap_authenticator_t {
authenticator_t authenticator_interface;
/**
- * @brief Check if the EAP method was/is mutual and secure.
+ * Check if the EAP method was/is mutual and secure.
*
* RFC4306 proposes to authenticate the EAP responder (server) by standard
* IKEv2 methods (RSA, psk). Not all, but some EAP methods
@@ -93,19 +88,17 @@ struct eap_authenticator_t {
* AUTH payload, the client must verify that the server initiated mutual
* EAP authentication before it can trust the server.
*
- * @param this calling object
* @return TRUE, if no AUTH payload required, FALSE otherwise
*/
bool (*is_mutual) (eap_authenticator_t* this);
/**
- * @brief Initiate the EAP exchange.
+ * Initiate the EAP exchange.
*
* The server initiates EAP exchanges, so the client never calls
* this method. If initiate() returns NEED_MORE, the EAP authentication
* process started. In any case, a payload is created in "out".
*
- * @param this calling object
* @param type EAP method to use to authenticate client
* @param vendor EAP vendor identifier, if type is vendor specific, or 0
* @param out created initiaal EAP message to send
@@ -117,7 +110,7 @@ struct eap_authenticator_t {
u_int32_t vendor, eap_payload_t **out);
/**
- * @brief Process an EAP message.
+ * Process an EAP message.
*
* After receiving an EAP message "in", the peer/server processes
* the payload and creates a reply/subsequent request.
@@ -132,7 +125,6 @@ struct eap_authenticator_t {
* If a SUCCESS is returned (on any side), the EAP authentication was
* successful and the AUTH payload can be exchanged.
*
- * @param this calling object
* @param in received EAP message
* @param out created EAP message to send
* @return
@@ -145,13 +137,11 @@ struct eap_authenticator_t {
};
/**
- * @brief Creates an authenticator for AUTH_EAP.
+ * Creates an authenticator for AUTH_EAP.
*
* @param ike_sa associated ike_sa
* @return eap_authenticator_t object
- *
- * @ingroup authenticators
*/
eap_authenticator_t *eap_authenticator_create(ike_sa_t *ike_sa);
-#endif /* EAP_AUTHENTICATOR_H_ */
+#endif /* EAP_AUTHENTICATOR_H_ @} */
diff --git a/src/charon/sa/authenticators/psk_authenticator.c b/src/charon/sa/authenticators/psk_authenticator.c
index 6b76088bb..d003dc2c9 100644
--- a/src/charon/sa/authenticators/psk_authenticator.c
+++ b/src/charon/sa/authenticators/psk_authenticator.c
@@ -1,10 +1,3 @@
-/**
- * @file psk_authenticator.c
- *
- * @brief Implementation of psk_authenticator_t.
- *
- */
-
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -19,6 +12,8 @@
* 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.
+ *
+ * $Id: psk_authenticator.c 3589 2008-03-13 14:14:44Z martin $
*/
#include <string.h>
@@ -26,6 +21,7 @@
#include "psk_authenticator.h"
#include <daemon.h>
+#include <credentials/auth_info.h>
/**
* Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
@@ -105,39 +101,49 @@ chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce,
* Implementation of authenticator_t.verify.
*/
static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init,
- chunk_t my_nonce, auth_payload_t *auth_payload)
+ chunk_t my_nonce, auth_payload_t *auth_payload)
{
- status_t status;
- chunk_t auth_data, recv_auth_data, shared_key;
+ chunk_t auth_data, recv_auth_data;
identification_t *my_id, *other_id;
+ shared_key_t *shared_key;
+ enumerator_t *enumerator;
+ bool authenticated = FALSE;
+ int keys_found = 0;
my_id = this->ike_sa->get_my_id(this->ike_sa);
other_id = this->ike_sa->get_other_id(this->ike_sa);
- status = charon->credentials->get_shared_key(charon->credentials, my_id,
- other_id, &shared_key);
- if (status != SUCCESS)
+ enumerator = charon->credentials->create_shared_enumerator(
+ charon->credentials, SHARED_IKE, my_id, other_id);
+ while (!authenticated && enumerator->enumerate(enumerator, &shared_key, NULL, NULL))
{
- DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id);
- return status;
+ keys_found++;
+ auth_data = build_shared_key_signature(ike_sa_init, my_nonce,
+ shared_key->get_key(shared_key), other_id,
+ this->ike_sa->get_skp_verify(this->ike_sa),
+ this->ike_sa->get_prf(this->ike_sa));
+ recv_auth_data = auth_payload->get_data(auth_payload);
+ if (auth_data.len == recv_auth_data.len &&
+ memeq(auth_data.ptr, recv_auth_data.ptr, auth_data.len))
+ {
+ DBG1(DBG_IKE, "authentication of '%D' with %N successful",
+ other_id, auth_method_names, AUTH_PSK);
+ authenticated = TRUE;
+ }
+ chunk_free(&auth_data);
}
+ enumerator->destroy(enumerator);
- auth_data = build_shared_key_signature(ike_sa_init, my_nonce, shared_key,
- other_id, this->ike_sa->get_skp_verify(this->ike_sa),
- this->ike_sa->get_prf(this->ike_sa));
- chunk_free_randomized(&shared_key);
-
- recv_auth_data = auth_payload->get_data(auth_payload);
- if (auth_data.len != recv_auth_data.len ||
- !memeq(auth_data.ptr, recv_auth_data.ptr, auth_data.len))
+ if (!authenticated)
{
- DBG1(DBG_IKE, "PSK MAC verification failed");
- chunk_free(&auth_data);
+ if (keys_found == 0)
+ {
+ DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id);
+ return NOT_FOUND;
+ }
+ DBG1(DBG_IKE, "tried %d shared key%s for '%D' - '%D', but MAC mismatched",
+ keys_found, keys_found == 1 ? "" : "s", my_id, other_id);
return FAILED;
}
- chunk_free(&auth_data);
-
- DBG1(DBG_IKE, "authentication of '%D' with %N successful",
- other_id, auth_method_names, AUTH_PSK);
return SUCCESS;
}
@@ -147,28 +153,27 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init,
static status_t build(private_psk_authenticator_t *this, chunk_t ike_sa_init,
chunk_t other_nonce, auth_payload_t **auth_payload)
{
- chunk_t shared_key;
+ shared_key_t *shared_key;
chunk_t auth_data;
- status_t status;
identification_t *my_id, *other_id;
my_id = this->ike_sa->get_my_id(this->ike_sa);
other_id = this->ike_sa->get_other_id(this->ike_sa);
DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
my_id, auth_method_names, AUTH_PSK);
- status = charon->credentials->get_shared_key(charon->credentials, my_id,
- other_id, &shared_key);
- if (status != SUCCESS)
+ shared_key = charon->credentials->get_shared(charon->credentials, SHARED_IKE,
+ my_id, other_id);
+ if (shared_key == NULL)
{
DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id);
- return status;
+ return NOT_FOUND;
}
-
- auth_data = build_shared_key_signature(ike_sa_init, other_nonce, shared_key,
- my_id, this->ike_sa->get_skp_build(this->ike_sa),
- this->ike_sa->get_prf(this->ike_sa));
+ auth_data = build_shared_key_signature(ike_sa_init, other_nonce,
+ shared_key->get_key(shared_key), my_id,
+ this->ike_sa->get_skp_build(this->ike_sa),
+ this->ike_sa->get_prf(this->ike_sa));
+ shared_key->destroy(shared_key);
DBG2(DBG_IKE, "successfully created shared key MAC");
- chunk_free_randomized(&shared_key);
*auth_payload = auth_payload_create();
(*auth_payload)->set_auth_method(*auth_payload, AUTH_PSK);
(*auth_payload)->set_data(*auth_payload, auth_data);
diff --git a/src/charon/sa/authenticators/psk_authenticator.h b/src/charon/sa/authenticators/psk_authenticator.h
index c1c5bcaac..c7cb5a23c 100644
--- a/src/charon/sa/authenticators/psk_authenticator.h
+++ b/src/charon/sa/authenticators/psk_authenticator.h
@@ -1,10 +1,3 @@
-/**
- * @file psk_authenticator.h
- *
- * @brief Interface of psk_authenticator_t.
- *
- */
-
/*
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: psk_authenticator.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup psk_authenticator psk_authenticator
+ * @{ @ingroup authenticators
*/
#ifndef PSK_AUTHENTICATOR_H_
@@ -28,13 +28,7 @@ typedef struct psk_authenticator_t psk_authenticator_t;
#include <sa/authenticators/authenticator.h>
/**
- * @brief Implementation of the authenticator_t interface using AUTH_PSK.
- *
- * @b Constructors:
- * - psk_authenticator_create()
- * - authenticator_create() using auth_method AUTH_PSK
- *
- * @ingroup authenticators
+ * Implementation of the authenticator_t interface using AUTH_PSK.
*/
struct psk_authenticator_t {
@@ -45,13 +39,11 @@ struct psk_authenticator_t {
};
/**
- * @brief Creates an authenticator for AUTH_PSK.
+ * Creates an authenticator for AUTH_PSK.
*
* @param ike_sa associated ike_sa
* @return psk_authenticator_t object
- *
- * @ingroup authenticators
*/
psk_authenticator_t *psk_authenticator_create(ike_sa_t *ike_sa);
-#endif /* PSK_AUTHENTICATOR_H_ */
+#endif /* PSK_AUTHENTICATOR_H_ @} */
diff --git a/src/charon/sa/authenticators/pubkey_authenticator.c b/src/charon/sa/authenticators/pubkey_authenticator.c
new file mode 100644
index 000000000..2c02ca84c
--- /dev/null
+++ b/src/charon/sa/authenticators/pubkey_authenticator.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * 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.
+ *
+ * $Id: pubkey_authenticator.c 4054 2008-06-10 20:31:53Z andreas $
+ */
+
+#include <string.h>
+
+#include "pubkey_authenticator.h"
+
+#include <daemon.h>
+#include <credentials/auth_info.h>
+
+
+typedef struct private_pubkey_authenticator_t private_pubkey_authenticator_t;
+
+/**
+ * Private data of an pubkey_authenticator_t object.
+ */
+struct private_pubkey_authenticator_t {
+
+ /**
+ * Public authenticator_t interface.
+ */
+ pubkey_authenticator_t public;
+
+ /**
+ * Assigned IKE_SA
+ */
+ ike_sa_t *ike_sa;
+};
+
+/**
+ * Function implemented in psk_authenticator.c
+ */
+extern chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce,
+ identification_t *id, prf_t *prf);
+
+/**
+ * Implementation of authenticator_t.verify.
+ */
+static status_t verify(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t my_nonce, auth_payload_t *auth_payload)
+{
+ public_key_t *public;
+ auth_method_t auth_method;
+ chunk_t auth_data, octets;
+ identification_t *other_id;
+ prf_t *prf;
+ auth_info_t *auth, *current_auth;
+ enumerator_t *enumerator;
+ key_type_t key_type = KEY_ECDSA;
+ signature_scheme_t scheme;
+ status_t status = FAILED;
+
+ other_id = this->ike_sa->get_other_id(this->ike_sa);
+ auth_method = auth_payload->get_auth_method(auth_payload);
+ switch (auth_method)
+ {
+ case AUTH_RSA:
+ /* We are currently fixed to SHA1 hashes.
+ * TODO: allow other hash algorithms and note it in "auth" */
+ key_type = KEY_RSA;
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
+ break;
+ case AUTH_ECDSA_256:
+ scheme = SIGN_ECDSA_256;
+ break;
+ case AUTH_ECDSA_384:
+ scheme = SIGN_ECDSA_384;
+ break;
+ case AUTH_ECDSA_521:
+ scheme = SIGN_ECDSA_521;
+ break;
+ default:
+ return INVALID_ARG;
+ }
+ auth_data = auth_payload->get_data(auth_payload);
+ prf = this->ike_sa->get_prf(this->ike_sa);
+ prf->set_key(prf, this->ike_sa->get_skp_verify(this->ike_sa));
+ octets = build_tbs_octets(ike_sa_init, my_nonce, other_id, prf);
+
+ auth = this->ike_sa->get_other_auth(this->ike_sa);
+ enumerator = charon->credentials->create_public_enumerator(
+ charon->credentials, key_type, other_id, auth);
+ while (enumerator->enumerate(enumerator, &public, &current_auth))
+ {
+ if (public->verify(public, scheme, octets, auth_data))
+ {
+ DBG1(DBG_IKE, "authentication of '%D' with %N successful",
+ other_id, auth_method_names, auth_method);
+ status = SUCCESS;
+ auth->merge(auth, current_auth);
+ break;
+ }
+ else
+ {
+ DBG1(DBG_IKE, "signature validation failed, looking for another key");
+ }
+ }
+ enumerator->destroy(enumerator);
+ chunk_free(&octets);
+ return status;
+}
+
+/**
+ * Implementation of authenticator_t.build.
+ */
+static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t other_nonce, auth_payload_t **auth_payload)
+{
+ chunk_t octets, auth_data;
+ status_t status = FAILED;
+ private_key_t *private;
+ identification_t *my_id;
+ prf_t *prf;
+ auth_info_t *auth;
+ auth_method_t auth_method;
+ signature_scheme_t scheme;
+
+ my_id = this->ike_sa->get_my_id(this->ike_sa);
+ auth = this->ike_sa->get_my_auth(this->ike_sa);
+ private = charon->credentials->get_private(charon->credentials, KEY_ANY,
+ my_id, auth);
+ if (private == NULL)
+ {
+ DBG1(DBG_IKE, "no private key found for '%D'", my_id);
+ return NOT_FOUND;
+ }
+
+ switch (private->get_type(private))
+ {
+ case KEY_RSA:
+ /* we currently use always SHA1 for signatures,
+ * TODO: support other hashes depending on configuration/auth */
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
+ auth_method = AUTH_RSA;
+ break;
+ case KEY_ECDSA:
+ /* we try to deduct the signature scheme from the keysize */
+ switch (private->get_keysize(private))
+ {
+ case 32:
+ scheme = SIGN_ECDSA_256;
+ auth_method = AUTH_ECDSA_256;
+ break;
+ case 48:
+ scheme = SIGN_ECDSA_384;
+ auth_method = AUTH_ECDSA_384;
+ break;
+ case 66:
+ scheme = SIGN_ECDSA_521;
+ auth_method = AUTH_ECDSA_521;
+ break;
+ default:
+ DBG1(DBG_IKE, "%d bit ECDSA private key size not supported",
+ private->get_keysize(private));
+ return status;
+ }
+ break;
+ default:
+ DBG1(DBG_IKE, "private key of type %N not supported",
+ key_type_names, private->get_type(private));
+ return status;
+ }
+ prf = this->ike_sa->get_prf(this->ike_sa);
+ prf->set_key(prf, this->ike_sa->get_skp_build(this->ike_sa));
+ octets = build_tbs_octets(ike_sa_init, other_nonce, my_id, prf);
+
+ if (private->sign(private, scheme, octets, &auth_data))
+ {
+ auth_payload_t *payload = auth_payload_create();
+ payload->set_auth_method(payload, auth_method);
+ payload->set_data(payload, auth_data);
+ *auth_payload = payload;
+ chunk_free(&auth_data);
+ status = SUCCESS;
+ }
+ DBG1(DBG_IKE, "authentication of '%D' (myself) with %N %s", my_id,
+ auth_method_names, auth_method,
+ (status == SUCCESS)? "successful":"failed");
+ chunk_free(&octets);
+ private->destroy(private);
+
+ return status;
+}
+
+/**
+ * Implementation of authenticator_t.destroy.
+ */
+static void destroy(private_pubkey_authenticator_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+pubkey_authenticator_t *pubkey_authenticator_create(ike_sa_t *ike_sa)
+{
+ private_pubkey_authenticator_t *this = malloc_thing(private_pubkey_authenticator_t);
+
+ /* public functions */
+ this->public.authenticator_interface.verify = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t*))verify;
+ this->public.authenticator_interface.build = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t**))build;
+ this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/authenticators/rsa_authenticator.h b/src/charon/sa/authenticators/pubkey_authenticator.h
index cc5cc0150..038d8b1d2 100644
--- a/src/charon/sa/authenticators/rsa_authenticator.h
+++ b/src/charon/sa/authenticators/pubkey_authenticator.h
@@ -1,11 +1,5 @@
-/**
- * @file rsa_authenticator.h
- *
- * @brief Interface of rsa_authenticator_t.
- *
- */
-
/*
+ * Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -18,25 +12,26 @@
* 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.
+ *
+ * $Id: pubkey_authenticator.h 4051 2008-06-10 09:08:27Z tobias $
*/
-#ifndef RSA_AUTHENTICATOR_H_
-#define RSA_AUTHENTICATOR_H_
+/**
+ * @defgroup pubkey_authenticator pubkey_authenticator
+ * @{ @ingroup authenticators
+ */
+
+#ifndef PUBKEY_AUTHENTICATOR_H_
+#define PUBKEY_AUTHENTICATOR_H_
-typedef struct rsa_authenticator_t rsa_authenticator_t;
+typedef struct pubkey_authenticator_t pubkey_authenticator_t;
#include <sa/authenticators/authenticator.h>
/**
- * @brief Implementation of the authenticator_t interface using AUTH_RSA.
- *
- * @b Constructors:
- * - rsa_authenticator_create()
- * - authenticator_create() using auth_method AUTH_RSA
- *
- * @ingroup authenticators
+ * Implementation of the authenticator_t interface using AUTH_PUBKEY.
*/
-struct rsa_authenticator_t {
+struct pubkey_authenticator_t {
/**
* Implemented authenticator_t interface.
@@ -45,13 +40,11 @@ struct rsa_authenticator_t {
};
/**
- * @brief Creates an authenticator for AUTH_RSA.
+ * Creates an authenticator for AUTH_PUBKEY.
*
* @param ike_sa associated ike_sa
- * @return rsa_authenticator_t object
- *
- * @ingroup authenticators
+ * @return pubkey_authenticator_t object
*/
-rsa_authenticator_t *rsa_authenticator_create(ike_sa_t *ike_sa);
+pubkey_authenticator_t *pubkey_authenticator_create(ike_sa_t *ike_sa);
-#endif /* RSA_AUTHENTICATOR_H_ */
+#endif /* PUBKEY_AUTHENTICATOR_H_ @} */
diff --git a/src/charon/sa/authenticators/rsa_authenticator.c b/src/charon/sa/authenticators/rsa_authenticator.c
deleted file mode 100644
index ba0fad1e3..000000000
--- a/src/charon/sa/authenticators/rsa_authenticator.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/**
- * @file rsa_authenticator.c
- *
- * @brief Implementation of rsa_authenticator_t.
- *
- */
-
-/*
- * Copyright (C) 2005-2006 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include <string.h>
-
-#include "rsa_authenticator.h"
-
-#include <daemon.h>
-
-
-typedef struct private_rsa_authenticator_t private_rsa_authenticator_t;
-
-/**
- * Private data of an rsa_authenticator_t object.
- */
-struct private_rsa_authenticator_t {
-
- /**
- * Public authenticator_t interface.
- */
- rsa_authenticator_t public;
-
- /**
- * Assigned IKE_SA
- */
- ike_sa_t *ike_sa;
-};
-
-/**
- * Function implemented in psk_authenticator.c
- */
-extern chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce,
- identification_t *id, prf_t *prf);
-
-/**
- * Implementation of authenticator_t.verify.
- */
-static status_t verify(private_rsa_authenticator_t *this, chunk_t ike_sa_init,
- chunk_t my_nonce, auth_payload_t *auth_payload)
-{
- status_t status;
- chunk_t auth_data, octets;
- identification_t *other_id;
- ca_info_t *issuer;
- prf_t *prf;
-
- other_id = this->ike_sa->get_other_id(this->ike_sa);
-
- if (auth_payload->get_auth_method(auth_payload) != AUTH_RSA)
- {
- return INVALID_ARG;
- }
- auth_data = auth_payload->get_data(auth_payload);
- prf = this->ike_sa->get_prf(this->ike_sa);
- prf->set_key(prf, this->ike_sa->get_skp_verify(this->ike_sa));
- octets = build_tbs_octets(ike_sa_init, my_nonce, other_id, prf);
- status = charon->credentials->verify_signature(charon->credentials,
- octets, auth_data, other_id, &issuer);
- chunk_free(&octets);
-
- if (status == SUCCESS)
- {
- this->ike_sa->set_other_ca(this->ike_sa, issuer);
- DBG1(DBG_IKE, "authentication of '%D' with %N successful",
- other_id, auth_method_names, AUTH_RSA);
- }
- return status;
-}
-
-/**
- * Implementation of authenticator_t.build.
- */
-static status_t build(private_rsa_authenticator_t *this, chunk_t ike_sa_init,
- chunk_t other_nonce, auth_payload_t **auth_payload)
-{
- chunk_t octets, auth_data;
- status_t status;
- rsa_public_key_t *my_pubkey;
- identification_t *my_id;
- prf_t *prf;
-
- my_id = this->ike_sa->get_my_id(this->ike_sa);
- DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
- my_id, auth_method_names, AUTH_RSA);
- DBG2(DBG_IKE, "looking for RSA public key belonging to '%D'...", my_id);
-
- my_pubkey = charon->credentials->get_rsa_public_key(charon->credentials, my_id);
- if (my_pubkey == NULL)
- {
- DBG1(DBG_IKE, "no RSA public key found for '%D'", my_id);
- return NOT_FOUND;
- }
- DBG2(DBG_IKE, " matching RSA public key found");
-
- prf = this->ike_sa->get_prf(this->ike_sa);
- prf->set_key(prf, this->ike_sa->get_skp_build(this->ike_sa));
- octets = build_tbs_octets(ike_sa_init, other_nonce, my_id, prf);
- status = charon->credentials->rsa_signature(charon->credentials,
- my_pubkey, HASH_SHA1, octets, &auth_data);
- chunk_free(&octets);
-
- if (status != SUCCESS)
- {
- DBG1(DBG_IKE, "building RSA signature with SHA-1 hash failed");
- return status;
- }
- DBG2(DBG_IKE, "successfully signed with RSA private key");
-
- *auth_payload = auth_payload_create();
- (*auth_payload)->set_auth_method(*auth_payload, AUTH_RSA);
- (*auth_payload)->set_data(*auth_payload, auth_data);
- chunk_free(&auth_data);
- return SUCCESS;
-}
-
-/**
- * Implementation of authenticator_t.destroy.
- */
-static void destroy(private_rsa_authenticator_t *this)
-{
- free(this);
-}
-
-/*
- * Described in header.
- */
-rsa_authenticator_t *rsa_authenticator_create(ike_sa_t *ike_sa)
-{
- private_rsa_authenticator_t *this = malloc_thing(private_rsa_authenticator_t);
-
- /* public functions */
- this->public.authenticator_interface.verify = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t*))verify;
- this->public.authenticator_interface.build = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t**))build;
- this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy;
-
- /* private data */
- this->ike_sa = ike_sa;
-
- return &this->public;
-}
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c
index b6c71a8b5..2a6b6f67c 100644
--- a/src/charon/sa/child_sa.c
+++ b/src/charon/sa/child_sa.c
@@ -1,13 +1,7 @@
-/**
- * @file child_sa.c
- *
- * @brief Implementation of child_sa_t.
- *
- */
-
/*
+ * Copyright (C) 2006-2008 Tobias Brunner
* Copyright (C) 2005-2007 Martin Willi
- * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
@@ -20,6 +14,8 @@
* 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.
+ *
+ * $Id: child_sa.c 3920 2008-05-08 16:19:11Z tobias $
*/
#define _GNU_SOURCE
@@ -75,6 +71,8 @@ struct private_child_sa_t {
identification_t *id;
/** actual used SPI, 0 if unused */
u_int32_t spi;
+ /** Compression Parameter Index (CPI) used, 0 if unused */
+ u_int16_t cpi;
} me, other;
/**
@@ -115,12 +113,22 @@ struct private_child_sa_t {
/**
* encryption algorithm used for this SA
*/
- algorithm_t encryption;
+ u_int16_t enc_alg;
+
+ /**
+ * key size of enc_alg
+ */
+ u_int16_t enc_size;
/**
* integrity protection algorithm used for this SA
*/
- algorithm_t integrity;
+ u_int16_t int_alg;
+
+ /**
+ * key size of int_alg
+ */
+ u_int16_t int_size;
/**
* time, on which SA was installed
@@ -143,6 +151,16 @@ struct private_child_sa_t {
bool encap;
/**
+ * Specifies the IPComp transform used (IPCOMP_NONE if disabled)
+ */
+ ipcomp_transform_t ipcomp;
+
+ /**
+ * TRUE if we allocated (or tried to allocate) a CPI
+ */
+ bool cpi_allocated;
+
+ /**
* mode this SA uses, tunnel/transport
*/
mode_t mode;
@@ -251,10 +269,10 @@ static void get_stats(private_child_sa_t *this, mode_t *mode,
iterator->destroy(iterator);
*mode = this->mode;
- *encr_algo = this->encryption.algorithm;
- *encr_len = this->encryption.key_size;
- *int_algo = this->integrity.algorithm;
- *int_len = this->integrity.key_size;
+ *encr_algo = this->enc_alg;
+ *encr_len = this->enc_size;
+ *int_algo = this->int_alg;
+ *int_len = this->int_size;
*rekey = this->rekey_time;
*use_in = in;
*use_out = out;
@@ -498,10 +516,7 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
static status_t install(private_child_sa_t *this, proposal_t *proposal,
mode_t mode, prf_plus_t *prf_plus, bool mine)
{
- u_int32_t spi, soft, hard;;
- algorithm_t *enc_algo, *int_algo;
- algorithm_t enc_algo_none = {ENCR_UNDEFINED, 0};
- algorithm_t int_algo_none = {AUTH_UNDEFINED, 0};
+ u_int32_t spi, soft, hard;
host_t *src;
host_t *dst;
status_t status;
@@ -549,43 +564,43 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
protocol_id_names, this->protocol);
/* select encryption algo */
- if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_algo))
+ if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
+ &this->enc_alg, &this->enc_size))
{
- DBG2(DBG_CHD, " using %N for encryption",
- encryption_algorithm_names, enc_algo->algorithm);
- }
- else
- {
- enc_algo = &enc_algo_none;
+ DBG2(DBG_CHD, " using %N for encryption",
+ encryption_algorithm_names, this->enc_alg);
}
/* select integrity algo */
- if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_algo))
+ if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
+ &this->int_alg, &this->int_size))
{
DBG2(DBG_CHD, " using %N for integrity",
- integrity_algorithm_names, int_algo->algorithm);
- }
- else
- {
- int_algo = &int_algo_none;
+ integrity_algorithm_names, this->int_alg);
}
-
soft = this->config->get_lifetime(this->config, TRUE);
hard = this->config->get_lifetime(this->config, FALSE);
/* send SA down to the kernel */
DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
- status = charon->kernel_interface->add_sa(charon->kernel_interface,
- src, dst, spi, this->protocol,
- this->reqid, mine ? soft : 0,
- hard, enc_algo, int_algo,
- prf_plus, mode, this->encap, mine);
- this->encryption = *enc_algo;
- this->integrity = *int_algo;
+ if (this->ipcomp != IPCOMP_NONE)
+ {
+ /* we install an additional IPComp SA */
+ u_int32_t cpi = htonl(ntohs(mine ? this->me.cpi : this->other.cpi));
+ status = charon->kernel_interface->add_sa(charon->kernel_interface,
+ src, dst, cpi, IPPROTO_COMP, this->reqid, 0, 0,
+ ENCR_UNDEFINED, 0, AUTH_UNDEFINED, 0, NULL, mode,
+ this->ipcomp, FALSE, mine);
+ }
+
+ status = charon->kernel_interface->add_sa(charon->kernel_interface,
+ src, dst, spi, this->protocol, this->reqid, mine ? soft : 0, hard,
+ this->enc_alg, this->enc_size, this->int_alg, this->int_size,
+ prf_plus, mode, IPCOMP_NONE, this->encap, mine);
+
this->install_time = time(NULL);
this->rekey_time = this->install_time + soft;
-
return status;
}
@@ -686,15 +701,15 @@ static status_t add_policies(private_child_sa_t *this,
/* install 3 policies: out, in and forward */
status = charon->kernel_interface->add_policy(charon->kernel_interface,
this->me.addr, this->other.addr, my_ts, other_ts, POLICY_OUT,
- this->protocol, this->reqid, high_prio, mode);
+ this->protocol, this->reqid, high_prio, mode, this->ipcomp);
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
this->other.addr, this->me.addr, other_ts, my_ts, POLICY_IN,
- this->protocol, this->reqid, high_prio, mode);
+ this->protocol, this->reqid, high_prio, mode, this->ipcomp);
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
this->other.addr, this->me.addr, other_ts, my_ts, POLICY_FWD,
- this->protocol, this->reqid, high_prio, mode);
+ this->protocol, this->reqid, high_prio, mode, this->ipcomp);
if (status != SUCCESS)
{
@@ -795,10 +810,20 @@ static status_t update_hosts(private_child_sa_t *this,
this->encap = encap;
- /* update our (initator) SAs */
+ if (this->ipcomp != IPCOMP_NONE)
+ {
+ /* update our (initator) IPComp SA */
+ charon->kernel_interface->update_sa(charon->kernel_interface, htonl(ntohs(this->me.cpi)),
+ IPPROTO_COMP, this->other.addr, this->me.addr, other, me, FALSE);
+ /* update his (responder) IPComp SA */
+ charon->kernel_interface->update_sa(charon->kernel_interface, htonl(ntohs(this->other.cpi)),
+ IPPROTO_COMP, this->me.addr, this->other.addr, me, other, FALSE);
+ }
+
+ /* update our (initator) SA */
charon->kernel_interface->update_sa(charon->kernel_interface, this->me.spi,
this->protocol, this->other.addr, this->me.addr, other, me, encap);
- /* update his (responder) SAs */
+ /* update his (responder) SA */
charon->kernel_interface->update_sa(charon->kernel_interface, this->other.spi,
this->protocol, this->me.addr, this->other.addr, me, other, encap);
@@ -846,13 +871,13 @@ static status_t update_hosts(private_child_sa_t *this,
/* reinstall updated policies */
charon->kernel_interface->add_policy(charon->kernel_interface,
me, other, policy->my_ts, policy->other_ts, POLICY_OUT,
- this->protocol, this->reqid, TRUE, this->mode);
+ this->protocol, this->reqid, TRUE, this->mode, this->ipcomp);
charon->kernel_interface->add_policy(charon->kernel_interface,
other, me, policy->other_ts, policy->my_ts, POLICY_IN,
- this->protocol, this->reqid, TRUE, this->mode);
+ this->protocol, this->reqid, TRUE, this->mode, this->ipcomp);
charon->kernel_interface->add_policy(charon->kernel_interface,
other, me, policy->other_ts, policy->my_ts, POLICY_FWD,
- this->protocol, this->reqid, TRUE, this->mode);
+ this->protocol, this->reqid, TRUE, this->mode, this->ipcomp);
}
iterator->destroy(iterator);
}
@@ -884,6 +909,30 @@ static void set_virtual_ip(private_child_sa_t *this, host_t *ip)
}
/**
+ * Implementation of child_sa_t.activate_ipcomp.
+ */
+static void activate_ipcomp(private_child_sa_t *this, ipcomp_transform_t ipcomp,
+ u_int16_t other_cpi)
+{
+ this->ipcomp = ipcomp;
+ this->other.cpi = other_cpi;
+}
+
+/**
+ * Implementation of child_sa_t.get_my_cpi.
+ */
+static u_int16_t get_my_cpi(private_child_sa_t *this)
+{
+ if (!this->cpi_allocated)
+ {
+ charon->kernel_interface->get_cpi(charon->kernel_interface,
+ this->other.addr, this->me.addr, this->reqid, &this->me.cpi);
+ this->cpi_allocated = TRUE;
+ }
+ return this->me.cpi;
+}
+
+/**
* Implementation of child_sa_t.destroy.
*/
static void destroy(private_child_sa_t *this)
@@ -916,6 +965,16 @@ static void destroy(private_child_sa_t *this)
charon->kernel_interface->del_sa(charon->kernel_interface,
this->other.addr, this->other.spi, this->protocol);
}
+ if (this->me.cpi)
+ {
+ charon->kernel_interface->del_sa(charon->kernel_interface,
+ this->other.addr, htonl(ntohs(this->me.cpi)), IPPROTO_COMP);
+ }
+ if (this->other.cpi)
+ {
+ charon->kernel_interface->del_sa(charon->kernel_interface,
+ this->other.addr, htonl(ntohs(this->other.cpi)), IPPROTO_COMP);
+ }
/* delete all policies in the kernel */
while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS)
@@ -976,6 +1035,8 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state;
this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state;
this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config;
+ this->public.activate_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t,u_int16_t))activate_ipcomp;
+ this->public.get_my_cpi = (u_int16_t(*)(child_sa_t*))get_my_cpi;
this->public.set_virtual_ip = (void(*)(child_sa_t*,host_t*))set_virtual_ip;
this->public.destroy = (void(*)(child_sa_t*))destroy;
@@ -985,17 +1046,21 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->me.id = my_id->clone(my_id);
this->other.id = other_id->clone(other_id);
this->me.spi = 0;
+ this->me.cpi = 0;
this->other.spi = 0;
+ this->other.cpi = 0;
this->alloc_ah_spi = 0;
this->alloc_esp_spi = 0;
this->encap = encap;
+ this->cpi_allocated = FALSE;
+ this->ipcomp = IPCOMP_NONE;
this->state = CHILD_CREATED;
/* reuse old reqid if we are rekeying an existing CHILD_SA */
this->reqid = rekey ? rekey : ++reqid;
- this->encryption.algorithm = ENCR_UNDEFINED;
- this->encryption.key_size = 0;
- this->integrity.algorithm = AUTH_UNDEFINED;
- this->encryption.key_size = 0;
+ this->enc_alg = ENCR_UNDEFINED;
+ this->enc_size = 0;
+ this->int_alg = AUTH_UNDEFINED;
+ this->int_size = 0;
this->policies = linked_list_create();
this->my_ts = linked_list_create();
this->other_ts = linked_list_create();
diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h
index b801dd012..5bd66acad 100644
--- a/src/charon/sa/child_sa.h
+++ b/src/charon/sa/child_sa.h
@@ -1,13 +1,7 @@
-/**
- * @file child_sa.h
- *
- * @brief Interface of child_sa_t.
- *
- */
-
/*
+ * Copyright (C) 2006-2008 Tobias Brunner
* Copyright (C) 2006-2007 Martin Willi
- * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2006 Daniel Roethlisberger
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -19,8 +13,14 @@
* 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.
+ *
+ * $Id: child_sa.h 3920 2008-05-08 16:19:11Z tobias $
*/
+/**
+ * @defgroup child_sa child_sa
+ * @{ @ingroup sa
+ */
#ifndef CHILD_SA_H_
#define CHILD_SA_H_
@@ -35,7 +35,7 @@ typedef struct child_sa_t child_sa_t;
#include <config/child_cfg.h>
/**
- * @brief States of a CHILD_SA
+ * States of a CHILD_SA
*/
enum child_sa_state_t {
@@ -71,7 +71,7 @@ enum child_sa_state_t {
extern enum_name_t *child_sa_state_names;
/**
- * @brief Represents an IPsec SAs between two hosts.
+ * Represents an IPsec SAs between two hosts.
*
* A child_sa_t contains two SAs. SAs for both
* directions are managed in one child_sa_t object. Both
@@ -86,57 +86,47 @@ extern enum_name_t *child_sa_state_names;
* - A calls child_sa_t.update to update the already allocated SPIs with the chosen proposal
*
* Once SAs are set up, policies can be added using add_policies.
- *
- *
- * @b Constructors:
- * - child_sa_create()
- *
- * @ingroup sa
*/
struct child_sa_t {
/**
- * @brief Get the name of the config this CHILD_SA uses.
+ * Get the name of the config this CHILD_SA uses.
*
- * @param this calling object
- * @return name
+ * @return name
*/
char* (*get_name) (child_sa_t *this);
/**
- * @brief Get the reqid of the CHILD SA.
+ * Get the reqid of the CHILD SA.
*
* Every CHILD_SA has a reqid. The kernel uses this ID to
* identify it.
*
- * @param this calling object
* @return reqid of the CHILD SA
*/
u_int32_t (*get_reqid)(child_sa_t *this);
/**
- * @brief Get the SPI of this CHILD_SA.
+ * Get the SPI of this CHILD_SA.
*
* Set the boolean parameter inbound to TRUE to
* get the SPI for which we receive packets, use
* FALSE to get those we use for sending packets.
*
- * @param this calling object
* @param inbound TRUE to get inbound SPI, FALSE for outbound.
* @return spi of the CHILD SA
*/
u_int32_t (*get_spi) (child_sa_t *this, bool inbound);
/**
- * @brief Get the protocol which this CHILD_SA uses to protect traffic.
+ * Get the protocol which this CHILD_SA uses to protect traffic.
*
- * @param this calling object
* @return AH | ESP
*/
protocol_id_t (*get_protocol) (child_sa_t *this);
/**
- * @brief Get info and statistics about this CHILD_SA.
+ * Get info and statistics about this CHILD_SA.
*
* @param mode mode this IKE_SA uses
* @param encr_algo encryption algorithm used by this CHILD_SA.
@@ -155,7 +145,7 @@ struct child_sa_t {
u_int32_t *use_fwd);
/**
- * @brief Allocate SPIs for given proposals.
+ * Allocate SPIs for given proposals.
*
* Since the kernel manages SPIs for us, we need
* to allocate them. If a proposal contains more
@@ -163,15 +153,13 @@ struct child_sa_t {
* allocated. SPIs are stored internally and written
* back to the proposal.
*
- * @param this calling object
* @param proposals list of proposals for which SPIs are allocated
*/
status_t (*alloc)(child_sa_t *this, linked_list_t* proposals);
/**
- * @brief Install the kernel SAs for a proposal, without previous SPI allocation.
+ * Install the kernel SAs for a proposal, without previous SPI allocation.
*
- * @param this calling object
* @param proposal proposal for which SPIs are allocated
* @param mode mode for the CHILD_SA
* @param prf_plus key material to use for key derivation
@@ -181,11 +169,10 @@ struct child_sa_t {
prf_plus_t *prf_plus);
/**
- * @brief Install the kernel SAs for a proposal, after SPIs have been allocated.
+ * Install the kernel SAs for a proposal, after SPIs have been allocated.
*
* Updates an SA, for which SPIs are already allocated via alloc().
*
- * @param this calling object
* @param proposal proposal for which SPIs are allocated
* @param mode mode for the CHILD_SA
* @param prf_plus key material to use for key derivation
@@ -195,11 +182,10 @@ struct child_sa_t {
prf_plus_t *prf_plus);
/**
- * @brief Update the hosts in the kernel SAs and policies.
+ * Update the hosts in the kernel SAs and policies.
*
* The CHILD must be INSTALLED to do this update.
*
- * @param this calling object
* @param me the new local host
* @param other the new remote host
* @param TRUE to use UDP encapsulation for NAT traversal
@@ -209,12 +195,11 @@ struct child_sa_t {
bool encap);
/**
- * @brief Install the policies using some traffic selectors.
+ * Install the policies using some traffic selectors.
*
* Supplied lists of traffic_selector_t's specify the policies
* to use for this child sa.
*
- * @param this calling object
* @param my_ts traffic selectors for local site
* @param other_ts traffic selectors for remote site
* @param mode mode for the SA: tunnel/transport
@@ -224,18 +209,16 @@ struct child_sa_t {
linked_list_t *other_ts_list, mode_t mode);
/**
- * @brief Get the traffic selectors of added policies of local host.
+ * Get the traffic selectors of added policies of local host.
*
- * @param this calling object
* @param local TRUE for own traffic selectors, FALSE for remote
* @return list of traffic selectors
*/
linked_list_t* (*get_traffic_selectors) (child_sa_t *this, bool local);
/**
- * @brief Get the time of this child_sa_t's last use (i.e. last use of any of its policies)
+ * Get the time of this child_sa_t's last use (i.e. last use of any of its policies)
*
- * @param this calling object
* @param inbound query for in- or outbound usage
* @param use_time the time
* @return SUCCESS or FAILED
@@ -243,48 +226,58 @@ struct child_sa_t {
status_t (*get_use_time) (child_sa_t *this, bool inbound, time_t *use_time);
/**
- * @brief Get the state of the CHILD_SA.
- *
- * @param this calling object
+ * Get the state of the CHILD_SA.
*/
child_sa_state_t (*get_state) (child_sa_t *this);
/**
- * @brief Set the state of the CHILD_SA.
+ * Set the state of the CHILD_SA.
*
- * @param this calling object
+ * @param state state to set on CHILD_SA
*/
void (*set_state) (child_sa_t *this, child_sa_state_t state);
/**
- * @brief Get the config used to set up this child sa.
+ * Get the config used to set up this child sa.
*
- * @param this calling object
* @return child_cfg
*/
child_cfg_t* (*get_config) (child_sa_t *this);
/**
- * @brief Set the virtual IP used received from IRAS.
+ * Set the virtual IP used received from IRAS.
*
* To allow proper setup of firewall rules, the virtual IP is required
* for filtering.
*
- * @param this calling object
* @param ip own virtual IP
*/
void (*set_virtual_ip) (child_sa_t *this, host_t *ip);
/**
- * @brief Destroys a child_sa.
- *
- * @param this calling object
+ * Activate IPComp by setting the transform ID and CPI values.
+ *
+ * @param ipcomp the IPComp transform to use
+ * @param other_cpi other Compression Parameter Index
+ */
+ void (*activate_ipcomp) (child_sa_t *this, ipcomp_transform_t ipcomp,
+ u_int16_t other_cpi);
+
+ /**
+ * Returns the Compression Parameter Index (CPI) allocated from the kernel.
+ *
+ * @return allocated CPI
+ */
+ u_int16_t (*get_my_cpi) (child_sa_t *this);
+
+ /**
+ * Destroys a child_sa.
*/
void (*destroy) (child_sa_t *this);
};
/**
- * @brief Constructor to create a new child_sa_t.
+ * Constructor to create a new child_sa_t.
*
* @param me own address
* @param other remote address
@@ -294,11 +287,9 @@ struct child_sa_t {
* @param reqid reqid of old CHILD_SA when rekeying, 0 otherwise
* @param encap TRUE to enable UDP encapsulation (NAT traversal)
* @return child_sa_t object
- *
- * @ingroup sa
*/
child_sa_t * child_sa_create(host_t *me, host_t *other,
identification_t *my_id, identification_t* other_id,
child_cfg_t *config, u_int32_t reqid, bool encap);
-#endif /*CHILD_SA_H_*/
+#endif /*CHILD_SA_H_ @} */
diff --git a/src/charon/sa/connect_manager.c b/src/charon/sa/connect_manager.c
index 06755fa9c..19ceea666 100644
--- a/src/charon/sa/connect_manager.c
+++ b/src/charon/sa/connect_manager.c
@@ -1,12 +1,5 @@
-/**
- * @file connect_manager.c
- *
- * @brief Implementation of connect_manager_t.
- *
- */
-
/*
- * Copyright (C) 2007 Tobias Brunner
+ * Copyright (C) 2007-2008 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -18,6 +11,8 @@
* 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.
+ *
+ * $Id: connect_manager.c 3792 2008-04-10 12:51:04Z tobias $
*/
#include "connect_manager.h"
@@ -34,13 +29,20 @@
#include <encoding/payloads/endpoint_notify.h>
/* base timeout
- * the sending interval is P2P_INTERVAL * active checklists (N)
- * retransmission timeout is P2P_INTERVAL * N * checks in waiting state (NW) */
-#define P2P_INTERVAL 20 /* ms */
-/* min retransmission timeout (RTO is P2P_INTERVAL * N * checks in waiting state) */
-#define P2P_RTO_MIN 100 /* ms */
-/* max number of retransmissions (+ the initial check) */
-#define P2P_MAX_RETRANS 2
+ * the check interval is ME_INTERVAL */
+#define ME_INTERVAL 25 /* ms */
+/* retransmission timeout is first ME_INTERVAL for ME_BOOST retransmissions
+ * then gets reduced to ME_INTERVAL * ME_RETRANS_BASE ^ (sent retransmissions - ME_BOOST). */
+/* number of initial retransmissions sent in short interval */
+#define ME_BOOST 2
+/* base for retransmissions */
+#define ME_RETRANS_BASE 1.8
+/* max number of retransmissions */
+#define ME_MAX_RETRANS 13
+
+/* time to wait before the initiator finishes the connectivity checks after
+ * the first check has succeeded */
+#define ME_WAIT_TO_FINISH 1000 /* ms */
typedef struct private_connect_manager_t private_connect_manager_t;
@@ -70,7 +72,7 @@ struct private_connect_manager_t {
linked_list_t *initiated;
/**
- * Linked list with checklists (hash table with session ID as key would be better).
+ * Linked list with checklists (hash table with connect ID as key would be better).
*/
linked_list_t *checklists;
};
@@ -180,8 +182,8 @@ struct check_list_t {
linked_list_t *endpoints;
} responder;
- /** session id */
- chunk_t session_id;
+ /** connect id */
+ chunk_t connect_id;
/** list of endpoint pairs */
linked_list_t *pairs;
@@ -195,6 +197,12 @@ struct check_list_t {
/** TRUE if this is the initiator */
bool is_initiator;
+ /** TRUE if the initiator is finishing the checks */
+ bool is_finishing;
+
+ /** the current sender job */
+ job_t *sender;
+
};
/**
@@ -205,7 +213,7 @@ static void check_list_destroy(check_list_t *this)
DESTROY_IF(this->initiator.id);
DESTROY_IF(this->responder.id);
- chunk_free(&this->session_id);
+ chunk_free(&this->connect_id);
chunk_free(&this->initiator.key);
chunk_free(&this->responder.key);
@@ -223,12 +231,12 @@ static void check_list_destroy(check_list_t *this)
* Creates a new checklist
*/
static check_list_t *check_list_create(identification_t *initiator, identification_t *responder,
- chunk_t session_id, chunk_t initiator_key, linked_list_t *initiator_endpoints,
+ chunk_t connect_id, chunk_t initiator_key, linked_list_t *initiator_endpoints,
bool is_initiator)
{
check_list_t *this = malloc_thing(check_list_t);
- this->session_id = chunk_clone(session_id);
+ this->connect_id = chunk_clone(connect_id);
this->initiator.id = initiator->clone(initiator);
this->initiator.key = chunk_clone(initiator_key);
@@ -242,43 +250,7 @@ static check_list_t *check_list_create(identification_t *initiator, identificati
this->triggered = linked_list_create();
this->state = CHECK_NONE;
this->is_initiator = is_initiator;
-
- return this;
-}
-
-
-typedef struct waiting_sa_t waiting_sa_t;
-
-/**
- * For an initiator, the data stored about a waiting mediated sa
- */
-struct waiting_sa_t {
- /** ike sa id */
- ike_sa_id_t *ike_sa_id;
-
- /** list of child_cfg_t */
- linked_list_t *childs;
-};
-
-/**
- * Destroys a queued mediated sa
- */
-static void waiting_sa_destroy(waiting_sa_t *this)
-{
- DESTROY_IF(this->ike_sa_id);
- this->childs->destroy_offset(this->childs, offsetof(child_cfg_t, destroy));
- free(this);
-}
-
-/**
- * Creates a new mediated sa object
- */
-static waiting_sa_t *waiting_sa_create(ike_sa_id_t *ike_sa_id)
-{
- waiting_sa_t *this = malloc_thing(waiting_sa_t);
-
- this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
- this->childs = linked_list_create();
+ this->is_finishing = FALSE;
return this;
}
@@ -306,7 +278,7 @@ static void initiated_destroy(initiated_t *this)
{
DESTROY_IF(this->id);
DESTROY_IF(this->peer_id);
- this->mediated->destroy_function(this->mediated, (void*)waiting_sa_destroy);
+ this->mediated->destroy_offset(this->mediated, offsetof(ike_sa_id_t, destroy));
free(this);
}
@@ -340,8 +312,8 @@ struct check_t {
/** destination of the connectivity check */
host_t *dst;
- /** session id */
- chunk_t session_id;
+ /** connect id */
+ chunk_t connect_id;
/** endpoint */
endpoint_notify_t *endpoint;
@@ -349,8 +321,8 @@ struct check_t {
/** raw endpoint payload (to verify the signature) */
chunk_t endpoint_raw;
- /** cookie */
- chunk_t cookie;
+ /** connect auth */
+ chunk_t auth;
};
/**
@@ -358,9 +330,11 @@ struct check_t {
*/
static void check_destroy(check_t *this)
{
- chunk_free(&this->session_id);
+ chunk_free(&this->connect_id);
chunk_free(&this->endpoint_raw);
- chunk_free(&this->cookie);
+ chunk_free(&this->auth);
+ DESTROY_IF(this->src);
+ DESTROY_IF(this->dst);
DESTROY_IF(this->endpoint);
free(this);
}
@@ -372,9 +346,11 @@ static check_t *check_create()
{
check_t *this = malloc_thing(check_t);
- this->session_id = chunk_empty;
- this->cookie = chunk_empty;
+ this->connect_id = chunk_empty;
+ this->auth = chunk_empty;
this->endpoint_raw = chunk_empty;
+ this->src = NULL;
+ this->dst = NULL;
this->endpoint = NULL;
this->mid = 0;
@@ -382,76 +358,52 @@ static check_t *check_create()
return this;
}
-typedef struct sender_data_t sender_data_t;
+typedef struct callback_data_t callback_data_t;
/**
- * Data required by the sender
+ * Data required by several callback jobs used in this file
*/
-struct sender_data_t {
+struct callback_data_t {
/** connect manager */
private_connect_manager_t *connect_manager;
- /** session id */
- chunk_t session_id;
+ /** connect id */
+ chunk_t connect_id;
+
+ /** message (pair) id */
+ u_int32_t mid;
};
/**
- * Destroys a sender data object
+ * Destroys a callback data object
*/
-static void sender_data_destroy(sender_data_t *this)
+static void callback_data_destroy(callback_data_t *this)
{
- chunk_free(&this->session_id);
+ chunk_free(&this->connect_id);
free(this);
}
/**
- * Creates a new sender data object
+ * Creates a new callback data object
*/
-static sender_data_t *sender_data_create(private_connect_manager_t *connect_manager, chunk_t session_id)
+static callback_data_t *callback_data_create(private_connect_manager_t *connect_manager,
+ chunk_t connect_id)
{
- sender_data_t *this = malloc_thing(sender_data_t);
+ callback_data_t *this = malloc_thing(callback_data_t);
this->connect_manager = connect_manager;
- this->session_id = session_id;
+ this->connect_id = chunk_clone(connect_id);
+ this->mid = 0;
return this;
}
-typedef struct retransmit_data_t retransmit_data_t;
-
-/**
- * Data required by the retransmission job
- */
-struct retransmit_data_t {
- /** connect manager */
- private_connect_manager_t *connect_manager;
-
- /** session id */
- chunk_t session_id;
-
- /** message (pair) id */
- u_int32_t mid;
-};
-
-/**
- * Destroys a retransmission data object
- */
-static void retransmit_data_destroy(retransmit_data_t *this)
-{
- chunk_free(&this->session_id);
- free(this);
-}
-
/**
* Creates a new retransmission data object
*/
-static retransmit_data_t *retransmit_data_create(private_connect_manager_t *connect_manager,
- chunk_t session_id, u_int32_t mid)
+static callback_data_t *retransmit_data_create(private_connect_manager_t *connect_manager,
+ chunk_t connect_id, u_int32_t mid)
{
- retransmit_data_t *this = malloc_thing(retransmit_data_t);
-
- this->connect_manager = connect_manager;
- this->session_id = session_id;
+ callback_data_t *this = callback_data_create(connect_manager, connect_id);
this->mid = mid;
-
return this;
}
@@ -529,34 +481,19 @@ static void remove_initiated(private_connect_manager_t *this, initiated_t *initi
}
/**
- * Finds a waiting sa
+ * Find the checklist with a specific connect ID
*/
-static bool match_waiting_sa(waiting_sa_t *current, ike_sa_id_t *ike_sa_id)
+static bool match_checklist_by_id(check_list_t *current, chunk_t *connect_id)
{
- return ike_sa_id->equals(ike_sa_id, current->ike_sa_id);
-}
-
-static status_t get_waiting_sa(initiated_t *initiated, ike_sa_id_t *ike_sa_id, waiting_sa_t **waiting_sa)
-{
- return initiated->mediated->find_first(initiated->mediated,
- (linked_list_match_t)match_waiting_sa,
- (void**)waiting_sa, ike_sa_id);
-}
-
-/**
- * Find the checklist with a specific session ID
- */
-static bool match_checklist_by_id(check_list_t *current, chunk_t *session_id)
-{
- return chunk_equals(*session_id, current->session_id);
+ return chunk_equals(*connect_id, current->connect_id);
}
static status_t get_checklist_by_id(private_connect_manager_t *this,
- chunk_t session_id, check_list_t **check_list)
+ chunk_t connect_id, check_list_t **check_list)
{
return this->checklists->find_first(this->checklists,
(linked_list_match_t)match_checklist_by_id,
- (void**)check_list, &session_id);
+ (void**)check_list, &connect_id);
}
/**
@@ -595,51 +532,6 @@ static status_t endpoints_contain(linked_list_t *endpoints, host_t *host, endpoi
}
/**
- * Updates the state of the whole checklist
- */
-static void update_checklist_state(check_list_t *checklist)
-{
- iterator_t *iterator;
- endpoint_pair_t *current;
- bool in_progress = FALSE, succeeded = FALSE;
-
- iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE);
- while (iterator->iterate(iterator, (void**)&current))
- {
- switch(current->state)
- {
- case CHECK_WAITING:
- /* at least one is still waiting -> checklist remains
- * in waiting state */
- iterator->destroy(iterator);
- return;
- case CHECK_IN_PROGRESS:
- in_progress = TRUE;
- break;
- case CHECK_SUCCEEDED:
- succeeded = TRUE;
- break;
- default:
- break;
- }
- }
- iterator->destroy(iterator);
-
- if (in_progress)
- {
- checklist->state = CHECK_IN_PROGRESS;
- }
- else if (succeeded)
- {
- checklist->state = CHECK_SUCCEEDED;
- }
- else
- {
- checklist->state = CHECK_FAILED;
- }
-}
-
-/**
* Inserts an endpoint pair into the list of pairs ordered by priority (high to low)
*/
static void insert_pair_by_priority(linked_list_t *pairs, endpoint_pair_t *pair)
@@ -681,14 +573,14 @@ static status_t get_pair_by_hosts(linked_list_t *pairs, host_t *local, host_t *r
(void**)pair, local, remote);
}
-/**
- * Searches for a pair with a specific id
- */
static bool match_pair_by_id(endpoint_pair_t *current, u_int32_t *id)
{
return current->id == *id;
}
+/**
+ * Searches for a pair with a specific id
+ */
static status_t get_pair_by_id(check_list_t *checklist, u_int32_t id, endpoint_pair_t **pair)
{
return checklist->pairs->find_first(checklist->pairs,
@@ -696,14 +588,14 @@ static status_t get_pair_by_id(check_list_t *checklist, u_int32_t id, endpoint_p
(void**)pair, &id);
}
-/**
- * Returns the best pair of state CHECK_SUCCEEDED from a checklist.
- */
static bool match_succeeded_pair(endpoint_pair_t *current)
{
return current->state == CHECK_SUCCEEDED;
}
+/**
+ * Returns the best pair of state CHECK_SUCCEEDED from a checklist.
+ */
static status_t get_best_valid_pair(check_list_t *checklist, endpoint_pair_t **pair)
{
return checklist->pairs->find_first(checklist->pairs,
@@ -711,14 +603,14 @@ static status_t get_best_valid_pair(check_list_t *checklist, endpoint_pair_t **p
(void**)pair);
}
-/**
- * Returns and *removes* the first triggered pair in state CHECK_WAITING.
- */
static bool match_waiting_pair(endpoint_pair_t *current)
{
return current->state == CHECK_WAITING;
}
+/**
+ * Returns and *removes* the first triggered pair in state CHECK_WAITING.
+ */
static status_t get_triggered_pair(check_list_t *checklist, endpoint_pair_t **pair)
{
iterator_t *iterator;
@@ -746,6 +638,24 @@ static status_t get_triggered_pair(check_list_t *checklist, endpoint_pair_t **pa
}
/**
+ * Prints all the pairs on a checklist
+ */
+static void print_checklist(check_list_t *checklist)
+{
+ iterator_t *iterator;
+ endpoint_pair_t *current;
+
+ DBG1(DBG_IKE, "pairs on checklist %#B:", &checklist->connect_id);
+ iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ DBG1(DBG_IKE, " * %#H - %#H (%d)", current->local, current->remote,
+ current->priority);
+ }
+ iterator->destroy(iterator);
+}
+
+/**
* Prunes identical pairs with lower priority from the list
* Note: this function also numbers the remaining pairs serially
*/
@@ -775,7 +685,7 @@ static void prune_pairs(linked_list_t *pairs)
* order, and we iterate the list from the beginning, we are
* sure that the priority of 'other' is lower than that of
* 'current', remove it */
- DBG1(DBG_IKE, "pruning endpoint pair %H - %H with priority %d",
+ DBG1(DBG_IKE, "pruning endpoint pair %#H - %#H with priority %d",
other->local, other->remote, other->priority);
search->remove(search);
endpoint_pair_destroy(other);
@@ -792,6 +702,7 @@ static void prune_pairs(linked_list_t *pairs)
*/
static void build_pairs(check_list_t *checklist)
{
+ /* FIXME: limit endpoints and pairs */
iterator_t *iterator_i, *iterator_r;
endpoint_notify_t *initiator, *responder;
@@ -812,6 +723,8 @@ static void build_pairs(check_list_t *checklist)
iterator_r->destroy(iterator_r);
}
iterator_i->destroy(iterator_i);
+
+ print_checklist(checklist);
prune_pairs(checklist->pairs);
}
@@ -838,45 +751,45 @@ static status_t process_payloads(message_t *message, check_t *check)
switch (notify->get_notify_type(notify))
{
- case P2P_ENDPOINT:
+ case ME_ENDPOINT:
{
if (check->endpoint)
{
- DBG1(DBG_IKE, "connectivity check contains multiple P2P_ENDPOINT notifies");
+ DBG1(DBG_IKE, "connectivity check contains multiple ME_ENDPOINT notifies");
break;
}
endpoint_notify_t *endpoint = endpoint_notify_create_from_payload(notify);
if (!endpoint)
{
- DBG1(DBG_IKE, "received invalid P2P_ENDPOINT notify");
+ DBG1(DBG_IKE, "received invalid ME_ENDPOINT notify");
break;
}
check->endpoint = endpoint;
check->endpoint_raw = chunk_clone(notify->get_notification_data(notify));
- DBG2(DBG_IKE, "received P2P_ENDPOINT notify");
+ DBG2(DBG_IKE, "received ME_ENDPOINT notify");
break;
}
- case P2P_SESSIONID:
+ case ME_CONNECTID:
{
- if (check->session_id.ptr)
+ if (check->connect_id.ptr)
{
- DBG1(DBG_IKE, "connectivity check contains multiple P2P_SESSIONID notifies");
+ DBG1(DBG_IKE, "connectivity check contains multiple ME_CONNECTID notifies");
break;
}
- check->session_id = chunk_clone(notify->get_notification_data(notify));
- DBG3(DBG_IKE, "received p2p_sessionid %B", &check->session_id);
+ check->connect_id = chunk_clone(notify->get_notification_data(notify));
+ DBG2(DBG_IKE, "received ME_CONNECTID %#B", &check->connect_id);
break;
}
- case COOKIE:
+ case ME_CONNECTAUTH:
{
- if (check->cookie.ptr)
+ if (check->auth.ptr)
{
- DBG1(DBG_IKE, "connectivity check contains multiple COOKIE notifies");
+ DBG1(DBG_IKE, "connectivity check contains multiple ME_CONNECTAUTH notifies");
break;
}
- check->cookie = chunk_clone(notify->get_notification_data(notify));
- DBG3(DBG_IKE, "received cookie %B", &check->cookie);
+ check->auth = chunk_clone(notify->get_notification_data(notify));
+ DBG2(DBG_IKE, "received ME_CONNECTAUTH %#B", &check->auth);
break;
}
default:
@@ -885,7 +798,7 @@ static status_t process_payloads(message_t *message, check_t *check)
}
iterator->destroy(iterator);
- if (!check->session_id.ptr || !check->endpoint || !check->cookie.ptr)
+ if (!check->connect_id.ptr || !check->endpoint || !check->auth.ptr)
{
DBG1(DBG_IKE, "at least one payload was missing from the connectivity check");
return FAILED;
@@ -900,42 +813,129 @@ static status_t process_payloads(message_t *message, check_t *check)
static chunk_t build_signature(private_connect_manager_t *this,
check_list_t *checklist, check_t *check, bool outbound)
{
+ u_int32_t mid;
chunk_t mid_chunk, key_chunk, sig_chunk;
chunk_t sig_hash;
- mid_chunk = chunk_from_thing(check->mid);
+ mid = htonl(check->mid);
+ mid_chunk = chunk_from_thing(mid);
key_chunk = (checklist->is_initiator && outbound) || (!checklist->is_initiator && !outbound)
? checklist->initiator.key : checklist->responder.key;
- /* signature = SHA1( MID | P2P_SESSIONID | P2P_ENDPOINT | P2P_SESSIONKEY ) */
- sig_chunk = chunk_cat("cccc", mid_chunk, check->session_id, check->endpoint_raw, key_chunk);
+ /* signature = SHA1( MID | ME_CONNECTID | ME_ENDPOINT | ME_CONNECTKEY ) */
+ sig_chunk = chunk_cat("cccc", mid_chunk, check->connect_id, check->endpoint_raw, key_chunk);
this->hasher->allocate_hash(this->hasher, sig_chunk, &sig_hash);
- DBG3(DBG_IKE, "sig_chunk %B", &sig_chunk);
- DBG3(DBG_IKE, "sig_hash %B", &sig_hash);
+ DBG3(DBG_IKE, "sig_chunk %#B", &sig_chunk);
+ DBG3(DBG_IKE, "sig_hash %#B", &sig_hash);
chunk_free(&sig_chunk);
return sig_hash;
}
-static void queue_retransmission(private_connect_manager_t *this, chunk_t session_id, u_int32_t mid);
+static void queue_retransmission(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair);
static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time);
static void finish_checks(private_connect_manager_t *this, check_list_t *checklist);
/**
+ * After one of the initiator's pairs has succeeded we finish the checks without
+ * waiting for all the timeouts
+ */
+static job_requeue_t initiator_finish(callback_data_t *data)
+{
+ private_connect_manager_t *this = data->connect_manager;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ check_list_t *checklist;
+ if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
+ {
+ DBG1(DBG_IKE, "checklist with id '%#B' not found, can't finish connectivity checks",
+ &data->connect_id);
+ pthread_mutex_unlock(&(this->mutex));
+ return JOB_REQUEUE_NONE;
+ }
+
+ finish_checks(this, checklist);
+
+ pthread_mutex_unlock(&(this->mutex));
+
+ return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Updates the state of the whole checklist
+ */
+static void update_checklist_state(private_connect_manager_t *this, check_list_t *checklist)
+{
+ iterator_t *iterator;
+ endpoint_pair_t *current;
+ bool in_progress = FALSE, succeeded = FALSE;
+
+ iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ switch(current->state)
+ {
+ case CHECK_WAITING:
+ /* at least one is still waiting -> checklist remains
+ * in waiting state */
+ iterator->destroy(iterator);
+ return;
+ case CHECK_IN_PROGRESS:
+ in_progress = TRUE;
+ break;
+ case CHECK_SUCCEEDED:
+ succeeded = TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (checklist->is_initiator && succeeded && !checklist->is_finishing)
+ {
+ /* instead of waiting until all checks have finished (i.e. all
+ * retransmissions have failed) the initiator finishes the checks
+ * right after the first check has succeeded. to allow a probably
+ * better pair to succeed, we still wait a certain time */
+ DBG2(DBG_IKE, "fast finishing checks for checklist '%#B'", &checklist->connect_id);
+
+ callback_data_t *data = callback_data_create(this, checklist->connect_id);
+ job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiator_finish, data, (callback_job_cleanup_t)callback_data_destroy, NULL);
+ charon->scheduler->schedule_job(charon->scheduler, job, ME_WAIT_TO_FINISH);
+ checklist->is_finishing = TRUE;
+ }
+
+ if (in_progress)
+ {
+ checklist->state = CHECK_IN_PROGRESS;
+ }
+ else if (succeeded)
+ {
+ checklist->state = CHECK_SUCCEEDED;
+ }
+ else
+ {
+ checklist->state = CHECK_FAILED;
+ }
+}
+
+/**
* This function is triggered for each sent check after a specific timeout
*/
-static job_requeue_t retransmit(retransmit_data_t *data)
+static job_requeue_t retransmit(callback_data_t *data)
{
private_connect_manager_t *this = data->connect_manager;
pthread_mutex_lock(&(this->mutex));
check_list_t *checklist;
- if (get_checklist_by_id(this, data->session_id, &checklist) != SUCCESS)
+ if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
{
- DBG1(DBG_IKE, "checklist with id '%B' not found, can't retransmit connectivity check",
- &data->session_id);
+ DBG1(DBG_IKE, "checklist with id '%#B' not found, can't retransmit connectivity check",
+ &data->connect_id);
pthread_mutex_unlock(&(this->mutex));
return JOB_REQUEUE_NONE;
}
@@ -955,20 +955,20 @@ static job_requeue_t retransmit(retransmit_data_t *data)
goto retransmit_end;
}
- if (++pair->retransmitted >= P2P_MAX_RETRANS)
+ if (++pair->retransmitted > ME_MAX_RETRANS)
{
- DBG2(DBG_IKE, "pair with id '%d' failed after %d tries",
- data->mid, pair->retransmitted);
+ DBG2(DBG_IKE, "pair with id '%d' failed after %d retransmissions",
+ data->mid, ME_MAX_RETRANS);
pair->state = CHECK_FAILED;
goto retransmit_end;
}
charon->sender->send(charon->sender, pair->packet->clone(pair->packet));
- queue_retransmission(this, checklist->session_id, pair->id);
+ queue_retransmission(this, checklist, pair);
retransmit_end:
- update_checklist_state(checklist);
+ update_checklist_state(this, checklist);
switch(checklist->state)
{
@@ -989,11 +989,20 @@ retransmit_end:
/**
* Queues a retransmission job
*/
-static void queue_retransmission(private_connect_manager_t *this, chunk_t session_id, u_int32_t mid)
+static void queue_retransmission(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair)
{
- retransmit_data_t *data = retransmit_data_create(this, chunk_clone(session_id), mid);
- job_t *job = (job_t*)callback_job_create((callback_job_cb_t)retransmit, data, (callback_job_cleanup_t)retransmit_data_destroy, NULL);
- charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, P2P_RTO_MIN);
+ callback_data_t *data = retransmit_data_create(this, checklist->connect_id, pair->id);
+ job_t *job = (job_t*)callback_job_create((callback_job_cb_t)retransmit, data, (callback_job_cleanup_t)callback_data_destroy, NULL);
+
+ u_int32_t retransmission = pair->retransmitted + 1;
+ u_int32_t rto = ME_INTERVAL;
+ if (retransmission > ME_BOOST)
+ {
+ rto = (u_int32_t)(ME_INTERVAL * pow(ME_RETRANS_BASE, retransmission - ME_BOOST));
+ }
+ DBG2(DBG_IKE, "scheduling retransmission %d of pair '%d' in %dms", retransmission, pair->id, rto);
+
+ charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, rto);
}
/**
@@ -1009,16 +1018,21 @@ static void send_check(private_connect_manager_t *this, check_list_t *checklist,
message->set_destination(message, check->dst->clone(check->dst));
message->set_source(message, check->src->clone(check->src));
- message->set_ike_sa_id(message, ike_sa_id_create(0, 0, request));
+ ike_sa_id_t *ike_sa_id = ike_sa_id_create(0, 0, request);
+ message->set_ike_sa_id(message, ike_sa_id);
+ ike_sa_id->destroy(ike_sa_id);
- message->add_notify(message, FALSE, P2P_SESSIONID, check->session_id);
+ message->add_notify(message, FALSE, ME_CONNECTID, check->connect_id);
+ DBG2(DBG_IKE, "send ME_CONNECTID %#B", &check->connect_id);
notify_payload_t *endpoint = check->endpoint->build_notify(check->endpoint);
check->endpoint_raw = chunk_clone(endpoint->get_notification_data(endpoint));
message->add_payload(message, (payload_t*)endpoint);
+ DBG2(DBG_IKE, "send ME_ENDPOINT notify");
- check->cookie = build_signature(this, checklist, check, TRUE);
- message->add_notify(message, FALSE, COOKIE, check->cookie);
+ check->auth = build_signature(this, checklist, check, TRUE);
+ message->add_notify(message, FALSE, ME_CONNECTAUTH, check->auth);
+ DBG2(DBG_IKE, "send ME_CONNECTAUTH %#B", &check->auth);
packet_t *packet;
if (message->generate(message, NULL, NULL, &packet) == SUCCESS)
@@ -1029,42 +1043,55 @@ static void send_check(private_connect_manager_t *this, check_list_t *checklist,
{
DESTROY_IF(pair->packet);
pair->packet = packet;
- queue_retransmission(this, checklist->session_id, pair->id);
+ pair->retransmitted = 0;
+ queue_retransmission(this, checklist, pair);
}
else
{
packet->destroy(packet);
}
}
+ message->destroy(message);
}
/**
* Queues a triggered check
*/
-static void queue_triggered_check(check_list_t *checklist, endpoint_pair_t *pair)
+static void queue_triggered_check(private_connect_manager_t *this,
+ check_list_t *checklist, endpoint_pair_t *pair)
{
+ DBG2(DBG_IKE, "queueing triggered check for pair '%d'", pair->id);
pair->state = CHECK_WAITING;
checklist->triggered->insert_last(checklist->triggered, pair);
+
+ if (!checklist->sender)
+ {
+ /* if the sender is not running we restart it */
+ schedule_checks(this, checklist, ME_INTERVAL);
+ }
}
/**
* This function is triggered for each checklist at a specific interval
*/
-static job_requeue_t sender(sender_data_t *data)
+static job_requeue_t sender(callback_data_t *data)
{
private_connect_manager_t *this = data->connect_manager;
pthread_mutex_lock(&(this->mutex));
-
+
check_list_t *checklist;
- if (get_checklist_by_id(this, data->session_id, &checklist) != SUCCESS)
+ if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
{
- DBG1(DBG_IKE, "checklist with id '%B' not found, can't send connectivity check",
- &data->session_id);
+ DBG1(DBG_IKE, "checklist with id '%#B' not found, can't send connectivity check",
+ &data->connect_id);
pthread_mutex_unlock(&(this->mutex));
return JOB_REQUEUE_NONE;
}
+ /* reset the sender */
+ checklist->sender = NULL;
+
endpoint_pair_t *pair;
if (get_triggered_pair(checklist, &pair) != SUCCESS)
{
@@ -1087,7 +1114,7 @@ static job_requeue_t sender(sender_data_t *data)
check->mid = pair->id;
check->src = pair->local->clone(pair->local);
check->dst = pair->remote->clone(pair->remote);
- check->session_id = chunk_clone(checklist->session_id);
+ check->connect_id = chunk_clone(checklist->connect_id);
check->endpoint = endpoint_notify_create();
pair->state = CHECK_IN_PROGRESS;
@@ -1097,8 +1124,7 @@ static job_requeue_t sender(sender_data_t *data)
check_destroy(check);
/* schedule this job again */
- u_int32_t N = this->checklists->get_count(this->checklists);
- schedule_checks(this, checklist, P2P_INTERVAL * N);
+ schedule_checks(this, checklist, ME_INTERVAL);
pthread_mutex_unlock(&(this->mutex));
@@ -1111,10 +1137,9 @@ static job_requeue_t sender(sender_data_t *data)
*/
static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time)
{
- chunk_t session_id = chunk_clone(checklist->session_id);
- sender_data_t *data = sender_data_create(this, session_id);
- job_t *job = (job_t*)callback_job_create((callback_job_cb_t)sender, data, (callback_job_cleanup_t)sender_data_destroy, NULL);
- charon->scheduler->schedule_job(charon->scheduler, job, time);
+ callback_data_t *data = callback_data_create(this, checklist->connect_id);
+ checklist->sender = (job_t*)callback_job_create((callback_job_cb_t)sender, data, (callback_job_cleanup_t)callback_data_destroy, NULL);
+ charon->scheduler->schedule_job(charon->scheduler, checklist->sender, time);
}
/**
@@ -1128,12 +1153,12 @@ static job_requeue_t initiate_mediated(initiate_data_t *data)
endpoint_pair_t *pair;
if (get_best_valid_pair(checklist, &pair) == SUCCESS)
{
- waiting_sa_t *waiting_sa;
+ ike_sa_id_t *waiting_sa;
iterator_t *iterator = initiated->mediated->create_iterator(initiated->mediated, TRUE);
while (iterator->iterate(iterator, (void**)&waiting_sa))
{
- ike_sa_t *sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, waiting_sa->ike_sa_id);
- if (sa->initiate_mediated(sa, pair->local, pair->remote, waiting_sa->childs) != SUCCESS)
+ ike_sa_t *sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, waiting_sa);
+ if (sa->initiate_mediated(sa, pair->local, pair->remote, checklist->connect_id) != SUCCESS)
{
SIG(IKE_UP_FAILED, "establishing the mediated connection failed");
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, sa);
@@ -1175,11 +1200,6 @@ static void finish_checks(private_connect_manager_t *this, check_list_t *checkli
"and '%D'", checklist->initiator.id, checklist->responder.id);
}
}
-
- /* remove_checklist(this, checklist);
- * check_list_destroy(checklist);
- * FIXME: we should do this ^^^ after a specific timeout on the
- * responder side */
}
/**
@@ -1212,7 +1232,7 @@ static void process_response(private_connect_manager_t *this, check_t *check,
local_endpoints->insert_last(local_endpoints, local_endpoint);
}
- update_checklist_state(checklist);
+ update_checklist_state(this, checklist);
switch(checklist->state)
{
@@ -1253,12 +1273,12 @@ static void process_request(private_connect_manager_t *this, check_t *check,
{
case CHECK_IN_PROGRESS:
/* prevent retransmissions */
- pair->retransmitted = P2P_MAX_RETRANS;
+ pair->retransmitted = ME_MAX_RETRANS;
/* FIXME: we should wait to the next rto to send the triggered check
* fall-through */
case CHECK_WAITING:
case CHECK_FAILED:
- queue_triggered_check(checklist, pair);
+ queue_triggered_check(this, checklist, pair);
break;
case CHECK_SUCCEEDED:
default:
@@ -1277,7 +1297,7 @@ static void process_request(private_connect_manager_t *this, check_t *check,
insert_pair_by_priority(checklist->pairs, pair);
- queue_triggered_check(checklist, pair);
+ queue_triggered_check(this, checklist, pair);
local_endpoint->destroy(local_endpoint);
}
@@ -1288,7 +1308,7 @@ static void process_request(private_connect_manager_t *this, check_t *check,
response->mid = check->mid;
response->src = check->dst->clone(check->dst);
response->dst = check->src->clone(check->src);
- response->session_id = chunk_clone(check->session_id);
+ response->connect_id = chunk_clone(check->connect_id);
response->endpoint = peer_reflexive;
send_check(this, checklist, response, pair, FALSE);
@@ -1313,7 +1333,9 @@ static void process_check(private_connect_manager_t *this, message_t *message)
check_t *check = check_create();
check->mid = message->get_message_id(message);
check->src = message->get_source(message);
+ check->src = check->src->clone(check->src);
check->dst = message->get_destination(message);
+ check->dst = check->dst->clone(check->dst);
if (process_payloads(message, check) != SUCCESS)
{
@@ -1326,17 +1348,17 @@ static void process_check(private_connect_manager_t *this, message_t *message)
pthread_mutex_lock(&(this->mutex));
check_list_t *checklist;
- if (get_checklist_by_id(this, check->session_id, &checklist) != SUCCESS)
+ if (get_checklist_by_id(this, check->connect_id, &checklist) != SUCCESS)
{
- DBG1(DBG_IKE, "checklist with id '%B' not found",
- &check->session_id);
+ DBG1(DBG_IKE, "checklist with id '%#B' not found",
+ &check->connect_id);
check_destroy(check);
pthread_mutex_unlock(&(this->mutex));
return;
}
chunk_t sig = build_signature(this, checklist, check, FALSE);
- if (!chunk_equals(sig, check->cookie))
+ if (!chunk_equals(sig, check->auth))
{
DBG1(DBG_IKE, "connectivity check verification failed");
check_destroy(check);
@@ -1365,7 +1387,7 @@ static void process_check(private_connect_manager_t *this, message_t *message)
*/
static bool check_and_register(private_connect_manager_t *this,
identification_t *id, identification_t *peer_id,
- ike_sa_id_t *mediated_sa, child_cfg_t *child)
+ ike_sa_id_t *mediated_sa)
{
initiated_t *initiated;
bool already_there = TRUE;
@@ -1380,16 +1402,12 @@ static bool check_and_register(private_connect_manager_t *this,
already_there = FALSE;
}
- waiting_sa_t *waiting_sa;
- if (get_waiting_sa(initiated, mediated_sa, &waiting_sa) != SUCCESS)
+ if (initiated->mediated->find_first(initiated->mediated,
+ (linked_list_match_t)mediated_sa->equals, NULL, mediated_sa) != SUCCESS)
{
- waiting_sa = waiting_sa_create(mediated_sa);
- initiated->mediated->insert_last(initiated->mediated, waiting_sa);
+ initiated->mediated->insert_last(initiated->mediated, mediated_sa->clone(mediated_sa));
}
- child->get_ref(child);
- waiting_sa->childs->insert_last(waiting_sa->childs, child);
-
pthread_mutex_unlock(&(this->mutex));
return already_there;
@@ -1412,14 +1430,14 @@ static void check_and_initiate(private_connect_manager_t *this, ike_sa_id_t *med
return;
}
- waiting_sa_t *waiting_sa;
+ ike_sa_id_t *waiting_sa;
iterator_t *iterator = initiated->mediated->create_iterator(initiated->mediated, TRUE);
while (iterator->iterate(iterator, (void**)&waiting_sa))
{
- job_t *job = (job_t*)reinitiate_mediation_job_create(mediation_sa,
- waiting_sa->ike_sa_id);
+ job_t *job = (job_t*)reinitiate_mediation_job_create(mediation_sa, waiting_sa);
charon->processor->queue_job(charon->processor, job);
}
+ iterator->destroy(iterator);
pthread_mutex_unlock(&(this->mutex));
}
@@ -1429,21 +1447,21 @@ static void check_and_initiate(private_connect_manager_t *this, ike_sa_id_t *med
*/
static status_t set_initiator_data(private_connect_manager_t *this,
identification_t *initiator, identification_t *responder,
- chunk_t session_id, chunk_t key, linked_list_t *endpoints, bool is_initiator)
+ chunk_t connect_id, chunk_t key, linked_list_t *endpoints, bool is_initiator)
{
check_list_t *checklist;
pthread_mutex_lock(&(this->mutex));
- if (get_checklist_by_id(this, session_id, NULL) == SUCCESS)
+ if (get_checklist_by_id(this, connect_id, NULL) == SUCCESS)
{
- DBG1(DBG_IKE, "checklist with id '%B' already exists, aborting",
- &session_id);
+ DBG1(DBG_IKE, "checklist with id '%#B' already exists, aborting",
+ &connect_id);
pthread_mutex_unlock(&(this->mutex));
return FAILED;
}
- checklist = check_list_create(initiator, responder, session_id, key, endpoints, is_initiator);
+ checklist = check_list_create(initiator, responder, connect_id, key, endpoints, is_initiator);
this->checklists->insert_last(this->checklists, checklist);
pthread_mutex_unlock(&(this->mutex));
@@ -1455,16 +1473,16 @@ static status_t set_initiator_data(private_connect_manager_t *this,
* Implementation of connect_manager_t.set_responder_data.
*/
static status_t set_responder_data(private_connect_manager_t *this,
- chunk_t session_id, chunk_t key, linked_list_t *endpoints)
+ chunk_t connect_id, chunk_t key, linked_list_t *endpoints)
{
check_list_t *checklist;
pthread_mutex_lock(&(this->mutex));
- if (get_checklist_by_id(this, session_id, &checklist) != SUCCESS)
+ if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS)
{
- DBG1(DBG_IKE, "checklist with id '%B' not found",
- &session_id);
+ DBG1(DBG_IKE, "checklist with id '%#B' not found",
+ &connect_id);
pthread_mutex_unlock(&(this->mutex));
return NOT_FOUND;
}
@@ -1484,6 +1502,33 @@ static status_t set_responder_data(private_connect_manager_t *this,
}
/**
+ * Implementation of connect_manager_t.stop_checks.
+ */
+static status_t stop_checks(private_connect_manager_t *this, chunk_t connect_id)
+{
+ check_list_t *checklist;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS)
+ {
+ DBG1(DBG_IKE, "checklist with id '%#B' not found",
+ &connect_id);
+ pthread_mutex_unlock(&(this->mutex));
+ return NOT_FOUND;
+ }
+
+ DBG1(DBG_IKE, "removing checklist with id '%#B'", &connect_id);
+
+ remove_checklist(this, checklist);
+ check_list_destroy(checklist);
+
+ pthread_mutex_unlock(&(this->mutex));
+
+ return SUCCESS;
+}
+
+/**
* Implementation of connect_manager_t.destroy.
*/
static void destroy(private_connect_manager_t *this)
@@ -1507,13 +1552,21 @@ connect_manager_t *connect_manager_create()
private_connect_manager_t *this = malloc_thing(private_connect_manager_t);
this->public.destroy = (void(*)(connect_manager_t*))destroy;
- this->public.check_and_register = (bool(*)(connect_manager_t*,identification_t*,identification_t*,ike_sa_id_t*,child_cfg_t*))check_and_register;
+ this->public.check_and_register = (bool(*)(connect_manager_t*,identification_t*,identification_t*,ike_sa_id_t*))check_and_register;
this->public.check_and_initiate = (void(*)(connect_manager_t*,ike_sa_id_t*,identification_t*,identification_t*))check_and_initiate;
this->public.set_initiator_data = (status_t(*)(connect_manager_t*,identification_t*,identification_t*,chunk_t,chunk_t,linked_list_t*,bool))set_initiator_data;
this->public.set_responder_data = (status_t(*)(connect_manager_t*,chunk_t,chunk_t,linked_list_t*))set_responder_data;
this->public.process_check = (void(*)(connect_manager_t*,message_t*))process_check;
+ this->public.stop_checks = (status_t(*)(connect_manager_t*,chunk_t))stop_checks;
+
+ this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+ if (this->hasher == NULL)
+ {
+ DBG1(DBG_IKE, "unable to create connect manager, SHA1 not supported");
+ free(this);
+ return NULL;
+ }
- this->hasher = hasher_create(HASH_SHA1);
this->checklists = linked_list_create();
this->initiated = linked_list_create();
diff --git a/src/charon/sa/connect_manager.h b/src/charon/sa/connect_manager.h
index 2f3e9109b..38d8e7a49 100644
--- a/src/charon/sa/connect_manager.h
+++ b/src/charon/sa/connect_manager.h
@@ -1,12 +1,5 @@
-/**
- * @file connect_manager.h
- *
- * @brief Interface of connect_manager_t.
- *
- */
-
/*
- * Copyright (C) 2007 Tobias Brunner
+ * Copyright (C) 2007-2008 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: connect_manager.h 3792 2008-04-10 12:51:04Z tobias $
+ */
+
+/**
+ * @defgroup connect_manager connect_manager
+ * @{ @ingroup sa
*/
#ifndef CONNECT_MANAGER_H_
@@ -26,43 +26,33 @@
typedef struct connect_manager_t connect_manager_t;
#include <encoding/message.h>
-#include <config/child_cfg.h>
#include <sa/ike_sa_id.h>
#include <utils/identification.h>
/**
- * @brief The connection manager is responsible for establishing a direct
+ * The connection manager is responsible for establishing a direct
* connection with another peer.
- *
- * @b Constructors:
- * - connect_manager_create()
- *
- * @ingroup sa
*/
struct connect_manager_t {
/**
- * @brief Checks if a there is already a mediated connection registered
+ * Checks if a there is already a mediated connection registered
* between two peers.
*
- * @param this the manager object
* @param id my id
* @param peer_id the other peer's id
* @param mediated_sa the IKE_SA ID of the mediated connection
- * @param child the CHILD_SA config of the mediated connection
* @returns
* - TRUE, if there was already a mediated connection registered
* - FALSE, otherwise
*/
bool (*check_and_register) (connect_manager_t *this,
- identification_t *id, identification_t *peer_id,
- ike_sa_id_t *mediated_sa, child_cfg_t *child);
+ identification_t *id, identification_t *peer_id, ike_sa_id_t *mediated_sa);
/**
- * @brief Checks if there are waiting connections with a specific peer.
+ * Checks if there are waiting connections with a specific peer.
* If so, reinitiate them.
*
- * @param this the manager object
* @param id my id
* @param peer_id the other peer's id
*/
@@ -70,29 +60,26 @@ struct connect_manager_t {
identification_t *id, identification_t *peer_id);
/**
- * @brief Creates a checklist and sets the initiator's data.
+ * Creates a checklist and sets the initiator's data.
*
- * @param this the manager object
* @param initiator ID of the initiator
* @param responder ID of the responder
- * @param session_id the session ID provided by the initiator
+ * @param connect_id the connect ID provided by the initiator
* @param key the initiator's key
* @param endpoints the initiator's endpoints
* @param is_initiator TRUE, if the caller of this method is the initiator
* FALSE, otherwise
- * @returns
- * SUCCESS
+ * @returns SUCCESS
*/
status_t (*set_initiator_data) (connect_manager_t *this,
identification_t *initiator, identification_t *responder,
- chunk_t session_id, chunk_t key, linked_list_t *endpoints, bool is_initiator);
+ chunk_t connect_id, chunk_t key, linked_list_t *endpoints, bool is_initiator);
/**
- * @brief Updates a checklist and sets the responder's data. The checklist's
+ * Updates a checklist and sets the responder's data. The checklist's
* state is advanced to WAITING which means that checks will be sent.
*
- * @param this the manager object
- * @param session_id the session ID
+ * @param connect_id the connect ID
* @param chunk_t the responder's key
* @param endpoints the responder's endpoints
* @returns
@@ -100,32 +87,37 @@ struct connect_manager_t {
* - SUCCESS, otherwise
*/
status_t (*set_responder_data) (connect_manager_t *this,
- chunk_t session_id, chunk_t key, linked_list_t *endpoints);
+ chunk_t connect_id, chunk_t key, linked_list_t *endpoints);
+ /**
+ * Stops checks for a checklist. Used after the responder received an IKE_SA_INIT
+ * request which contains a ME_CONNECTID payload.
+ *
+ * @param connect_id the connect ID
+ * @returns
+ * - NOT_FOUND, if the checklist has not been found
+ * - SUCCESS, otherwise
+ */
+ status_t (*stop_checks) (connect_manager_t *this, chunk_t connect_id);
/**
- * @brief Processes a connectivity check
+ * Processes a connectivity check
*
- * @param this the manager object
* @param message the received message
*/
void (*process_check) (connect_manager_t *this, message_t *message);
/**
- * @brief Destroys the manager with all data.
- *
- * @param this the manager object
+ * Destroys the manager with all data.
*/
void (*destroy) (connect_manager_t *this);
};
/**
- * @brief Create a manager.
+ * Create a manager.
*
* @returns connect_manager_t object
- *
- * @ingroup sa
*/
connect_manager_t *connect_manager_create(void);
-#endif /*CONNECT_MANAGER_H_*/
+#endif /*CONNECT_MANAGER_H_ @} */
diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c
index 93aa08965..384226380 100644
--- a/src/charon/sa/ike_sa.c
+++ b/src/charon/sa/ike_sa.c
@@ -1,12 +1,5 @@
-/**
- * @file ike_sa.c
- *
- * @brief Implementation of ike_sa_t.
- *
- */
-
/*
- * Copyright (C) 2006-2007 Tobias Brunner
+ * Copyright (C) 2006-2008 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -21,6 +14,8 @@
* 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.
+ *
+ * $Id: ike_sa.c 4106 2008-06-25 11:40:50Z martin $
*/
#include <sys/time.h>
@@ -53,7 +48,8 @@
#include <sa/tasks/ike_auth.h>
#include <sa/tasks/ike_auth_lifetime.h>
#include <sa/tasks/ike_config.h>
-#include <sa/tasks/ike_cert.h>
+#include <sa/tasks/ike_cert_pre.h>
+#include <sa/tasks/ike_cert_post.h>
#include <sa/tasks/ike_rekey.h>
#include <sa/tasks/ike_reauth.h>
#include <sa/tasks/ike_delete.h>
@@ -67,8 +63,8 @@
#include <processing/jobs/send_keepalive_job.h>
#include <processing/jobs/rekey_ike_sa_job.h>
-#ifdef P2P
-#include <sa/tasks/ike_p2p.h>
+#ifdef ME
+#include <sa/tasks/ike_me.h>
#include <processing/jobs/initiate_mediation_job.h>
#endif
@@ -122,6 +118,16 @@ struct private_ike_sa_t {
peer_cfg_t *peer_cfg;
/**
+ * associated authentication/authorization info for local peer
+ */
+ auth_info_t *my_auth;
+
+ /**
+ * associated authentication/authorization info for remote peer
+ */
+ auth_info_t *other_auth;
+
+ /**
* Juggles tasks to process messages
*/
task_manager_t *task_manager;
@@ -136,12 +142,22 @@ struct private_ike_sa_t {
*/
host_t *other_host;
-#ifdef P2P
+#ifdef ME
+ /**
+ * Are we mediation server
+ */
+ bool is_mediation_server;
+
/**
* Server reflexive host
*/
host_t *server_reflexive_host;
-#endif /* P2P */
+
+ /**
+ * Connect ID
+ */
+ chunk_t connect_id;
+#endif /* ME */
/**
* Identification used for us
@@ -154,11 +170,6 @@ struct private_ike_sa_t {
identification_t *other_id;
/**
- * CA that issued the certificate of other
- */
- ca_info_t *other_ca;
-
- /**
* set of extensions the peer supports
*/
ike_extension_t extensions;
@@ -174,6 +185,11 @@ struct private_ike_sa_t {
linked_list_t *child_sas;
/**
+ * String describing the selected IKE proposal
+ */
+ char *selected_proposal;
+
+ /**
* crypter for inbound traffic
*/
crypter_t *crypter_in;
@@ -390,6 +406,7 @@ static peer_cfg_t* get_peer_cfg(private_ike_sa_t *this)
*/
static void set_peer_cfg(private_ike_sa_t *this, peer_cfg_t *peer_cfg)
{
+ DESTROY_IF(this->peer_cfg);
peer_cfg->get_ref(peer_cfg);
this->peer_cfg = peer_cfg;
@@ -398,18 +415,6 @@ static void set_peer_cfg(private_ike_sa_t *this, peer_cfg_t *peer_cfg)
this->ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
this->ike_cfg->get_ref(this->ike_cfg);
}
-
- /* apply values, so we are ready to initate/acquire */
- if (this->my_host->is_anyaddr(this->my_host))
- {
- host_t *me = this->ike_cfg->get_my_host(this->ike_cfg);
- set_my_host(this, me->clone(me));
- }
- if (this->other_host->is_anyaddr(this->other_host))
- {
- host_t *other = this->ike_cfg->get_other_host(this->ike_cfg);
- set_other_host(this, other->clone(other));
- }
/* apply IDs if they are not already set */
if (this->my_id->contains_wildcards(this->my_id))
{
@@ -426,6 +431,22 @@ static void set_peer_cfg(private_ike_sa_t *this, peer_cfg_t *peer_cfg)
}
/**
+ * Implementation of ike_sa_t.get_my_auth.
+ */
+static auth_info_t* get_my_auth(private_ike_sa_t *this)
+{
+ return this->my_auth;
+}
+
+/**
+ * Implementation of ike_sa_t.get_other_auth.
+ */
+static auth_info_t* get_other_auth(private_ike_sa_t *this)
+{
+ return this->other_auth;
+}
+
+/**
* Implementation of ike_sa_t.send_keepalive
*/
static void send_keepalive(private_ike_sa_t *this)
@@ -480,6 +501,15 @@ static void set_ike_cfg(private_ike_sa_t *this, ike_cfg_t *ike_cfg)
ike_cfg->get_ref(ike_cfg);
this->ike_cfg = ike_cfg;
}
+
+/**
+ * Implementation of ike_sa_t.is_ike_initiator
+ */
+static bool is_ike_initiator(private_ike_sa_t *this)
+{
+ return this->ike_initiator;
+}
+
/**
* Implementation of ike_sa_t.enable_extension.
*/
@@ -562,7 +592,7 @@ static status_t send_dpd(private_ike_sa_t *this)
send_dpd_job_t *job;
time_t diff, delay;
- delay = this->peer_cfg->get_dpd_delay(this->peer_cfg);
+ delay = this->peer_cfg->get_dpd(this->peer_cfg);
if (delay == 0)
{
@@ -907,7 +937,17 @@ static void send_notify_response(private_ike_sa_t *this, message_t *request,
response->destroy(response);
}
-#ifdef P2P
+#ifdef ME
+/**
+ * Implementation of ike_sa_t.act_as_mediation_server.
+ */
+static void act_as_mediation_server(private_ike_sa_t *this)
+{
+ charon->mediation_manager->update_sa_id(charon->mediation_manager,
+ this->other_id, this->ike_sa_id);
+ this->is_mediation_server = TRUE;
+}
+
/**
* Implementation of ike_sa_t.get_server_reflexive_host.
*/
@@ -926,13 +966,21 @@ static void set_server_reflexive_host(private_ike_sa_t *this, host_t *host)
}
/**
+ * Implementation of ike_sa_t.get_connect_id.
+ */
+static chunk_t get_connect_id(private_ike_sa_t *this)
+{
+ return this->connect_id;
+}
+
+/**
* Implementation of ike_sa_t.respond
*/
static status_t respond(private_ike_sa_t *this, identification_t *peer_id,
- chunk_t session_id)
+ chunk_t connect_id)
{
- ike_p2p_t *task = ike_p2p_create(&this->public, TRUE);
- task->respond(task, peer_id, session_id);
+ ike_me_t *task = ike_me_create(&this->public, TRUE);
+ task->respond(task, peer_id, connect_id);
this->task_manager->queue_task(this->task_manager, (task_t*)task);
return this->task_manager->initiate(this->task_manager);
}
@@ -942,7 +990,7 @@ static status_t respond(private_ike_sa_t *this, identification_t *peer_id,
*/
static status_t callback(private_ike_sa_t *this, identification_t *peer_id)
{
- ike_p2p_t *task = ike_p2p_create(&this->public, TRUE);
+ ike_me_t *task = ike_me_create(&this->public, TRUE);
task->callback(task, peer_id);
this->task_manager->queue_task(this->task_manager, (task_t*)task);
return this->task_manager->initiate(this->task_manager);
@@ -952,10 +1000,10 @@ static status_t callback(private_ike_sa_t *this, identification_t *peer_id)
* Implementation of ike_sa_t.relay
*/
static status_t relay(private_ike_sa_t *this, identification_t *requester,
- chunk_t session_id, chunk_t session_key, linked_list_t *endpoints, bool response)
+ chunk_t connect_id, chunk_t connect_key, linked_list_t *endpoints, bool response)
{
- ike_p2p_t *task = ike_p2p_create(&this->public, TRUE);
- task->relay(task, requester, session_id, session_key, endpoints, response);
+ ike_me_t *task = ike_me_create(&this->public, TRUE);
+ task->relay(task, requester, connect_id, connect_key, endpoints, response);
this->task_manager->queue_task(this->task_manager, (task_t*)task);
return this->task_manager->initiate(this->task_manager);
}
@@ -965,7 +1013,7 @@ static status_t relay(private_ike_sa_t *this, identification_t *requester,
*/
static status_t initiate_mediation(private_ike_sa_t *this, peer_cfg_t *mediated_cfg)
{
- ike_p2p_t *task = ike_p2p_create(&this->public, TRUE);
+ ike_me_t *task = ike_me_create(&this->public, TRUE);
task->connect(task, mediated_cfg->get_peer_id(mediated_cfg));
this->task_manager->queue_task(this->task_manager, (task_t*)task);
return this->task_manager->initiate(this->task_manager);
@@ -975,37 +1023,54 @@ static status_t initiate_mediation(private_ike_sa_t *this, peer_cfg_t *mediated_
* Implementation of ike_sa_t.initiate_mediated
*/
static status_t initiate_mediated(private_ike_sa_t *this, host_t *me, host_t *other,
- linked_list_t *childs)
+ chunk_t connect_id)
{
- this->my_host = me->clone(me);
- this->other_host = other->clone(other);
+ set_my_host(this, me->clone(me));
+ set_other_host(this, other->clone(other));
+ chunk_free(&this->connect_id);
+ this->connect_id = chunk_clone(connect_id);
- task_t *task;
- child_cfg_t *child_cfg;
- iterator_t *iterator = childs->create_iterator(childs, TRUE);
- while (iterator->iterate(iterator, (void**)&child_cfg))
+ return this->task_manager->initiate(this->task_manager);
+}
+#endif /* ME */
+
+/**
+ * Resolve DNS host in configuration
+ */
+static void resolve_hosts(private_ike_sa_t *this)
+{
+ host_t *host;
+
+ host = host_create_from_dns(this->ike_cfg->get_my_addr(this->ike_cfg), 0,
+ IKEV2_UDP_PORT);
+ if (host)
{
- task = (task_t*)child_create_create(&this->public, child_cfg);
- this->task_manager->queue_task(this->task_manager, task);
+ set_my_host(this, host);
+ }
+ host = host_create_from_dns(this->ike_cfg->get_other_addr(this->ike_cfg),
+ this->my_host->get_family(this->my_host),
+ IKEV2_UDP_PORT);
+ if (host)
+ {
+ set_other_host(this, host);
}
- iterator->destroy(iterator);
- return this->task_manager->initiate(this->task_manager);
}
-#endif /* P2P */
/**
- * Implementation of ike_sa_t.initiate.
+ * Initiates a CHILD_SA using the appropriate reqid
*/
-static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
+static status_t initiate_with_reqid(private_ike_sa_t *this, child_cfg_t *child_cfg, u_int32_t reqid)
{
task_t *task;
if (this->state == IKE_CREATED)
{
+ resolve_hosts(this);
+
if (this->other_host->is_anyaddr(this->other_host)
-#ifdef P2P
+#ifdef ME
&& !this->peer_cfg->get_mediated_by(this->peer_cfg)
-#endif /* P2P */
+#endif /* ME */
)
{
child_cfg->destroy(child_cfg);
@@ -1020,10 +1085,12 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
this->task_manager->queue_task(this->task_manager, task);
task = (task_t*)ike_natd_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
- task = (task_t*)ike_cert_create(&this->public, TRUE);
+ task = (task_t*)ike_cert_pre_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
task = (task_t*)ike_auth_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
+ task = (task_t*)ike_cert_post_create(&this->public, TRUE);
+ this->task_manager->queue_task(this->task_manager, task);
task = (task_t*)ike_config_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
task = (task_t*)ike_auth_lifetime_create(&this->public, TRUE);
@@ -1033,50 +1100,65 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
task = (task_t*)ike_mobike_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
}
-#ifdef P2P
- task = (task_t*)ike_p2p_create(&this->public, TRUE);
+#ifdef ME
+ task = (task_t*)ike_me_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
-#endif /* P2P */
+#endif /* ME */
}
-#ifdef P2P
- if (this->peer_cfg->get_mediated_by(this->peer_cfg))
- {
- /* mediated connection, initiate mediation process */
- job_t *job = (job_t*)initiate_mediation_job_create(this->ike_sa_id, child_cfg);
- child_cfg->destroy(child_cfg);
- charon->processor->queue_job(charon->processor, job);
- return SUCCESS;
- }
- else if (this->peer_cfg->is_mediation(this->peer_cfg))
+#ifdef ME
+ if (this->peer_cfg->is_mediation(this->peer_cfg))
{
+ /* mediation connection */
if (this->state == IKE_ESTABLISHED)
{ /* FIXME: we should try to find a better solution to this */
SIG(CHILD_UP_SUCCESS, "mediation connection is already up and running");
}
+ DESTROY_IF(child_cfg);
}
else
-#endif /* P2P */
+#endif /* ME */
{
/* normal IKE_SA with CHILD_SA */
task = (task_t*)child_create_create(&this->public, child_cfg);
child_cfg->destroy(child_cfg);
+ if (reqid)
+ {
+ child_create_t *child_create = (child_create_t*)task;
+ child_create->use_reqid(child_create, reqid);
+ }
this->task_manager->queue_task(this->task_manager, task);
+
+#ifdef ME
+ if (this->peer_cfg->get_mediated_by(this->peer_cfg))
+ {
+ /* mediated connection, initiate mediation process */
+ job_t *job = (job_t*)initiate_mediation_job_create(this->ike_sa_id);
+ charon->processor->queue_job(charon->processor, job);
+ return SUCCESS;
+ }
+#endif /* ME */
}
return this->task_manager->initiate(this->task_manager);
}
/**
+ * Implementation of ike_sa_t.initiate.
+ */
+static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
+{
+ return initiate_with_reqid(this, child_cfg, 0);
+}
+
+/**
* Implementation of ike_sa_t.acquire.
*/
static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
-{ /* FIXME: P2P-NAT-T */
+{
child_cfg_t *child_cfg;
iterator_t *iterator;
child_sa_t *current, *child_sa = NULL;
- task_t *task;
- child_create_t *child_create;
if (this->state == IKE_DELETING)
{
@@ -1105,34 +1187,10 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
return FAILED;
}
-
- if (this->state == IKE_CREATED)
- {
- task = (task_t*)ike_init_create(&this->public, TRUE, NULL);
- this->task_manager->queue_task(this->task_manager, task);
- task = (task_t*)ike_natd_create(&this->public, TRUE);
- this->task_manager->queue_task(this->task_manager, task);
- task = (task_t*)ike_cert_create(&this->public, TRUE);
- this->task_manager->queue_task(this->task_manager, task);
- task = (task_t*)ike_auth_create(&this->public, TRUE);
- this->task_manager->queue_task(this->task_manager, task);
- task = (task_t*)ike_config_create(&this->public, TRUE);
- this->task_manager->queue_task(this->task_manager, task);
- task = (task_t*)ike_auth_lifetime_create(&this->public, TRUE);
- this->task_manager->queue_task(this->task_manager, task);
- if (this->peer_cfg->use_mobike(this->peer_cfg))
- {
- task = (task_t*)ike_mobike_create(&this->public, TRUE);
- this->task_manager->queue_task(this->task_manager, task);
- }
- }
-
child_cfg = child_sa->get_config(child_sa);
- child_create = child_create_create(&this->public, child_cfg);
- child_create->use_reqid(child_create, reqid);
- this->task_manager->queue_task(this->task_manager, (task_t*)child_create);
+ child_cfg->get_ref(child_cfg);
- return this->task_manager->initiate(this->task_manager);
+ return initiate_with_reqid(this, child_cfg, reqid);
}
/**
@@ -1175,10 +1233,12 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg)
default:
break;
}
+
+ resolve_hosts(this);
/* install kernel policies */
child_sa = child_sa_create(this->my_host, this->other_host, this->my_id,
- this->other_id, child_cfg, FALSE, 0);
+ this->other_id, child_cfg, 0, FALSE);
me = this->my_host;
if (this->my_virtual_ip)
{
@@ -1394,145 +1454,6 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
}
/**
- * Implementation of ike_sa_t.retransmit.
- */
-static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
-{ /* FIXME: P2P-NAT-T */
- this->time.outbound = time(NULL);
- if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
- {
- child_cfg_t *child_cfg;
- child_sa_t* child_sa;
- linked_list_t *to_route, *to_restart;
- iterator_t *iterator;
-
- /* send a proper signal to brief interested bus listeners */
- switch (this->state)
- {
- case IKE_CONNECTING:
- {
- /* retry IKE_SA_INIT if we have multiple keyingtries */
- u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg);
- this->keyingtry++;
- if (tries == 0 || tries > this->keyingtry)
- {
- SIG(IKE_UP_FAILED, "peer not responding, trying again "
- "(%d/%d) in background ", this->keyingtry + 1, tries);
- reset(this);
- return this->task_manager->initiate(this->task_manager);
- }
- SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding");
- break;
- }
- case IKE_REKEYING:
- SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding");
- break;
- case IKE_DELETING:
- SIG(IKE_DOWN_FAILED, "proper IKE_SA delete failed, peer not responding");
- break;
- default:
- break;
- }
-
- /* summarize how we have to handle each child */
- to_route = linked_list_create();
- to_restart = linked_list_create();
- iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
- while (iterator->iterate(iterator, (void**)&child_sa))
- {
- child_cfg = child_sa->get_config(child_sa);
-
- if (child_sa->get_state(child_sa) == CHILD_ROUTED)
- {
- /* reroute routed CHILD_SAs */
- to_route->insert_last(to_route, child_cfg);
- }
- else
- {
- /* use DPD action for established CHILD_SAs */
- switch (this->peer_cfg->get_dpd_action(this->peer_cfg))
- {
- case DPD_ROUTE:
- to_route->insert_last(to_route, child_cfg);
- break;
- case DPD_RESTART:
- to_restart->insert_last(to_restart, child_cfg);
- break;
- default:
- break;
- }
- }
- }
- iterator->destroy(iterator);
-
- /* create a new IKE_SA if we have to route or to restart */
- if (to_route->get_count(to_route) || to_restart->get_count(to_restart))
- {
- private_ike_sa_t *new;
- task_t *task;
-
- new = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new(
- charon->ike_sa_manager, TRUE);
-
- set_peer_cfg(new, this->peer_cfg);
- /* use actual used host, not the wildcarded one in config */
- new->other_host->destroy(new->other_host);
- new->other_host = this->other_host->clone(this->other_host);
- /* reset port to 500, but only if peer is not NATed */
- if (!has_condition(this, COND_NAT_THERE))
- {
- new->other_host->set_port(new->other_host, IKEV2_UDP_PORT);
- }
- /* take over virtual ip, as we need it for a proper route */
- if (this->my_virtual_ip)
- {
- set_virtual_ip(new, TRUE, this->my_virtual_ip);
- }
-
- /* install routes */
- while (to_route->remove_last(to_route, (void**)&child_cfg) == SUCCESS)
- {
- route(new, child_cfg);
- }
-
- /* restart children */
- if (to_restart->get_count(to_restart))
- {
- task = (task_t*)ike_init_create(&new->public, TRUE, NULL);
- new->task_manager->queue_task(new->task_manager, task);
- task = (task_t*)ike_natd_create(&new->public, TRUE);
- new->task_manager->queue_task(new->task_manager, task);
- task = (task_t*)ike_cert_create(&new->public, TRUE);
- new->task_manager->queue_task(new->task_manager, task);
- task = (task_t*)ike_config_create(&new->public, TRUE);
- new->task_manager->queue_task(new->task_manager, task);
- task = (task_t*)ike_auth_create(&new->public, TRUE);
- new->task_manager->queue_task(new->task_manager, task);
-
- while (to_restart->remove_last(to_restart, (void**)&child_cfg) == SUCCESS)
- {
- task = (task_t*)child_create_create(&new->public, child_cfg);
- new->task_manager->queue_task(new->task_manager, task);
- }
- task = (task_t*)ike_auth_lifetime_create(&new->public, TRUE);
- new->task_manager->queue_task(new->task_manager, task);
- if (this->peer_cfg->use_mobike(this->peer_cfg))
- {
- task = (task_t*)ike_mobike_create(&new->public, TRUE);
- new->task_manager->queue_task(new->task_manager, task);
- }
- new->task_manager->initiate(new->task_manager);
- }
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, &new->public);
- }
- to_route->destroy(to_route);
- to_restart->destroy(to_restart);
- return DESTROY_ME;
- }
- return SUCCESS;
-}
-
-/**
* Implementation of ike_sa_t.get_prf.
*/
static prf_t *get_prf(private_ike_sa_t *this)
@@ -1607,22 +1528,6 @@ static void set_other_id(private_ike_sa_t *this, identification_t *other)
}
/**
- * Implementation of ike_sa_t.get_other_ca.
- */
-static ca_info_t* get_other_ca(private_ike_sa_t *this)
-{
- return this->other_ca;
-}
-
-/**
- * Implementation of ike_sa_t.set_other_ca.
- */
-static void set_other_ca(private_ike_sa_t *this, ca_info_t *other_ca)
-{
- this->other_ca = other_ca;
-}
-
-/**
* Implementation of ike_sa_t.derive_keys.
*/
static status_t derive_keys(private_ike_sa_t *this,
@@ -1631,9 +1536,8 @@ static status_t derive_keys(private_ike_sa_t *this,
bool initiator, prf_t *child_prf, prf_t *old_prf)
{
prf_plus_t *prf_plus;
- chunk_t skeyseed, key, nonces, prf_plus_seed;
- algorithm_t *algo;
- size_t key_size;
+ chunk_t skeyseed, key, full_nonce, fixed_nonce, prf_plus_seed;
+ u_int16_t alg, key_size;
crypter_t *crypter_i, *crypter_r;
signer_t *signer_i, *signer_r;
u_int8_t spi_i_buf[sizeof(u_int64_t)], spi_r_buf[sizeof(u_int64_t)];
@@ -1641,24 +1545,42 @@ static status_t derive_keys(private_ike_sa_t *this,
chunk_t spi_r = chunk_from_buf(spi_r_buf);
/* Create SAs general purpose PRF first, we may use it here */
- if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo))
+ if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
{
- DBG1(DBG_IKE, "key derivation failed: no PSEUDO_RANDOM_FUNCTION");;
+ DBG1(DBG_IKE, "no %N selected",
+ transform_type_names, PSEUDO_RANDOM_FUNCTION);
return FAILED;
}
- this->prf = prf_create(algo->algorithm);
+ this->prf = lib->crypto->create_prf(lib->crypto, alg);
if (this->prf == NULL)
{
- DBG1(DBG_IKE, "key derivation failed: PSEUDO_RANDOM_FUNCTION "
- "%N not supported!", pseudo_random_function_names, algo->algorithm);
+ DBG1(DBG_IKE, "%N %N not supported!",
+ transform_type_names, PSEUDO_RANDOM_FUNCTION,
+ pseudo_random_function_names, alg);
return FAILED;
}
-
DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret);
- nonces = chunk_cat("cc", nonce_i, nonce_r);
+ /* full nonce is used as seed for PRF+ ... */
+ full_nonce = chunk_cat("cc", nonce_i, nonce_r);
+ /* but the PRF may need a fixed key which only uses the first bytes of
+ * the nonces. */
+ switch (alg)
+ {
+ case PRF_AES128_XCBC:
+ /* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does
+ * not and therefore fixed key semantics apply to XCBC for key
+ * derivation. */
+ nonce_i.len = min(nonce_i.len, this->prf->get_key_size(this->prf)/2);
+ nonce_r.len = min(nonce_r.len, this->prf->get_key_size(this->prf)/2);
+ break;
+ default:
+ /* all other algorithms use variable key length, full nonce */
+ break;
+ }
+ fixed_nonce = chunk_cat("cc", nonce_i, nonce_r);
*((u_int64_t*)spi_i.ptr) = this->ike_sa_id->get_initiator_spi(this->ike_sa_id);
*((u_int64_t*)spi_r.ptr) = this->ike_sa_id->get_responder_spi(this->ike_sa_id);
- prf_plus_seed = chunk_cat("ccc", nonces, spi_i, spi_r);
+ prf_plus_seed = chunk_cat("ccc", full_nonce, spi_i, spi_r);
/* KEYMAT = prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr)
*
@@ -1667,7 +1589,7 @@ static status_t derive_keys(private_ike_sa_t *this,
if (child_prf == NULL) /* not rekeying */
{
/* SKEYSEED = prf(Ni | Nr, g^ir) */
- this->prf->set_key(this->prf, nonces);
+ this->prf->set_key(this->prf, fixed_nonce);
this->prf->allocate_bytes(this->prf, secret, &skeyseed);
DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
this->prf->set_key(this->prf, skeyseed);
@@ -1679,7 +1601,7 @@ static status_t derive_keys(private_ike_sa_t *this,
{
/* SKEYSEED = prf(SK_d (old), [g^ir (new)] | Ni | Nr)
* use OLD SAs PRF functions for both prf_plus and prf */
- secret = chunk_cat("mc", secret, nonces);
+ secret = chunk_cat("mc", secret, full_nonce);
child_prf->allocate_bytes(child_prf, secret, &skeyseed);
DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
old_prf->set_key(old_prf, skeyseed);
@@ -1687,14 +1609,15 @@ static status_t derive_keys(private_ike_sa_t *this,
chunk_free(&secret);
prf_plus = prf_plus_create(old_prf, prf_plus_seed);
}
- chunk_free(&nonces);
+ chunk_free(&full_nonce);
+ chunk_free(&fixed_nonce);
chunk_free(&prf_plus_seed);
/* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */
/* SK_d is used for generating CHILD_SA key mat => child_prf */
- proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo);
- this->child_prf = prf_create(algo->algorithm);
+ proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL);
+ this->child_prf = lib->crypto->create_prf(lib->crypto, alg);
key_size = this->child_prf->get_key_size(this->child_prf);
prf_plus->allocate_bytes(prf_plus, key_size, &key);
DBG4(DBG_IKE, "Sk_d secret %B", &key);
@@ -1702,17 +1625,20 @@ static status_t derive_keys(private_ike_sa_t *this,
chunk_free(&key);
/* SK_ai/SK_ar used for integrity protection => signer_in/signer_out */
- if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &algo))
+ if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL))
{
- DBG1(DBG_IKE, "key derivation failed: no INTEGRITY_ALGORITHM");
+ DBG1(DBG_IKE, "no %N selected",
+ transform_type_names, INTEGRITY_ALGORITHM);
return FAILED;
}
- signer_i = signer_create(algo->algorithm);
- signer_r = signer_create(algo->algorithm);
+ signer_i = lib->crypto->create_signer(lib->crypto, alg);
+ signer_r = lib->crypto->create_signer(lib->crypto, alg);
if (signer_i == NULL || signer_r == NULL)
{
- DBG1(DBG_IKE, "key derivation failed: INTEGRITY_ALGORITHM "
- "%N not supported!", integrity_algorithm_names ,algo->algorithm);
+ DBG1(DBG_IKE, "%N %N not supported!",
+ transform_type_names, INTEGRITY_ALGORITHM,
+ integrity_algorithm_names ,alg);
+ prf_plus->destroy(prf_plus);
return FAILED;
}
key_size = signer_i->get_key_size(signer_i);
@@ -1739,18 +1665,21 @@ static status_t derive_keys(private_ike_sa_t *this,
}
/* SK_ei/SK_er used for encryption => crypter_in/crypter_out */
- if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &algo))
+ if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &key_size))
{
- DBG1(DBG_IKE, "key derivation failed: no ENCRYPTION_ALGORITHM");
+ DBG1(DBG_IKE, "no %N selected",
+ transform_type_names, ENCRYPTION_ALGORITHM);
+ prf_plus->destroy(prf_plus);
return FAILED;
}
- crypter_i = crypter_create(algo->algorithm, algo->key_size / 8);
- crypter_r = crypter_create(algo->algorithm, algo->key_size / 8);
+ crypter_i = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
+ crypter_r = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
if (crypter_i == NULL || crypter_r == NULL)
{
- DBG1(DBG_IKE, "key derivation failed: ENCRYPTION_ALGORITHM "
- "%N (key size %d) not supported!",
- encryption_algorithm_names, algo->algorithm, algo->key_size);
+ DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
+ transform_type_names, ENCRYPTION_ALGORITHM,
+ encryption_algorithm_names, alg, key_size);
+ prf_plus->destroy(prf_plus);
return FAILED;
}
key_size = crypter_i->get_key_size(crypter_i);
@@ -1806,6 +1735,23 @@ static status_t derive_keys(private_ike_sa_t *this,
}
/**
+ * Implementation of ike_sa_t.get_proposal.
+ */
+static char* get_proposal(private_ike_sa_t *this)
+{
+ return this->selected_proposal;
+}
+
+/**
+ * Implementation of ike_sa_t.set_proposal.
+ */
+static void set_proposal(private_ike_sa_t *this, char *proposal)
+{
+ free(this->selected_proposal);
+ this->selected_proposal = strdup(proposal);
+}
+
+/**
* Implementation of ike_sa_t.add_child_sa.
*/
static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa)
@@ -1944,9 +1890,9 @@ static status_t rekey(private_ike_sa_t *this)
}
/**
- * Implementation of ike_sa_t.reestablish
+ * Implementation of ike_sa_t.reauth
*/
-static status_t reestablish(private_ike_sa_t *this)
+static status_t reauth(private_ike_sa_t *this)
{
task_t *task;
@@ -1957,7 +1903,12 @@ static status_t reestablish(private_ike_sa_t *this)
{
DBG1(DBG_IKE, "initiator did not reauthenticate as requested");
if (this->other_virtual_ip != NULL ||
- has_condition(this, COND_EAP_AUTHENTICATED))
+ has_condition(this, COND_EAP_AUTHENTICATED)
+#ifdef ME
+ /* if we are mediation server we too cannot reauth the IKE_SA */
+ || this->is_mediation_server
+#endif /* ME */
+ )
{
time_t now = time(NULL);
@@ -1976,6 +1927,176 @@ static status_t reestablish(private_ike_sa_t *this)
}
/**
+ * Implementation of ike_sa_t.reestablish
+ */
+static status_t reestablish(private_ike_sa_t *this)
+{
+ ike_sa_t *new;
+ host_t *host;
+ action_t action;
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+ child_cfg_t *child_cfg;
+ bool required = FALSE;
+ status_t status = FAILED;
+
+ /* check if we have children to keep up at all*/
+ iterator = create_child_sa_iterator(this);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ child_cfg = child_sa->get_config(child_sa);
+ if (this->state == IKE_DELETING)
+ {
+ action = child_cfg->get_close_action(child_cfg);
+ }
+ else
+ {
+ action = child_cfg->get_dpd_action(child_cfg);
+ }
+ switch (action)
+ {
+ case ACTION_RESTART:
+ case ACTION_ROUTE:
+ required = TRUE;
+ default:
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+#ifdef ME
+ /* we initiate the new IKE_SA of the mediation connection without CHILD_SA */
+ if (this->peer_cfg->is_mediation(this->peer_cfg))
+ {
+ required = TRUE;
+ }
+#endif /* ME */
+ if (!required)
+ {
+ return FAILED;
+ }
+
+ /* check if we are able to reestablish this IKE_SA */
+ if (!this->ike_initiator &&
+ (this->other_virtual_ip != NULL ||
+ has_condition(this, COND_EAP_AUTHENTICATED)
+#ifdef ME
+ || this->is_mediation_server
+#endif /* ME */
+ ))
+ {
+ DBG1(DBG_IKE, "unable to reestablish IKE_SA due asymetric setup");
+ return FAILED;
+ }
+
+ new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE);
+ new->set_peer_cfg(new, this->peer_cfg);
+ host = this->other_host;
+ new->set_other_host(new, host->clone(host));
+ host = this->my_host;
+ new->set_my_host(new, host->clone(host));
+ /* if we already have a virtual IP, we reuse it */
+ host = this->my_virtual_ip;
+ if (host)
+ {
+ new->set_virtual_ip(new, TRUE, host);
+ }
+
+#ifdef ME
+ if (this->peer_cfg->is_mediation(this->peer_cfg))
+ {
+ status = new->initiate(new, NULL);
+ }
+ else
+#endif /* ME */
+ {
+ iterator = create_child_sa_iterator(this);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ child_cfg = child_sa->get_config(child_sa);
+ if (this->state == IKE_DELETING)
+ {
+ action = child_cfg->get_close_action(child_cfg);
+ }
+ else
+ {
+ action = child_cfg->get_dpd_action(child_cfg);
+ }
+ switch (action)
+ {
+ case ACTION_RESTART:
+ DBG1(DBG_IKE, "restarting CHILD_SA %s",
+ child_cfg->get_name(child_cfg));
+ child_cfg->get_ref(child_cfg);
+ status = new->initiate(new, child_cfg);
+ break;
+ case ACTION_ROUTE:
+ status = new->route(new, child_cfg);
+ break;
+ default:
+ continue;
+ }
+ if (status == DESTROY_ME)
+ {
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ }
+
+ if (status == DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, new);
+ return FAILED;
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, new);
+ return SUCCESS;
+ }
+}
+
+/**
+ * Implementation of ike_sa_t.retransmit.
+ */
+static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
+{
+ this->time.outbound = time(NULL);
+ if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
+ {
+ /* send a proper signal to brief interested bus listeners */
+ switch (this->state)
+ {
+ case IKE_CONNECTING:
+ {
+ /* retry IKE_SA_INIT if we have multiple keyingtries */
+ u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg);
+ this->keyingtry++;
+ if (tries == 0 || tries > this->keyingtry)
+ {
+ SIG(IKE_UP_FAILED, "peer not responding, trying again "
+ "(%d/%d) in background ", this->keyingtry + 1, tries);
+ reset(this);
+ return this->task_manager->initiate(this->task_manager);
+ }
+ SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding");
+ break;
+ }
+ case IKE_DELETING:
+ SIG(IKE_DOWN_FAILED, "proper IKE_SA delete failed, peer not responding");
+ break;
+ case IKE_REKEYING:
+ SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding");
+ /* FALL */
+ default:
+ reestablish(this);
+ break;
+ }
+ return DESTROY_ME;
+ }
+ return SUCCESS;
+}
+
+/**
* Implementation of ike_sa_t.set_auth_lifetime.
*/
static void set_auth_lifetime(private_ike_sa_t *this, u_int32_t lifetime)
@@ -2009,6 +2130,14 @@ static status_t roam(private_ike_sa_t *this, bool address)
host_t *me, *other;
ike_mobike_t *mobike;
+ switch (this->state)
+ {
+ case IKE_CREATED:
+ case IKE_DELETING:
+ return SUCCESS;
+ default:
+ break;
+ }
/* responder just updates the peer about changed address config */
if (!this->ike_sa_id->is_initiator(this->ike_sa_id))
{
@@ -2048,9 +2177,9 @@ static status_t roam(private_ike_sa_t *this, bool address)
this->task_manager->queue_task(this->task_manager, (task_t*)mobike);
return this->task_manager->initiate(this->task_manager);
}
- DBG1(DBG_IKE, "reestablishing IKE_SA due address change");
- /* ... reestablish if not */
- return reestablish(this);
+ DBG1(DBG_IKE, "reauthenticating IKE_SA due address change");
+ /* ... reauth if not */
+ return reauth(this);
}
/**
@@ -2097,6 +2226,18 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other)
{
send_keepalive(this);
}
+
+#ifdef ME
+ if (other->is_mediation_server)
+ {
+ act_as_mediation_server(this);
+ }
+ else if (other->server_reflexive_host)
+ {
+ this->server_reflexive_host = other->server_reflexive_host->clone(
+ other->server_reflexive_host);
+ }
+#endif /* ME */
/* adopt all children */
while (other->child_sas->remove_last(other->child_sas,
@@ -2270,6 +2411,8 @@ static void destroy(private_ike_sa_t *this)
{
this->child_sas->destroy_offset(this->child_sas, offsetof(child_sa_t, destroy));
+ this->task_manager->destroy(this->task_manager);
+
DESTROY_IF(this->crypter_in);
DESTROY_IF(this->crypter_out);
DESTROY_IF(this->signer_in);
@@ -2278,6 +2421,7 @@ static void destroy(private_ike_sa_t *this)
DESTROY_IF(this->child_prf);
chunk_free(&this->skp_verify);
chunk_free(&this->skp_build);
+ free(this->selected_proposal);
if (this->my_virtual_ip)
{
@@ -2285,22 +2429,30 @@ static void destroy(private_ike_sa_t *this)
this->my_virtual_ip);
this->my_virtual_ip->destroy(this->my_virtual_ip);
}
- DESTROY_IF(this->other_virtual_ip);
+ if (this->other_virtual_ip)
+ {
+ if (this->peer_cfg && this->peer_cfg->get_pool(this->peer_cfg))
+ {
+ charon->attributes->release_address(charon->attributes,
+ this->peer_cfg->get_pool(this->peer_cfg),
+ this->other_virtual_ip);
+ }
+ this->other_virtual_ip->destroy(this->other_virtual_ip);
+ }
remove_dns_servers(this);
this->dns_servers->destroy_offset(this->dns_servers,
offsetof(host_t, destroy));
this->additional_addresses->destroy_offset(this->additional_addresses,
offsetof(host_t, destroy));
-#ifdef P2P
- if (this->peer_cfg && this->peer_cfg->is_mediation(this->peer_cfg) &&
- !this->ike_sa_id->is_initiator(this->ike_sa_id))
+#ifdef ME
+ if (this->is_mediation_server)
{
- /* mediation server */
charon->mediation_manager->remove(charon->mediation_manager, this->ike_sa_id);
}
DESTROY_IF(this->server_reflexive_host);
-#endif /* P2P */
+ chunk_free(&this->connect_id);
+#endif /* ME */
DESTROY_IF(this->my_host);
DESTROY_IF(this->other_host);
@@ -2309,9 +2461,10 @@ static void destroy(private_ike_sa_t *this)
DESTROY_IF(this->ike_cfg);
DESTROY_IF(this->peer_cfg);
+ DESTROY_IF(this->my_auth);
+ DESTROY_IF(this->other_auth);
this->ike_sa_id->destroy(this->ike_sa_id);
- this->task_manager->destroy(this->task_manager);
free(this);
}
@@ -2337,6 +2490,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->public.set_ike_cfg = (void (*)(ike_sa_t*,ike_cfg_t*))set_ike_cfg;
this->public.get_peer_cfg = (peer_cfg_t* (*)(ike_sa_t*))get_peer_cfg;
this->public.set_peer_cfg = (void (*)(ike_sa_t*,peer_cfg_t*))set_peer_cfg;
+ this->public.get_my_auth = (auth_info_t*(*)(ike_sa_t*))get_my_auth;
+ this->public.get_other_auth = (auth_info_t*(*)(ike_sa_t*))get_other_auth;
this->public.get_id = (ike_sa_id_t* (*)(ike_sa_t*)) get_id;
this->public.get_my_host = (host_t* (*)(ike_sa_t*)) get_my_host;
this->public.set_my_host = (void (*)(ike_sa_t*,host_t*)) set_my_host;
@@ -2347,14 +2502,13 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->public.set_my_id = (void (*)(ike_sa_t*,identification_t*)) set_my_id;
this->public.get_other_id = (identification_t* (*)(ike_sa_t*)) get_other_id;
this->public.set_other_id = (void (*)(ike_sa_t*,identification_t*)) set_other_id;
- this->public.get_other_ca = (ca_info_t* (*)(ike_sa_t*)) get_other_ca;
- this->public.set_other_ca = (void (*)(ike_sa_t*,ca_info_t*)) set_other_ca;
this->public.enable_extension = (void(*)(ike_sa_t*, ike_extension_t extension))enable_extension;
this->public.supports_extension = (bool(*)(ike_sa_t*, ike_extension_t extension))supports_extension;
this->public.set_condition = (void (*)(ike_sa_t*, ike_condition_t,bool)) set_condition;
this->public.has_condition = (bool (*)(ike_sa_t*,ike_condition_t)) has_condition;
this->public.set_pending_updates = (void(*)(ike_sa_t*, u_int32_t updates))set_pending_updates;
this->public.get_pending_updates = (u_int32_t(*)(ike_sa_t*))get_pending_updates;
+ this->public.is_ike_initiator = (bool (*)(ike_sa_t*))is_ike_initiator;
this->public.create_additional_address_iterator = (iterator_t*(*)(ike_sa_t*))create_additional_address_iterator;
this->public.add_additional_address = (void(*)(ike_sa_t*, host_t *host))add_additional_address;
this->public.retransmit = (status_t (*)(ike_sa_t *, u_int32_t)) retransmit;
@@ -2367,6 +2521,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->public.get_skp_verify = (chunk_t (*)(ike_sa_t *)) get_skp_verify;
this->public.get_skp_build = (chunk_t (*)(ike_sa_t *)) get_skp_build;
this->public.derive_keys = (status_t (*)(ike_sa_t *,proposal_t*,chunk_t,chunk_t,chunk_t,bool,prf_t*,prf_t*)) derive_keys;
+ this->public.get_proposal = (char* (*)(ike_sa_t*)) get_proposal;
+ this->public.set_proposal = (void (*)(ike_sa_t*,char*)) set_proposal;
this->public.add_child_sa = (void (*)(ike_sa_t*,child_sa_t*)) add_child_sa;
this->public.get_child_sa = (child_sa_t* (*)(ike_sa_t*,protocol_id_t,u_int32_t,bool)) get_child_sa;
this->public.create_child_sa_iterator = (iterator_t* (*)(ike_sa_t*)) create_child_sa_iterator;
@@ -2374,6 +2530,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->public.delete_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t)) delete_child_sa;
this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa;
this->public.rekey = (status_t (*)(ike_sa_t*))rekey;
+ this->public.reauth = (status_t (*)(ike_sa_t*))reauth;
this->public.reestablish = (status_t (*)(ike_sa_t*))reestablish;
this->public.set_auth_lifetime = (void(*)(ike_sa_t*, u_int32_t lifetime))set_auth_lifetime;
this->public.roam = (status_t(*)(ike_sa_t*,bool))roam;
@@ -2384,26 +2541,28 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->public.set_virtual_ip = (void (*)(ike_sa_t*,bool,host_t*))set_virtual_ip;
this->public.get_virtual_ip = (host_t* (*)(ike_sa_t*,bool))get_virtual_ip;
this->public.add_dns_server = (void (*)(ike_sa_t*,host_t*))add_dns_server;
-#ifdef P2P
+#ifdef ME
+ this->public.act_as_mediation_server = (void (*)(ike_sa_t*)) act_as_mediation_server;
this->public.get_server_reflexive_host = (host_t* (*)(ike_sa_t*)) get_server_reflexive_host;
this->public.set_server_reflexive_host = (void (*)(ike_sa_t*,host_t*)) set_server_reflexive_host;
+ this->public.get_connect_id = (chunk_t (*)(ike_sa_t*)) get_connect_id;
this->public.initiate_mediation = (status_t (*)(ike_sa_t*,peer_cfg_t*)) initiate_mediation;
- this->public.initiate_mediated = (status_t (*)(ike_sa_t*,host_t*,host_t*,linked_list_t*)) initiate_mediated;
+ this->public.initiate_mediated = (status_t (*)(ike_sa_t*,host_t*,host_t*,chunk_t)) initiate_mediated;
this->public.relay = (status_t (*)(ike_sa_t*,identification_t*,chunk_t,chunk_t,linked_list_t*,bool)) relay;
this->public.callback = (status_t (*)(ike_sa_t*,identification_t*)) callback;
this->public.respond = (status_t (*)(ike_sa_t*,identification_t*,chunk_t)) respond;
-#endif /* P2P */
+#endif /* ME */
/* initialize private fields */
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
this->child_sas = linked_list_create();
- this->my_host = host_create_any(AF_INET);
- this->other_host = host_create_any(AF_INET);
+ this->my_host = host_create_from_string("0.0.0.0", IKEV2_UDP_PORT);
+ this->other_host = host_create_from_string("0.0.0.0", IKEV2_UDP_PORT);
this->my_id = identification_create_from_encoding(ID_ANY, chunk_empty);
this->other_id = identification_create_from_encoding(ID_ANY, chunk_empty);
- this->other_ca = NULL;
this->extensions = 0;
this->conditions = 0;
+ this->selected_proposal = NULL;
this->crypter_in = NULL;
this->crypter_out = NULL;
this->signer_in = NULL;
@@ -2420,6 +2579,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->time.delete = 0;
this->ike_cfg = NULL;
this->peer_cfg = NULL;
+ this->my_auth = auth_info_create();
+ this->other_auth = auth_info_create();
this->task_manager = task_manager_create(&this->public);
this->unique_id = ++unique_id;
this->my_virtual_ip = NULL;
@@ -2429,9 +2590,11 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->pending_updates = 0;
this->keyingtry = 0;
this->ike_initiator = FALSE;
-#ifdef P2P
+#ifdef ME
+ this->is_mediation_server = FALSE;
this->server_reflexive_host = NULL;
-#endif /* P2P */
+ this->connect_id = chunk_empty;
+#endif /* ME */
return &this->public;
}
diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h
index 975447d9c..0935f5d6b 100644
--- a/src/charon/sa/ike_sa.h
+++ b/src/charon/sa/ike_sa.h
@@ -1,12 +1,5 @@
-/**
- * @file ike_sa.h
- *
- * @brief Interface of ike_sa_t.
- *
- */
-
/*
- * Copyright (C) 2006-2007 Tobias Brunner
+ * Copyright (C) 2006-2008 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -21,6 +14,13 @@
* 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.
+ *
+ * $Id: ike_sa.h 4086 2008-06-22 11:24:33Z andreas $
+ */
+
+/**
+ * @defgroup ike_sa ike_sa
+ * @{ @ingroup sa
*/
#ifndef IKE_SA_H_
@@ -38,44 +38,35 @@ typedef struct ike_sa_t ike_sa_t;
#include <sa/ike_sa_id.h>
#include <sa/child_sa.h>
#include <sa/tasks/task.h>
-#include <utils/randomizer.h>
#include <crypto/prfs/prf.h>
#include <crypto/crypters/crypter.h>
#include <crypto/signers/signer.h>
-#include <crypto/ca.h>
#include <config/peer_cfg.h>
#include <config/ike_cfg.h>
+#include <credentials/auth_info.h>
/**
* Timeout in milliseconds after that a half open IKE_SA gets deleted.
- *
- * @ingroup sa
*/
#define HALF_OPEN_IKE_SA_TIMEOUT 30000
/**
* Interval to send keepalives when NATed, in seconds.
- *
- * @ingroup sa
*/
#define KEEPALIVE_INTERVAL 20
/**
* After which time rekeying should be retried if it failed, in seconds.
- *
- * @ingroup sa
*/
#define RETRY_INTERVAL 30
/**
* Jitter to subtract from RETRY_INTERVAL to randomize rekey retry.
- *
- * @ingroup sa
*/
#define RETRY_JITTER 20
/**
- * @brief Extensions (or optional features) the peer supports
+ * Extensions (or optional features) the peer supports
*/
enum ike_extension_t {
@@ -88,10 +79,15 @@ enum ike_extension_t {
* peer supports MOBIKE (RFC4555)
*/
EXT_MOBIKE = (1<<1),
+
+ /**
+ * peer supports HTTP cert lookups as specified in RFC4306
+ */
+ EXT_HASH_AND_URL = (1<<2),
};
/**
- * @brief Conditions of an IKE_SA, change during its lifetime
+ * Conditions of an IKE_SA, change during its lifetime
*/
enum ike_condition_t {
@@ -119,6 +115,11 @@ enum ike_condition_t {
* peer has ben authenticated using EAP
*/
COND_EAP_AUTHENTICATED = (1<<4),
+
+ /**
+ * received a certificate request from the peer
+ */
+ COND_CERTREQ_SEEN = (1<<5),
};
/**
@@ -138,7 +139,7 @@ enum statistic_t {
};
/**
- * @brief State of an IKE_SA.
+ * State of an IKE_SA.
*
* An IKE_SA passes various states in its lifetime. A newly created
* SA is in the state CREATED.
@@ -173,8 +174,6 @@ enum statistic_t {
X
/ \
@endverbatim
- *
- * @ingroup sa
*/
enum ike_sa_state_t {
@@ -210,365 +209,342 @@ enum ike_sa_state_t {
extern enum_name_t *ike_sa_state_names;
/**
- * @brief Class ike_sa_t representing an IKE_SA.
+ * Class ike_sa_t representing an IKE_SA.
*
* An IKE_SA contains crypto information related to a connection
* with a peer. It contains multiple IPsec CHILD_SA, for which
* it is responsible. All traffic is handled by an IKE_SA, using
* the task manager and its tasks.
- *
- * @b Constructors:
- * - ike_sa_create()
- *
- * @ingroup sa
*/
struct ike_sa_t {
/**
- * @brief Get the id of the SA.
+ * Get the id of the SA.
*
* Returned ike_sa_id_t object is not getting cloned!
*
- * @param this calling object
* @return ike_sa's ike_sa_id_t
*/
ike_sa_id_t* (*get_id) (ike_sa_t *this);
/**
- * @brief Get the numerical ID uniquely defining this IKE_SA.
+ * Get the numerical ID uniquely defining this IKE_SA.
*
- * @param this calling object
* @return unique ID
*/
u_int32_t (*get_unique_id) (ike_sa_t *this);
/**
- * @brief Get the state of the IKE_SA.
+ * Get the state of the IKE_SA.
*
- * @param this calling object
* @return state of the IKE_SA
*/
ike_sa_state_t (*get_state) (ike_sa_t *this);
/**
- * @brief Set the state of the IKE_SA.
+ * Set the state of the IKE_SA.
*
- * @param this calling object
* @param state state to set for the IKE_SA
*/
void (*set_state) (ike_sa_t *this, ike_sa_state_t ike_sa);
/**
- * @brief Get the name of the connection this IKE_SA uses.
+ * Get the name of the connection this IKE_SA uses.
*
- * @param this calling object
* @return name
*/
char* (*get_name) (ike_sa_t *this);
/**
- * @brief Get statistic values from the IKE_SA.
+ * Get statistic values from the IKE_SA.
*
- * @param this calling object
* @param kind kind of requested value
* @return value as integer
*/
u_int32_t (*get_statistic)(ike_sa_t *this, statistic_t kind);
/**
- * @brief Get the own host address.
+ * Get the own host address.
*
- * @param this calling object
* @return host address
*/
host_t* (*get_my_host) (ike_sa_t *this);
/**
- * @brief Set the own host address.
+ * Set the own host address.
*
- * @param this calling object
* @param me host address
*/
void (*set_my_host) (ike_sa_t *this, host_t *me);
/**
- * @brief Get the other peers host address.
+ * Get the other peers host address.
*
- * @param this calling object
* @return host address
*/
host_t* (*get_other_host) (ike_sa_t *this);
/**
- * @brief Set the others host address.
+ * Set the others host address.
*
- * @param this calling object
* @param other host address
*/
void (*set_other_host) (ike_sa_t *this, host_t *other);
/**
- * @brief Update the IKE_SAs host.
+ * Update the IKE_SAs host.
*
* Hosts may be NULL to use current host.
*
- * @param this calling object
* @param me new local host address, or NULL
* @param other new remote host address, or NULL
*/
void (*update_hosts)(ike_sa_t *this, host_t *me, host_t *other);
/**
- * @brief Get the own identification.
+ * Get the own identification.
*
- * @param this calling object
* @return identification
*/
identification_t* (*get_my_id) (ike_sa_t *this);
/**
- * @brief Set the own identification.
+ * Set the own identification.
*
- * @param this calling object
* @param me identification
*/
void (*set_my_id) (ike_sa_t *this, identification_t *me);
/**
- * @brief Get the other peer's identification.
+ * Get the other peer's identification.
*
- * @param this calling object
* @return identification
*/
identification_t* (*get_other_id) (ike_sa_t *this);
/**
- * @brief Set the other peer's identification.
+ * Set the other peer's identification.
*
- * @param this calling object
* @param other identification
*/
void (*set_other_id) (ike_sa_t *this, identification_t *other);
/**
- * @brief Get the other peer's certification authority
+ * Get the config used to setup this IKE_SA.
*
- * @param this calling object
- * @return ca_info_t record of other ca
- */
- ca_info_t* (*get_other_ca) (ike_sa_t *this);
-
- /**
- * @brief Set the other peer's certification authority
- *
- * @param this calling object
- * @param other_ca ca_info_t record of other ca
- */
- void (*set_other_ca) (ike_sa_t *this, ca_info_t *other_ca);
-
- /**
- * @brief Get the config used to setup this IKE_SA.
- *
- * @param this calling object
* @return ike_config
*/
ike_cfg_t* (*get_ike_cfg) (ike_sa_t *this);
/**
- * @brief Set the config to setup this IKE_SA.
+ * Set the config to setup this IKE_SA.
*
- * @param this calling object
* @param config ike_config to use
*/
void (*set_ike_cfg) (ike_sa_t *this, ike_cfg_t* config);
/**
- * @brief Get the peer config used by this IKE_SA.
+ * Get the peer config used by this IKE_SA.
*
- * @param this calling object
* @return peer_config
*/
peer_cfg_t* (*get_peer_cfg) (ike_sa_t *this);
/**
- * @brief Set the peer config to use with this IKE_SA.
+ * Set the peer config to use with this IKE_SA.
*
- * @param this calling object
* @param config peer_config to use
*/
void (*set_peer_cfg) (ike_sa_t *this, peer_cfg_t *config);
/**
- * @brief Add an additional address for the peer.
+ * Get authentication/authorization info for local peer.
+ *
+ * @return auth_info for me
+ */
+ auth_info_t* (*get_my_auth)(ike_sa_t *this);
+
+ /**
+ * Get authentication/authorization info for remote peer.
+ *
+ * @return auth_info for me
+ */
+ auth_info_t* (*get_other_auth)(ike_sa_t *this);
+
+ /**
+ * Add an additional address for the peer.
*
* In MOBIKE, a peer may transmit additional addresses where it is
* reachable. These are stored in the IKE_SA.
* The own list of addresses is not stored, they are queried from
* the kernel when required.
*
- * @param this calling object
* @param host host to add to list
*/
void (*add_additional_address)(ike_sa_t *this, host_t *host);
/**
- * @brief Create an iterator over all additional addresses of the peer.
+ * Create an iterator over all additional addresses of the peer.
*
- * @param this calling object
* @return iterator over addresses
*/
iterator_t* (*create_additional_address_iterator)(ike_sa_t *this);
/**
- * @brief Enable an extension the peer supports.
+ * Enable an extension the peer supports.
*
* If support for an IKE extension is detected, this method is called
* to enable that extension and behave accordingly.
*
- * @param this calling object
* @param extension extension to enable
*/
void (*enable_extension)(ike_sa_t *this, ike_extension_t extension);
/**
- * @brief Check if the peer supports an extension.
+ * Check if the peer supports an extension.
*
- * @param this calling object
* @param extension extension to check for support
* @return TRUE if peer supports it, FALSE otherwise
*/
bool (*supports_extension)(ike_sa_t *this, ike_extension_t extension);
/**
- * @brief Enable/disable a condition flag for this IKE_SA.
+ * Enable/disable a condition flag for this IKE_SA.
*
- * @param this calling object
* @param condition condition to enable/disable
* @param enable TRUE to enable condition, FALSE to disable
*/
void (*set_condition) (ike_sa_t *this, ike_condition_t condition, bool enable);
/**
- * @brief Check if a condition flag is set.
+ * Check if a condition flag is set.
*
- * @param this calling object
* @param condition condition to check
* @return TRUE if condition flag set, FALSE otherwise
*/
bool (*has_condition) (ike_sa_t *this, ike_condition_t condition);
/**
- * @brief Get the number of queued MOBIKE address updates.
+ * Get the number of queued MOBIKE address updates.
*
- * @param this calling object
* @return number of pending updates
*/
u_int32_t (*get_pending_updates)(ike_sa_t *this);
/**
- * @brief Set the number of queued MOBIKE address updates.
+ * Set the number of queued MOBIKE address updates.
*
- * @param this calling object
* @param updates number of pending updates
*/
void (*set_pending_updates)(ike_sa_t *this, u_int32_t updates);
+
+ /**
+ * Check if we are the original initiator of this IKE_SA (rekeying does not
+ * change this flag).
+ */
+ bool (*is_ike_initiator)(ike_sa_t *this);
+
-#ifdef P2P
+#ifdef ME
/**
- * @brief Get the server reflexive host.
+ * Activate mediation server functionality for this IKE_SA.
+ */
+ void (*act_as_mediation_server) (ike_sa_t *this);
+
+ /**
+ * Get the server reflexive host.
*
- * @param this calling object
* @return server reflexive host
*/
host_t* (*get_server_reflexive_host) (ike_sa_t *this);
/**
- * @brief Set the server reflexive host.
+ * Set the server reflexive host.
*
- * @param this calling object
* @param host server reflexive host
*/
void (*set_server_reflexive_host) (ike_sa_t *this, host_t *host);
/**
- * @brief Initiate the mediation of a mediated connection (i.e. initiate a
- * P2P_CONNECT exchange).
+ * Get the connect ID.
+ *
+ * @return connect ID
+ */
+ chunk_t (*get_connect_id) (ike_sa_t *this);
+
+ /**
+ * Initiate the mediation of a mediated connection (i.e. initiate a
+ * ME_CONNECT exchange).
*
- * @param this calling object
* @param mediated_cfg peer_cfg of the mediated connection
* @return
- * - SUCCESS if initialization started
- * - DESTROY_ME if initialization failed
+ * - SUCCESS if initialization started
+ * - DESTROY_ME if initialization failed
*/
status_t (*initiate_mediation) (ike_sa_t *this, peer_cfg_t *mediated_cfg);
/**
- * @brief Initiate the mediated connection
+ * Initiate the mediated connection
*
- * @param this calling object
* @param me local endpoint (gets cloned)
* @param other remote endpoint (gets cloned)
- * @param childs linked list of child_cfg_t of CHILD_SAs (gets cloned)
+ * @param connect_id connect ID (gets cloned)
* @return
- * - SUCCESS if initialization started
- * - DESTROY_ME if initialization failed
+ * - SUCCESS if initialization started
+ * - DESTROY_ME if initialization failed
*/
status_t (*initiate_mediated) (ike_sa_t *this, host_t *me, host_t *other,
- linked_list_t *childs);
+ chunk_t connect_id);
/**
- * @brief Relay data from one peer to another (i.e. initiate a
- * P2P_CONNECT exchange).
+ * Relay data from one peer to another (i.e. initiate a
+ * ME_CONNECT exchange).
*
* Data is cloned.
*
- * @param this calling object
* @param requester ID of the requesting peer
- * @param session_id data of the P2P_SESSIONID payload
- * @param session_key data of the P2P_SESSIONKEY payload
+ * @param connect_id data of the ME_CONNECTID payload
+ * @param connect_key data of the ME_CONNECTKEY payload
* @param endpoints endpoints
* @param response TRUE if this is a response
* @return
- * - SUCCESS if relay started
- * - DESTROY_ME if relay failed
+ * - SUCCESS if relay started
+ * - DESTROY_ME if relay failed
*/
- status_t (*relay) (ike_sa_t *this, identification_t *requester, chunk_t session_id,
- chunk_t session_key, linked_list_t *endpoints, bool response);
+ status_t (*relay) (ike_sa_t *this, identification_t *requester, chunk_t connect_id,
+ chunk_t connect_key, linked_list_t *endpoints, bool response);
/**
- * @brief Send a callback to a peer.
+ * Send a callback to a peer.
*
* Data is cloned.
*
- * @param this calling object
* @param peer_id ID of the other peer
* @return
- * - SUCCESS if response started
- * - DESTROY_ME if response failed
+ * - SUCCESS if response started
+ * - DESTROY_ME if response failed
*/
status_t (*callback) (ike_sa_t *this, identification_t *peer_id);
/**
- * @brief Respond to a P2P_CONNECT request.
+ * Respond to a ME_CONNECT request.
*
* Data is cloned.
*
- * @param this calling object
* @param peer_id ID of the other peer
- * @param session_id the session ID supplied by the initiator
+ * @param connect_id the connect ID supplied by the initiator
* @return
- * - SUCCESS if response started
- * - DESTROY_ME if response failed
+ * - SUCCESS if response started
+ * - DESTROY_ME if response failed
*/
- status_t (*respond) (ike_sa_t *this, identification_t *peer_id, chunk_t session_id);
-#endif /* P2P */
+ status_t (*respond) (ike_sa_t *this, identification_t *peer_id, chunk_t connect_id);
+#endif /* ME */
/**
- * @brief Initiate a new connection.
+ * Initiate a new connection.
*
* The configs are owned by the IKE_SA after the call.
*
- * @param this calling object
* @param child_cfg child config to create CHILD from
* @return
* - SUCCESS if initialization started
@@ -577,12 +553,11 @@ struct ike_sa_t {
status_t (*initiate) (ike_sa_t *this, child_cfg_t *child_cfg);
/**
- * @brief Route a policy in the kernel.
+ * Route a policy in the kernel.
*
* Installs the policies in the kernel. If traffic matches,
* the kernel requests connection setup from the IKE_SA via acquire().
*
- * @param this calling object
* @param child_cfg child config to route
* @return
* - SUCCESS if routed successfully
@@ -591,9 +566,8 @@ struct ike_sa_t {
status_t (*route) (ike_sa_t *this, child_cfg_t *child_cfg);
/**
- * @brief Unroute a policy in the kernel previously routed.
+ * Unroute a policy in the kernel previously routed.
*
- * @param this calling object
* @param reqid reqid of CHILD_SA to unroute
* @return
* - SUCCESS if route removed
@@ -603,12 +577,11 @@ struct ike_sa_t {
status_t (*unroute) (ike_sa_t *this, u_int32_t reqid);
/**
- * @brief Acquire connection setup for an installed kernel policy.
+ * Acquire connection setup for an installed kernel policy.
*
* If an installed policy raises an acquire, the kernel calls
* this function to establish the CHILD_SA (and maybe the IKE_SA).
*
- * @param this calling object
* @param reqid reqid of the CHILD_SA the policy belongs to.
* @return
* - SUCCESS if initialization started
@@ -617,13 +590,12 @@ struct ike_sa_t {
status_t (*acquire) (ike_sa_t *this, u_int32_t reqid);
/**
- * @brief Initiates the deletion of an IKE_SA.
+ * Initiates the deletion of an IKE_SA.
*
* Sends a delete message to the remote peer and waits for
* its response. If the response comes in, or a timeout occurs,
* the IKE SA gets deleted.
*
- * @param this calling object
* @return
* - SUCCESS if deletion is initialized
* - INVALID_STATE, if the IKE_SA is not in
@@ -633,7 +605,7 @@ struct ike_sa_t {
status_t (*delete) (ike_sa_t *this);
/**
- * @brief Update IKE_SAs after network interfaces have changed.
+ * Update IKE_SAs after network interfaces have changed.
*
* Whenever the network interface configuration changes, the kernel
* interface calls roam() on each IKE_SA. The IKE_SA then checks if
@@ -641,21 +613,19 @@ struct ike_sa_t {
* If MOBIKE is supported, addresses are updated; If not, the tunnel is
* restarted.
*
- * @param this calling object
* @param address TRUE if address list changed, FALSE otherwise
* @return SUCCESS, FAILED, DESTROY_ME
*/
status_t (*roam)(ike_sa_t *this, bool address);
/**
- * @brief Processes a incoming IKEv2-Message.
+ * Processes a incoming IKEv2-Message.
*
* Message processing may fail. If a critical failure occurs,
* process_message() return DESTROY_ME. Then the caller must
* destroy the IKE_SA immediatly, as it is unusable.
*
- * @param this calling object
- * @param message message to process
+ * @param message message to process
* @return
* - SUCCESS
* - FAILED
@@ -664,12 +634,11 @@ struct ike_sa_t {
status_t (*process_message) (ike_sa_t *this, message_t *message);
/**
- * @brief Generate a IKE message to send it to the peer.
+ * Generate a IKE message to send it to the peer.
*
* This method generates all payloads in the message and encrypts/signs
* the packet.
*
- * @param this calling object
* @param message message to generate
* @param packet generated output packet
* @return
@@ -681,9 +650,8 @@ struct ike_sa_t {
packet_t **packet);
/**
- * @brief Retransmits a request.
+ * Retransmits a request.
*
- * @param this calling object
* @param message_id ID of the request to retransmit
* @return
* - SUCCESS
@@ -692,13 +660,12 @@ struct ike_sa_t {
status_t (*retransmit) (ike_sa_t *this, u_int32_t message_id);
/**
- * @brief Sends a DPD request to the peer.
+ * Sends a DPD request to the peer.
*
* To check if a peer is still alive, periodic
* empty INFORMATIONAL messages are sent if no
* other traffic was received.
*
- * @param this calling object
* @return
* - SUCCESS
* - DESTROY_ME, if peer did not respond
@@ -706,19 +673,17 @@ struct ike_sa_t {
status_t (*send_dpd) (ike_sa_t *this);
/**
- * @brief Sends a keep alive packet.
+ * Sends a keep alive packet.
*
* To refresh NAT tables in a NAT router
* between the peers, periodic empty
* UDP packets are sent if no other traffic
* was sent.
- *
- * @param this calling object
*/
void (*send_keepalive) (ike_sa_t *this);
/**
- * @brief Derive all keys and create the transforms for IKE communication.
+ * Derive all keys and create the transforms for IKE communication.
*
* Keys are derived using the diffie hellman secret, nonces and internal
* stored SPIs.
@@ -726,7 +691,6 @@ struct ike_sa_t {
* existing IKE_SA (rekeying). The SK_d key from the old IKE_SA
* is included in the derivation process.
*
- * @param this calling object
* @param proposal proposal which contains algorithms to use
* @param secret secret derived from DH exchange, gets freed
* @param nonce_i initiators nonce
@@ -740,49 +704,58 @@ struct ike_sa_t {
bool initiator, prf_t *child_prf, prf_t *old_prf);
/**
- * @brief Get a multi purpose prf for the negotiated PRF function.
+ * Get the selected IKE proposal string
+ *
+ * @return string describing the selected IKE proposal
+ */
+ char* (*get_proposal)(ike_sa_t *this);
+
+ /**
+ * Set the selected IKE proposal string for status information purposes
+ * (the "%P" printf format handler is used)
+ *
+ * @param proposal string describing the selected IKE proposal
+ */
+ void (*set_proposal)(ike_sa_t *this, char *proposal);
+
+ /**
+ * Get a multi purpose prf for the negotiated PRF function.
*
- * @param this calling object
* @return pointer to prf_t object
*/
prf_t *(*get_prf) (ike_sa_t *this);
/**
- * @brief Get the prf-object, which is used to derive keys for child SAs.
+ * Get the prf-object, which is used to derive keys for child SAs.
*
- * @param this calling object
* @return pointer to prf_t object
*/
prf_t *(*get_child_prf) (ike_sa_t *this);
/**
- * @brief Get the key to build outgoing authentication data.
+ * Get the key to build outgoing authentication data.
*
- * @param this calling object
* @return pointer to prf_t object
*/
chunk_t (*get_skp_build) (ike_sa_t *this);
/**
- * @brief Get the key to verify incoming authentication data.
+ * Get the key to verify incoming authentication data.
*
- * @param this calling object
* @return pointer to prf_t object
*/
chunk_t (*get_skp_verify) (ike_sa_t *this);
/**
- * @brief Associates a child SA to this IKE SA
+ * Associates a child SA to this IKE SA
*
- * @param this calling object
* @param child_sa child_sa to add
*/
void (*add_child_sa) (ike_sa_t *this, child_sa_t *child_sa);
/**
- * @brief Get a CHILD_SA identified by protocol and SPI.
+ * Get a CHILD_SA identified by protocol and SPI.
*
- * @param this calling object
* @param protocol protocol of the SA
* @param spi SPI of the CHILD_SA
* @param inbound TRUE if SPI is inbound, FALSE if outbound
@@ -792,19 +765,17 @@ struct ike_sa_t {
u_int32_t spi, bool inbound);
/**
- * @brief Create an iterator over all CHILD_SAs.
+ * Create an iterator over all CHILD_SAs.
*
- * @param this calling object
* @return iterator
*/
iterator_t* (*create_child_sa_iterator) (ike_sa_t *this);
/**
- * @brief Rekey the CHILD SA with the specified reqid.
+ * Rekey the CHILD SA with the specified reqid.
*
* Looks for a CHILD SA owned by this IKE_SA, and start the rekeing.
*
- * @param this calling object
* @param protocol protocol of the SA
* @param spi inbound SPI of the CHILD_SA
* @return
@@ -814,13 +785,12 @@ struct ike_sa_t {
status_t (*rekey_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi);
/**
- * @brief Close the CHILD SA with the specified protocol/SPI.
+ * Close the CHILD SA with the specified protocol/SPI.
*
* Looks for a CHILD SA owned by this IKE_SA, deletes it and
* notify's the remote peer about the delete. The associated
* states and policies in the kernel get deleted, if they exist.
*
- * @param this calling object
* @param protocol protocol of the SA
* @param spi inbound SPI of the CHILD_SA
* @return
@@ -830,11 +800,10 @@ struct ike_sa_t {
status_t (*delete_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi);
/**
- * @brief Destroy a CHILD SA with the specified protocol/SPI.
+ * Destroy a CHILD SA with the specified protocol/SPI.
*
* Looks for a CHILD SA owned by this IKE_SA and destroys it.
*
- * @param this calling object
* @param protocol protocol of the SA
* @param spi inbound SPI of the CHILD_SA
* @return
@@ -844,99 +813,98 @@ struct ike_sa_t {
status_t (*destroy_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi);
/**
- * @brief Rekey the IKE_SA.
+ * Rekey the IKE_SA.
*
* Sets up a new IKE_SA, moves all CHILDs to it and deletes this IKE_SA.
*
- * @param this calling object
* @return - SUCCESS, if IKE_SA rekeying initiated
*/
status_t (*rekey) (ike_sa_t *this);
/**
- * @brief Restablish the IKE_SA.
+ * Reauthenticate the IKE_SA.
*
* Create a completely new IKE_SA with authentication, recreates all children
* within the IKE_SA, closes this IKE_SA.
*
- * @param this calling object
+ * @return DESTROY_ME to destroy the IKE_SA
+ */
+ status_t (*reauth) (ike_sa_t *this);
+
+ /**
+ * Restablish the IKE_SA.
+ *
+ * Reestablish an IKE_SA after it has been closed.
+ *
* @return DESTROY_ME to destroy the IKE_SA
*/
status_t (*reestablish) (ike_sa_t *this);
/**
- * @brief Set the lifetime limit received from a AUTH_LIFETIME notify.
+ * Set the lifetime limit received from a AUTH_LIFETIME notify.
*
- * @param this calling object
* @param lifetime lifetime in seconds
*/
void (*set_auth_lifetime)(ike_sa_t *this, u_int32_t lifetime);
/**
- * @brief Set the virtual IP to use for this IKE_SA and its children.
+ * Set the virtual IP to use for this IKE_SA and its children.
*
* The virtual IP is assigned per IKE_SA, not per CHILD_SA. It has the same
* lifetime as the IKE_SA.
*
- * @param this calling object
+ * @param local TRUE to set local address, FALSE for remote
+ * @param ip IP to set as virtual IP
*/
void (*set_virtual_ip) (ike_sa_t *this, bool local, host_t *ip);
/**
- * @brief Get the virtual IP configured.
+ * Get the virtual IP configured.
*
- * @param this calling object
* @param local TRUE to get local virtual IP, FALSE for remote
+ * @return host_t *virtual IP
*/
host_t* (*get_virtual_ip) (ike_sa_t *this, bool local);
/**
- * @brief Add a DNS server to the system.
+ * Add a DNS server to the system.
*
* An IRAS may send a DNS server. To use it, it is installed on the
* system. The DNS entry has a lifetime until the IKE_SA gets closed.
*
- * @param this calling object
* @param dns DNS server to install on the system
*/
void (*add_dns_server) (ike_sa_t *this, host_t *dns);
/**
- * @brief Inherit all attributes of other to this after rekeying.
+ * Inherit all attributes of other to this after rekeying.
*
* When rekeying is completed, all CHILD_SAs, the virtual IP and all
* outstanding tasks are moved from other to this.
* As this call may initiate inherited tasks, a status is returned.
*
- * @param this calling object
* @param other other task to inherit from
* @return DESTROY_ME if initiation of inherited task failed
*/
status_t (*inherit) (ike_sa_t *this, ike_sa_t *other);
/**
- * @brief Reset the IKE_SA, useable when initiating fails
- *
- * @param this calling object
+ * Reset the IKE_SA, useable when initiating fails
*/
void (*reset) (ike_sa_t *this);
/**
- * @brief Destroys a ike_sa_t object.
- *
- * @param this calling object
+ * Destroys a ike_sa_t object.
*/
void (*destroy) (ike_sa_t *this);
};
/**
- * @brief Creates an ike_sa_t object with a specific ID.
+ * Creates an ike_sa_t object with a specific ID.
*
* @param ike_sa_id ike_sa_id_t object to associate with new IKE_SA
* @return ike_sa_t object
- *
- * @ingroup sa
*/
ike_sa_t *ike_sa_create(ike_sa_id_t *ike_sa_id);
-#endif /* IKE_SA_H_ */
+#endif /* IKE_SA_H_ @} */
diff --git a/src/charon/sa/ike_sa_id.c b/src/charon/sa/ike_sa_id.c
index a838c0b8a..e012d5944 100644
--- a/src/charon/sa/ike_sa_id.c
+++ b/src/charon/sa/ike_sa_id.c
@@ -1,10 +1,3 @@
-/**
- * @file ike_sa_id.c
- *
- * @brief Implementation of ike_sa_id_t.
- *
- */
-
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -19,9 +12,10 @@
* 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.
+ *
+ * $Id: ike_sa_id.c 3589 2008-03-13 14:14:44Z martin $
*/
-
#include "ike_sa_id.h"
#include <stdio.h>
diff --git a/src/charon/sa/ike_sa_id.h b/src/charon/sa/ike_sa_id.h
index 0606b7222..652c968b6 100644
--- a/src/charon/sa/ike_sa_id.h
+++ b/src/charon/sa/ike_sa_id.h
@@ -1,10 +1,3 @@
-/**
- * @file ike_sa_id.h
- *
- * @brief Interface of ike_sa_id_t.
- *
- */
-
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -19,8 +12,14 @@
* 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.
+ *
+ * $Id: ike_sa_id.h 3589 2008-03-13 14:14:44Z martin $
*/
+/**
+ * @defgroup ike_sa_id ike_sa_id
+ * @{ @ingroup sa
+ */
#ifndef IKE_SA_ID_H_
#define IKE_SA_ID_H_
@@ -29,119 +28,101 @@ typedef struct ike_sa_id_t ike_sa_id_t;
#include <library.h>
-
/**
- * @brief An object of type ike_sa_id_t is used to identify an IKE_SA.
+ * An object of type ike_sa_id_t is used to identify an IKE_SA.
*
* An IKE_SA is identified by its initiator and responder spi's.
* Additionaly it contains the role of the actual running IKEv2-Daemon
* for the specific IKE_SA (original initiator or responder).
- *
- * @b Constructors:
- * - ike_sa_id_create()
- *
- * @ingroup sa
*/
struct ike_sa_id_t {
/**
- * @brief Set the SPI of the responder.
+ * Set the SPI of the responder.
*
* This function is called when a request or reply of a IKE_SA_INIT is received.
*
- * @param this calling object
* @param responder_spi SPI of responder to set
*/
void (*set_responder_spi) (ike_sa_id_t *this, u_int64_t responder_spi);
/**
- * @brief Set the SPI of the initiator.
+ * Set the SPI of the initiator.
*
- * @param this calling object
* @param initiator_spi SPI to set
*/
void (*set_initiator_spi) (ike_sa_id_t *this, u_int64_t initiator_spi);
/**
- * @brief Get the initiator SPI.
+ * Get the initiator SPI.
*
- * @param this calling object
* @return SPI of the initiator
*/
u_int64_t (*get_initiator_spi) (ike_sa_id_t *this);
/**
- * @brief Get the responder SPI.
+ * Get the responder SPI.
*
- * @param this calling object
* @return SPI of the responder
*/
u_int64_t (*get_responder_spi) (ike_sa_id_t *this);
/**
- * @brief Check if two ike_sa_id_t objects are equal.
+ * Check if two ike_sa_id_t objects are equal.
*
* Two ike_sa_id_t objects are equal if both SPI values and the role matches.
*
- * @param this calling object
* @param other ike_sa_id_t object to check if equal
* @return TRUE if given ike_sa_id_t are equal, FALSE otherwise
*/
bool (*equals) (ike_sa_id_t *this, ike_sa_id_t *other);
/**
- * @brief Replace all values of a given ike_sa_id_t object with values.
+ * Replace all values of a given ike_sa_id_t object with values.
* from another ike_sa_id_t object.
*
* After calling this function, both objects are equal.
*
- * @param this calling object
* @param other ike_sa_id_t object from which values will be taken
*/
void (*replace_values) (ike_sa_id_t *this, ike_sa_id_t *other);
/**
- * @brief Get the initiator flag.
+ * Get the initiator flag.
*
- * @param this calling object
* @return TRUE if we are the original initator
*/
bool (*is_initiator) (ike_sa_id_t *this);
/**
- * @brief Switche the original initiator flag.
+ * Switche the original initiator flag.
*
- * @param this calling object
* @return TRUE if we are the original initator after switch, FALSE otherwise
*/
bool (*switch_initiator) (ike_sa_id_t *this);
/**
- * @brief Clones a given ike_sa_id_t object.
+ * Clones a given ike_sa_id_t object.
*
- * @param this calling object
* @return cloned ike_sa_id_t object
*/
ike_sa_id_t *(*clone) (ike_sa_id_t *this);
/**
- * @brief Destroys an ike_sa_id_t object.
- *
- * @param this calling object
+ * Destroys an ike_sa_id_t object.
*/
void (*destroy) (ike_sa_id_t *this);
};
/**
- * @brief Creates an ike_sa_id_t object with specific SPI's and defined role.
+ * Creates an ike_sa_id_t object with specific SPI's and defined role.
*
* @param initiator_spi initiators SPI
* @param responder_spi responders SPI
* @param is_initiaor TRUE if we are the original initiator
* @return ike_sa_id_t object
- *
- * @ingroup sa
*/
-ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi, bool is_initiaor);
+ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi,
+ bool is_initiaor);
-#endif /*IKE_SA_ID_H_*/
+#endif /*IKE_SA_ID_H_ @} */
diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c
index 5e7f78af0..9c1b2d413 100644
--- a/src/charon/sa/ike_sa_manager.c
+++ b/src/charon/sa/ike_sa_manager.c
@@ -1,10 +1,3 @@
-/**
- * @file ike_sa_manager.c
- *
- * @brief Implementation of ike_sa_mananger_t.
- *
- */
-
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -19,6 +12,8 @@
* 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.
+ *
+ * $Id: ike_sa_manager.c 4044 2008-06-06 15:05:54Z martin $
*/
#include <pthread.h>
@@ -30,6 +25,7 @@
#include <sa/ike_sa_id.h>
#include <bus/bus.h>
#include <utils/linked_list.h>
+#include <crypto/hashers/hasher.h>
typedef struct entry_t entry_t;
@@ -79,6 +75,11 @@ struct entry_t {
chunk_t init_hash;
/**
+ * remote host address, required for DoS detection
+ */
+ host_t *other;
+
+ /**
* message ID currently processing, if any
*/
u_int32_t message_id;
@@ -93,6 +94,7 @@ static status_t entry_destroy(entry_t *this)
this->ike_sa->destroy(this->ike_sa);
this->ike_sa_id->destroy(this->ike_sa_id);
chunk_free(&this->init_hash);
+ DESTROY_IF(this->other);
free(this);
return SUCCESS;
}
@@ -113,6 +115,7 @@ static entry_t *entry_create(ike_sa_id_t *ike_sa_id)
this->driveout_waiting_threads = FALSE;
this->message_id = -1;
this->init_hash = chunk_empty;
+ this->other = NULL;
/* ike_sa_id is always cloned */
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
@@ -146,9 +149,9 @@ struct private_ike_sa_manager_t {
linked_list_t *ike_sa_list;
/**
- * A randomizer, to get random SPIs for our side
+ * RNG to get random SPIs for our side
*/
- randomizer_t *randomizer;
+ rng_t *rng;
/**
* SHA1 hasher for IKE_SA_INIT retransmit detection
@@ -159,20 +162,20 @@ struct private_ike_sa_manager_t {
/**
* Implementation of private_ike_sa_manager_t.get_entry_by_id.
*/
-static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, entry_t **entry)
+static status_t get_entry_by_id(private_ike_sa_manager_t *this,
+ ike_sa_id_t *ike_sa_id, entry_t **entry)
{
- linked_list_t *list = this->ike_sa_list;
- iterator_t *iterator;
+ enumerator_t *enumerator;
entry_t *current;
status_t status;
- /* create iterator over list of ike_sa's */
- iterator = list->create_iterator(list, TRUE);
+ /* create enumerator over list of ike_sa's */
+ enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
/* default status */
status = NOT_FOUND;
- while (iterator->iterate(iterator, (void**)&current))
+ while (enumerator->enumerate(enumerator, &current))
{
if (current->ike_sa_id->equals(current->ike_sa_id, ike_sa_id))
{
@@ -198,26 +201,26 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike
}
}
- iterator->destroy(iterator);
+ enumerator->destroy(enumerator);
return status;
}
/**
* Implementation of private_ike_sa_manager_t.get_entry_by_sa.
*/
-static status_t get_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa, entry_t **entry)
+static status_t get_entry_by_sa(private_ike_sa_manager_t *this,
+ ike_sa_t *ike_sa, entry_t **entry)
{
- linked_list_t *list = this->ike_sa_list;
- iterator_t *iterator;
+ enumerator_t *enumerator;
entry_t *current;
status_t status;
- iterator = list->create_iterator(list, TRUE);
+ enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
/* default status */
status = NOT_FOUND;
- while (iterator->iterate(iterator, (void**)&current))
+ while (enumerator->enumerate(enumerator, &current))
{
/* only pointers are compared */
if (current->ike_sa == ike_sa)
@@ -228,7 +231,7 @@ static status_t get_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa
break;
}
}
- iterator->destroy(iterator);
+ enumerator->destroy(enumerator);
return status;
}
@@ -238,16 +241,15 @@ static status_t get_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa
*/
static status_t delete_entry(private_ike_sa_manager_t *this, entry_t *entry)
{
- linked_list_t *list = this->ike_sa_list;
- iterator_t *iterator;
+ enumerator_t *enumerator;
entry_t *current;
status_t status;
- iterator = list->create_iterator(list, TRUE);
+ enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
status = NOT_FOUND;
- while (iterator->iterate(iterator, (void**)&current))
+ while (enumerator->enumerate(enumerator, &current))
{
if (current == entry)
{
@@ -263,13 +265,13 @@ static status_t delete_entry(private_ike_sa_manager_t *this, entry_t *entry)
}
DBG2(DBG_MGR, "found entry by pointer, deleting it");
- iterator->remove(iterator);
+ this->ike_sa_list->remove_at(this->ike_sa_list, enumerator);
entry_destroy(entry);
status = SUCCESS;
break;
}
}
- iterator->destroy(iterator);
+ enumerator->destroy(enumerator);
return status;
}
@@ -309,8 +311,7 @@ static u_int64_t get_next_spi(private_ike_sa_manager_t *this)
{
u_int64_t spi;
- this->randomizer->get_pseudo_random_bytes(this->randomizer, sizeof(spi),
- (u_int8_t*)&spi);
+ this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi);
return spi;
}
@@ -386,7 +387,7 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this,
message->get_exchange_type(message) == IKE_SA_INIT)
{
/* IKE_SA_INIT request. Check for an IKE_SA with such a message hash. */
- iterator_t *iterator;
+ enumerator_t *enumerator;
chunk_t data, hash;
data = message->get_packet_data(message);
@@ -394,14 +395,14 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this,
chunk_free(&data);
pthread_mutex_lock(&this->mutex);
- iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
- while (iterator->iterate(iterator, (void**)&entry))
+ enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
+ while (enumerator->enumerate(enumerator, &entry))
{
if (chunk_equals(hash, entry->init_hash))
{
if (entry->message_id == 0)
{
- iterator->destroy(iterator);
+ enumerator->destroy(enumerator);
pthread_mutex_unlock(&this->mutex);
chunk_free(&hash);
id->destroy(id);
@@ -418,7 +419,7 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this,
break;
}
}
- iterator->destroy(iterator);
+ enumerator->destroy(enumerator);
pthread_mutex_unlock(&this->mutex);
if (ike_sa == NULL)
@@ -488,7 +489,7 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this,
static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this,
peer_cfg_t *peer_cfg)
{
- iterator_t *iterator;
+ enumerator_t *enumerator;
entry_t *entry;
ike_sa_t *ike_sa = NULL;
identification_t *my_id, *other_id;
@@ -496,65 +497,70 @@ static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this,
ike_cfg_t *ike_cfg;
ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
- my_host = ike_cfg->get_my_host(ike_cfg);
- other_host = ike_cfg->get_other_host(ike_cfg);
my_id = peer_cfg->get_my_id(peer_cfg);
other_id = peer_cfg->get_other_id(peer_cfg);
+ my_host = host_create_from_dns(ike_cfg->get_my_addr(ike_cfg), 0, 0);
+ other_host = host_create_from_dns(ike_cfg->get_other_addr(ike_cfg), 0, 0);
pthread_mutex_lock(&(this->mutex));
- iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
- while (iterator->iterate(iterator, (void**)&entry))
+ if (my_host && other_host)
{
- identification_t *found_my_id, *found_other_id;
- host_t *found_my_host, *found_other_host;
- int wc;
-
- if (!wait_for_entry(this, entry))
+ enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
+ while (enumerator->enumerate(enumerator, &entry))
{
- continue;
- }
+ identification_t *found_my_id, *found_other_id;
+ host_t *found_my_host, *found_other_host;
- if (entry->ike_sa->get_state(entry->ike_sa) == IKE_DELETING)
- {
- /* skip IKE_SA which are not useable */
- continue;
- }
+ if (!wait_for_entry(this, entry))
+ {
+ continue;
+ }
- found_my_id = entry->ike_sa->get_my_id(entry->ike_sa);
- found_other_id = entry->ike_sa->get_other_id(entry->ike_sa);
- found_my_host = entry->ike_sa->get_my_host(entry->ike_sa);
- found_other_host = entry->ike_sa->get_other_host(entry->ike_sa);
+ if (entry->ike_sa->get_state(entry->ike_sa) == IKE_DELETING)
+ {
+ /* skip IKE_SA which are not useable */
+ continue;
+ }
- if (found_my_id->get_type(found_my_id) == ID_ANY &&
- found_other_id->get_type(found_other_id) == ID_ANY)
- {
- /* IKE_SA has no IDs yet, so we can't use it */
- continue;
- }
- DBG2(DBG_MGR, "candidate IKE_SA for \n\t%H[%D]...%H[%D]\n\t%H[%D]...%H[%D]",
- my_host, my_id, other_host, other_id,
- found_my_host, found_my_id, found_other_host, found_other_id);
- /* compare ID and hosts. Supplied ID may contain wildcards, and IP
- * may be %any. */
- if ((my_host->is_anyaddr(my_host) ||
- my_host->ip_equals(my_host, found_my_host)) &&
- (other_host->is_anyaddr(other_host) ||
- other_host->ip_equals(other_host, found_other_host)) &&
- found_my_id->matches(found_my_id, my_id, &wc) &&
- found_other_id->matches(found_other_id, other_id, &wc) &&
- streq(peer_cfg->get_name(peer_cfg),
- entry->ike_sa->get_name(entry->ike_sa)))
- {
- /* looks good, we take this one */
- DBG2(DBG_MGR, "found an existing IKE_SA for %H[%D]...%H[%D]",
- my_host, my_id, other_host, other_id);
- entry->checked_out = TRUE;
- ike_sa = entry->ike_sa;
- break;
+ found_my_id = entry->ike_sa->get_my_id(entry->ike_sa);
+ found_other_id = entry->ike_sa->get_other_id(entry->ike_sa);
+ found_my_host = entry->ike_sa->get_my_host(entry->ike_sa);
+ found_other_host = entry->ike_sa->get_other_host(entry->ike_sa);
+
+ if (found_my_id->get_type(found_my_id) == ID_ANY &&
+ found_other_id->get_type(found_other_id) == ID_ANY)
+ {
+ /* IKE_SA has no IDs yet, so we can't use it */
+ continue;
+ }
+ DBG2(DBG_MGR, "candidate IKE_SA for \n\t"
+ "%H[%D]...%H[%D]\n\t%H[%D]...%H[%D]",
+ my_host, my_id, other_host, other_id,
+ found_my_host, found_my_id, found_other_host, found_other_id);
+ /* compare ID and hosts. Supplied ID may contain wildcards, and IP
+ * may be %any. */
+ if ((my_host->is_anyaddr(my_host) ||
+ my_host->ip_equals(my_host, found_my_host)) &&
+ (other_host->is_anyaddr(other_host) ||
+ other_host->ip_equals(other_host, found_other_host)) &&
+ found_my_id->matches(found_my_id, my_id) &&
+ found_other_id->matches(found_other_id, other_id) &&
+ streq(peer_cfg->get_name(peer_cfg),
+ entry->ike_sa->get_name(entry->ike_sa)))
+ {
+ /* looks good, we take this one */
+ DBG2(DBG_MGR, "found an existing IKE_SA for %H[%D]...%H[%D]",
+ my_host, my_id, other_host, other_id);
+ entry->checked_out = TRUE;
+ ike_sa = entry->ike_sa;
+ break;
+ }
}
+ enumerator->destroy(enumerator);
}
- iterator->destroy(iterator);
+ DESTROY_IF(my_host);
+ DESTROY_IF(other_host);
if (!ike_sa)
{
@@ -589,15 +595,16 @@ static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this,
static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id,
bool child)
{
- iterator_t *iterator, *children;
+ enumerator_t *enumerator;
+ iterator_t *children;
entry_t *entry;
ike_sa_t *ike_sa = NULL;
child_sa_t *child_sa;
pthread_mutex_lock(&(this->mutex));
- iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
- while (iterator->iterate(iterator, (void**)&entry))
+ enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
+ while (enumerator->enumerate(enumerator, &entry))
{
if (wait_for_entry(this, entry))
{
@@ -630,7 +637,7 @@ static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id,
}
}
}
- iterator->destroy(iterator);
+ enumerator->destroy(enumerator);
pthread_mutex_unlock(&(this->mutex));
charon->bus->set_sa(charon->bus, ike_sa);
@@ -643,15 +650,16 @@ static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id,
static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name,
bool child)
{
- iterator_t *iterator, *children;
+ enumerator_t *enumerator;
+ iterator_t *children;
entry_t *entry;
ike_sa_t *ike_sa = NULL;
child_sa_t *child_sa;
pthread_mutex_lock(&(this->mutex));
- iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
- while (iterator->iterate(iterator, (void**)&entry))
+ enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
+ while (enumerator->enumerate(enumerator, &entry))
{
if (wait_for_entry(this, entry))
{
@@ -684,39 +692,82 @@ static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name,
}
}
}
- iterator->destroy(iterator);
+ enumerator->destroy(enumerator);
pthread_mutex_unlock(&(this->mutex));
charon->bus->set_sa(charon->bus, ike_sa);
return ike_sa;
}
+
+/**
+ * Implementation of ike_sa_manager_t.checkout_duplicate.
+ */
+static ike_sa_t* checkout_duplicate(private_ike_sa_manager_t *this,
+ ike_sa_t *ike_sa)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+ ike_sa_t *duplicate = NULL;
+ identification_t *me, *other;
+
+ me = ike_sa->get_my_id(ike_sa);
+ other = ike_sa->get_other_id(ike_sa);
+
+ pthread_mutex_lock(&this->mutex);
+ enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->ike_sa == ike_sa)
+ { /* self is not a duplicate */
+ continue;
+ }
+ if (wait_for_entry(this, entry))
+ {
+ if (me->equals(me, entry->ike_sa->get_my_id(entry->ike_sa)) &&
+ other->equals(other, entry->ike_sa->get_other_id(entry->ike_sa)))
+ {
+ duplicate = entry->ike_sa;
+ entry->checked_out = TRUE;
+ break;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ pthread_mutex_unlock(&this->mutex);
+ return duplicate;
+}
+
+/**
+ * enumerator cleanup function
+ */
+static void enumerator_unlock(private_ike_sa_manager_t *this)
+{
+ pthread_mutex_unlock(&this->mutex);
+}
/**
- * Iterator hook for iterate, gets ike_sas instead of entries
+ * enumerator filter function
*/
-static hook_result_t iterator_hook(private_ike_sa_manager_t* this, entry_t *in,
- ike_sa_t **out)
+static bool enumerator_filter(private_ike_sa_manager_t *this,
+ entry_t **in, ike_sa_t **out)
{
- /* check out entry */
- if (wait_for_entry(this, in))
+ if (wait_for_entry(this, *in))
{
- *out = in->ike_sa;
- return HOOK_NEXT;
+ *out = (*in)->ike_sa;
+ return TRUE;
}
- return HOOK_SKIP;
+ return FALSE;
}
/**
* Implementation of ike_sa_manager_t.create_iterator.
*/
-static iterator_t *create_iterator(private_ike_sa_manager_t* this)
+static enumerator_t *create_enumerator(private_ike_sa_manager_t* this)
{
- iterator_t *iterator = this->ike_sa_list->create_iterator_locked(
- this->ike_sa_list, &this->mutex);
-
- /* register hook to iterator over ike_sas, not entries */
- iterator->set_iterator_hook(iterator, (iterator_hook_t*)iterator_hook, this);
- return iterator;
+ pthread_mutex_lock(&this->mutex);
+ return enumerator_create_filter(
+ this->ike_sa_list->create_enumerator(this->ike_sa_list),
+ (void*)enumerator_filter, this, (void*)enumerator_unlock);
}
/**
@@ -732,6 +783,7 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
status_t retval;
entry_t *entry;
ike_sa_id_t *ike_sa_id;
+ host_t *other;
ike_sa_id = ike_sa->get_id(ike_sa);
@@ -747,6 +799,13 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
/* signal waiting threads */
entry->checked_out = FALSE;
entry->message_id = -1;
+ /* apply remote address for DoS detection */
+ other = ike_sa->get_other_host(ike_sa);
+ if (!entry->other || !other->equals(other, entry->other))
+ {
+ DESTROY_IF(entry->other);
+ entry->other = other->clone(other);
+ }
DBG2(DBG_MGR, "check-in of IKE_SA successful.");
pthread_cond_signal(&(entry->condvar));
retval = SUCCESS;
@@ -783,6 +842,7 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik
ike_sa_id = ike_sa->get_id(ike_sa);
DBG2(DBG_MGR, "checkin and destroy IKE_SA");
+ charon->bus->set_sa(charon->bus, NULL);
pthread_mutex_lock(&(this->mutex));
@@ -803,7 +863,6 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik
}
pthread_mutex_unlock(&(this->mutex));
- charon->bus->set_sa(charon->bus, ike_sa);
return retval;
}
@@ -812,23 +871,22 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik
*/
static int get_half_open_count(private_ike_sa_manager_t *this, host_t *ip)
{
- iterator_t *iterator;
+ enumerator_t *enumerator;
entry_t *entry;
int count = 0;
pthread_mutex_lock(&(this->mutex));
- iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
- while (iterator->iterate(iterator, (void**)&entry))
+ enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
+ while (enumerator->enumerate(enumerator, &entry))
{
/* we check if we have a responder CONNECTING IKE_SA without checkout */
if (!entry->ike_sa_id->is_initiator(entry->ike_sa_id) &&
entry->ike_sa->get_state(entry->ike_sa) == IKE_CONNECTING)
{
- /* if we have a host, we have wait until no other uses the IKE_SA */
+ /* if we have a host, count only matching IKE_SAs */
if (ip)
{
- if (wait_for_entry(this, entry) && ip->ip_equals(ip,
- entry->ike_sa->get_other_host(entry->ike_sa)))
+ if (entry->other && ip->ip_equals(ip, entry->other))
{
count++;
}
@@ -839,37 +897,37 @@ static int get_half_open_count(private_ike_sa_manager_t *this, host_t *ip)
}
}
}
- iterator->destroy(iterator);
+ enumerator->destroy(enumerator);
pthread_mutex_unlock(&(this->mutex));
return count;
}
/**
- * Implementation of ike_sa_manager_t.destroy.
+ * Implementation of ike_sa_manager_t.flush.
*/
-static void destroy(private_ike_sa_manager_t *this)
+static void flush(private_ike_sa_manager_t *this)
{
/* destroy all list entries */
- linked_list_t *list = this->ike_sa_list;
- iterator_t *iterator;
+ enumerator_t *enumerator;
entry_t *entry;
pthread_mutex_lock(&(this->mutex));
DBG2(DBG_MGR, "going to destroy IKE_SA manager and all managed IKE_SA's");
/* Step 1: drive out all waiting threads */
DBG2(DBG_MGR, "set driveout flags for all stored IKE_SA's");
- iterator = list->create_iterator(list, TRUE);
- while (iterator->iterate(iterator, (void**)&entry))
+ enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
+ while (enumerator->enumerate(enumerator, &entry))
{
/* do not accept new threads, drive out waiting threads */
entry->driveout_new_threads = TRUE;
entry->driveout_waiting_threads = TRUE;
}
+ enumerator->destroy(enumerator);
DBG2(DBG_MGR, "wait for all threads to leave IKE_SA's");
/* Step 2: wait until all are gone */
- iterator->reset(iterator);
- while (iterator->iterate(iterator, (void**)&entry))
+ enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
+ while (enumerator->enumerate(enumerator, &entry))
{
while (entry->waiting_threads)
{
@@ -879,21 +937,33 @@ static void destroy(private_ike_sa_manager_t *this)
pthread_cond_wait(&(entry->condvar), &(this->mutex));
}
}
+ enumerator->destroy(enumerator);
DBG2(DBG_MGR, "delete all IKE_SA's");
/* Step 3: initiate deletion of all IKE_SAs */
- iterator->reset(iterator);
- while (iterator->iterate(iterator, (void**)&entry))
+ enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
+ while (enumerator->enumerate(enumerator, &entry))
{
entry->ike_sa->delete(entry->ike_sa);
}
- iterator->destroy(iterator);
+ enumerator->destroy(enumerator);
DBG2(DBG_MGR, "destroy all entries");
/* Step 4: destroy all entries */
- list->destroy_function(list, (void*)entry_destroy);
+ while (this->ike_sa_list->remove_last(this->ike_sa_list,
+ (void**)&entry) == SUCCESS)
+ {
+ entry_destroy(entry);
+ }
pthread_mutex_unlock(&(this->mutex));
-
- this->randomizer->destroy(this->randomizer);
+}
+
+/**
+ * Implementation of ike_sa_manager_t.destroy.
+ */
+static void destroy(private_ike_sa_manager_t *this)
+{
+ this->ike_sa_list->destroy(this->ike_sa_list);
+ this->rng->destroy(this->rng);
this->hasher->destroy(this->hasher);
free(this);
@@ -907,6 +977,7 @@ ike_sa_manager_t *ike_sa_manager_create()
private_ike_sa_manager_t *this = malloc_thing(private_ike_sa_manager_t);
/* assign public functions */
+ this->public.flush = (void(*)(ike_sa_manager_t*))flush;
this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout;
this->public.checkout_new = (ike_sa_t*(*)(ike_sa_manager_t*,bool))checkout_new;
@@ -914,16 +985,30 @@ ike_sa_manager_t *ike_sa_manager_create()
this->public.checkout_by_config = (ike_sa_t*(*)(ike_sa_manager_t*,peer_cfg_t*))checkout_by_config;
this->public.checkout_by_id = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t,bool))checkout_by_id;
this->public.checkout_by_name = (ike_sa_t*(*)(ike_sa_manager_t*,char*,bool))checkout_by_name;
- this->public.create_iterator = (iterator_t*(*)(ike_sa_manager_t*))create_iterator;
+ this->public.checkout_duplicate = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_t *ike_sa))checkout_duplicate;
+ this->public.create_enumerator = (enumerator_t*(*)(ike_sa_manager_t*))create_enumerator;
this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin;
this->public.checkin_and_destroy = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy;
this->public.get_half_open_count = (int(*)(ike_sa_manager_t*,host_t*))get_half_open_count;
/* initialize private variables */
+ this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_PREFERRED);
+ if (this->hasher == NULL)
+ {
+ DBG1(DBG_MGR, "manager initialization failed, no hasher supported");
+ free(this);
+ return NULL;
+ }
+ this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+ if (this->rng == NULL)
+ {
+ DBG1(DBG_MGR, "manager initialization failed, no RNG supported");
+ this->hasher->destroy(this->hasher);
+ free(this);
+ return NULL;
+ }
this->ike_sa_list = linked_list_create();
pthread_mutex_init(&this->mutex, NULL);
- this->randomizer = randomizer_create();
- this->hasher = hasher_create(HASH_SHA1);
-
return &this->public;
}
+
diff --git a/src/charon/sa/ike_sa_manager.h b/src/charon/sa/ike_sa_manager.h
index a73a106ba..04b6d96c2 100644
--- a/src/charon/sa/ike_sa_manager.h
+++ b/src/charon/sa/ike_sa_manager.h
@@ -1,10 +1,3 @@
-/**
- * @file ike_sa_manager.h
- *
- * @brief Interface of ike_sa_manager_t.
- *
- */
-
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -19,6 +12,13 @@
* 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.
+ *
+ * $Id: ike_sa_manager.h 3819 2008-04-17 10:46:25Z martin $
+ */
+
+/**
+ * @defgroup ike_sa_manager ike_sa_manager
+ * @{ @ingroup sa
*/
#ifndef IKE_SA_MANAGER_H_
@@ -32,7 +32,7 @@ typedef struct ike_sa_manager_t ike_sa_manager_t;
#include <config/peer_cfg.h>
/**
- * @brief The IKE_SA-Manager is responsible for managing all initiated and responded IKE_SA's.
+ * The IKE_SA-Manager is responsible for managing all initiated and responded IKE_SA's.
*
* To avoid access from multiple threads, IKE_SAs must be checked out from
* the manager, and checked in after usage.
@@ -42,18 +42,12 @@ typedef struct ike_sa_manager_t ike_sa_manager_t;
* This could be done by comparing thread-ids via pthread_self()...
*
* @todo Managing of ike_sa_t objects in a hash table instead of linked list.
- *
- * @b Constructors:
- * - ike_sa_manager_create()
- *
- * @ingroup sa
*/
struct ike_sa_manager_t {
/**
- * @brief Checkout an existing IKE_SA.
+ * Checkout an existing IKE_SA.
*
- * @param this the manager object
* @param ike_sa_id the SA identifier, will be updated
* @returns
* - checked out IKE_SA if found
@@ -62,16 +56,15 @@ struct ike_sa_manager_t {
ike_sa_t* (*checkout) (ike_sa_manager_t* this, ike_sa_id_t *sa_id);
/**
- * @brief Create and check out a new IKE_SA.
+ * Create and check out a new IKE_SA.
*
- * @param this the manager object
* @param initiator TRUE for initiator, FALSE otherwise
* @returns created andchecked out IKE_SA
*/
ike_sa_t* (*checkout_new) (ike_sa_manager_t* this, bool initiator);
/**
- * @brief Checkout an IKE_SA by a message.
+ * Checkout an IKE_SA by a message.
*
* In some situations, it is necessary that the manager knows the
* message to use for the checkout. This has the folloing reasons:
@@ -86,7 +79,6 @@ struct ike_sa_manager_t {
* If processing the message does not make sense (for the reasons above),
* NULL is returned.
*
- * @param this the manager object
* @param ike_sa_id the SA identifier, will be updated
* @returns
* - checked out/created IKE_SA
@@ -95,7 +87,7 @@ struct ike_sa_manager_t {
ike_sa_t* (*checkout_by_message) (ike_sa_manager_t* this, message_t *message);
/**
- * @brief Checkout an IKE_SA for initiation by a peer_config.
+ * Checkout an IKE_SA for initiation by a peer_config.
*
* To initiate, a CHILD_SA may be established within an existing IKE_SA.
* This call checks for an existing IKE_SA by comparing the configuration.
@@ -104,7 +96,6 @@ struct ike_sa_manager_t {
* If no IKE_SA is found, a new one is created. This is also the case when
* the found IKE_SA is in the DELETING state.
*
- * @param this the manager object
* @param peer_cfg configuration used to find an existing IKE_SA
* @return checked out/created IKE_SA
*/
@@ -112,14 +103,21 @@ struct ike_sa_manager_t {
peer_cfg_t *peer_cfg);
/**
- * @brief Check out an IKE_SA a unique ID.
+ * Check out a duplicate if ike_sa to do uniqueness tests.
+ *
+ * @param ike_sa ike_sa to get a duplicate from
+ * @return checked out duplicate
+ */
+ ike_sa_t* (*checkout_duplicate)(ike_sa_manager_t *this, ike_sa_t *ike_sa);
+
+ /**
+ * Check out an IKE_SA a unique ID.
*
* Every IKE_SA and every CHILD_SA is uniquely identified by an ID.
* These checkout function uses, depending
* on the child parameter, the unique ID of the IKE_SA or the reqid
* of one of a IKE_SAs CHILD_SA.
*
- * @param this the manager object
* @param id unique ID of the object
* @param child TRUE to use CHILD, FALSE to use IKE_SA
* @return
@@ -130,12 +128,11 @@ struct ike_sa_manager_t {
bool child);
/**
- * @brief Check out an IKE_SA by the policy/connection name.
+ * Check out an IKE_SA by the policy/connection name.
*
* Check out the IKE_SA by the connections name or by a CHILD_SAs policy
* name.
*
- * @param this the manager object
* @param name name of the connection/policy
* @param child TRUE to use policy name, FALSE to use conn name
* @return
@@ -146,24 +143,21 @@ struct ike_sa_manager_t {
bool child);
/**
- * @brief Create an iterator over all stored IKE_SAs.
+ * Create an enumerator over all stored IKE_SAs.
*
- * The avoid synchronization issues, the iterator locks access
+ * The avoid synchronization issues, the enumerator locks access
* to the manager exclusively, until it gets destroyed.
- * This iterator is for reading only! Writing will corrupt the manager.
*
- * @param this the manager object
- * @return iterator over all IKE_SAs.
+ * @return enumerator over all IKE_SAs.
*/
- iterator_t *(*create_iterator) (ike_sa_manager_t* this);
+ enumerator_t *(*create_enumerator) (ike_sa_manager_t* this);
/**
- * @brief Checkin the SA after usage.
+ * Checkin the SA after usage.
*
* @warning the SA pointer MUST NOT be used after checkin!
* The SA must be checked out again!
*
- * @param this the manager object
* @param ike_sa_id the SA identifier, will be updated
* @param ike_sa checked out SA
* @returns
@@ -173,7 +167,7 @@ struct ike_sa_manager_t {
status_t (*checkin) (ike_sa_manager_t* this, ike_sa_t *ike_sa);
/**
- * @brief Destroy a checked out SA.
+ * Destroy a checked out SA.
*
* The IKE SA is destroyed without notification of the remote peer.
* Use this only if the other peer doesn't respond or behaves not
@@ -182,7 +176,6 @@ struct ike_sa_manager_t {
* so this can be called if the SA is in a "unclean" state, without the
* risk that another thread can get the SA.
*
- * @param this the manager object
* @param ike_sa SA to delete
* @returns
* - SUCCESS if found
@@ -191,7 +184,7 @@ struct ike_sa_manager_t {
status_t (*checkin_and_destroy) (ike_sa_manager_t* this, ike_sa_t *ike_sa);
/**
- * @brief Get the number of IKE_SAs which are in the connecting state.
+ * Get the number of IKE_SAs which are in the connecting state.
*
* To prevent the server from resource exhaustion, cookies and other
* mechanisms are used. The number of half open IKE_SAs is a good
@@ -200,29 +193,31 @@ struct ike_sa_manager_t {
* from this IP are counted.
* Only SAs for which we are the responder are counted.
*
- * @param this the manager object
* @param ip NULL for all, IP for half open IKE_SAs with IP
* @return number of half open IKE_SAs
*/
int (*get_half_open_count) (ike_sa_manager_t *this, host_t *ip);
/**
- * @brief Destroys the manager with all associated SAs.
+ * Delete all existing IKE_SAs and destroy them immediately.
*
* Threads will be driven out, so all SAs can be deleted cleanly.
- *
- * @param this the manager object
+ */
+ void (*flush)(ike_sa_manager_t *this);
+
+ /**
+ * Destroys the manager with all associated SAs.
+ *
+ * A call to flush() is required before calling destroy.
*/
void (*destroy) (ike_sa_manager_t *this);
};
/**
- * @brief Create a manager.
- *
- * @returns ike_sa_manager_t object
+ * Create a manager.
*
- * @ingroup sa
+ * @returns ike_sa_manager_t object, NULL if initialization fails
*/
ike_sa_manager_t *ike_sa_manager_create(void);
-#endif /*IKE_SA_MANAGER_H_*/
+#endif /*IKE_SA_MANAGER_H_ @} */
diff --git a/src/charon/sa/mediation_manager.c b/src/charon/sa/mediation_manager.c
index f6137304d..d15f4c100 100644
--- a/src/charon/sa/mediation_manager.c
+++ b/src/charon/sa/mediation_manager.c
@@ -1,10 +1,3 @@
-/**
- * @file mediation_manager.c
- *
- * @brief Implementation of mediation_manager_t.
- *
- */
-
/*
* Copyright (C) 2007 Tobias Brunner
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,8 @@
* 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.
+ *
+ * $Id: mediation_manager.c 3773 2008-04-07 09:36:52Z tobias $
*/
#include "mediation_manager.h"
@@ -246,6 +241,7 @@ static void update_sa_id(private_mediation_manager_t *this, identification_t *pe
{
job_t *job = (job_t*)mediation_callback_job_create(requester, peer_id);
charon->processor->queue_job(charon->processor, job);
+ requester->destroy(requester);
}
pthread_mutex_unlock(&(this->mutex));
diff --git a/src/charon/sa/mediation_manager.h b/src/charon/sa/mediation_manager.h
index 74acc4d41..d21c93244 100644
--- a/src/charon/sa/mediation_manager.h
+++ b/src/charon/sa/mediation_manager.h
@@ -1,10 +1,3 @@
-/**
- * @file mediation_manager.h
- *
- * @brief Interface of mediation_manager_t.
- *
- */
-
/*
* Copyright (C) 2007 Tobias Brunner
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: mediation_manager.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup mediation_manager mediation_manager
+ * @{ @ingroup sa
*/
#ifndef MEDIATION_MANAGER_H_
@@ -29,29 +29,22 @@ typedef struct mediation_manager_t mediation_manager_t;
#include <utils/identification.h>
/**
- * @brief The mediation manager is responsible for managing currently online
+ * The mediation manager is responsible for managing currently online
* peers and registered requests for offline peers on the mediation server.
- *
- * @b Constructors:
- * - mediation_manager_create()
- *
- * @ingroup sa
*/
struct mediation_manager_t {
/**
- * @brief Remove the IKE_SA of a peer.
+ * Remove the IKE_SA of a peer.
*
- * @param this the manager object
* @param ike_sa_id the IKE_SA ID of the peer's SA
*/
void (*remove) (mediation_manager_t* this, ike_sa_id_t *ike_sa_id);
/**
- * @brief Update the ike_sa_id that is assigned to a peer's ID. If the peer
+ * Update the ike_sa_id that is assigned to a peer's ID. If the peer
* is new, it gets a new record assigned.
*
- * @param this the manager object
* @param peer_id the peer's ID
* @param ike_sa_id the IKE_SA ID of the peer's SA
*/
@@ -59,9 +52,8 @@ struct mediation_manager_t {
ike_sa_id_t *ike_sa_id);
/**
- * @brief Checks if a specific peer is online.
+ * Checks if a specific peer is online.
*
- * @param this the manager object
* @param peer_id the peer's ID
* @returns
* - IKE_SA ID of the peer's SA.
@@ -71,10 +63,9 @@ struct mediation_manager_t {
identification_t *peer_id);
/**
- * @brief Checks if a specific peer is online and registers the requesting
+ * Checks if a specific peer is online and registers the requesting
* peer if it is not.
*
- * @param this the manager object
* @param peer_id the peer's ID
* @param requester the requesters ID
* @returns
@@ -85,20 +76,16 @@ struct mediation_manager_t {
identification_t *peer_id, identification_t *requester);
/**
- * @brief Destroys the manager with all data.
- *
- * @param this the manager object
+ * Destroys the manager with all data.
*/
void (*destroy) (mediation_manager_t *this);
};
/**
- * @brief Create a manager.
+ * Create a manager.
*
* @returns mediation_manager_t object
- *
- * @ingroup sa
*/
mediation_manager_t *mediation_manager_create(void);
-#endif /*MEDIATION_MANAGER_H_*/
+#endif /*MEDIATION_MANAGER_H_ @} */
diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c
index 89f527aba..e453fff00 100644
--- a/src/charon/sa/task_manager.c
+++ b/src/charon/sa/task_manager.c
@@ -1,10 +1,3 @@
-/**
- * @file task_manager.c
- *
- * @brief Implementation of task_manager_t.
- *
- */
-
/*
* Copyright (C) 2007 Tobias Brunner
* Copyright (C) 2007 Martin Willi
@@ -19,6 +12,8 @@
* 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.
+ *
+ * $Id: task_manager.c 3666 2008-03-26 18:40:19Z tobias $
*/
#include "task_manager.h"
@@ -31,7 +26,8 @@
#include <sa/tasks/ike_mobike.h>
#include <sa/tasks/ike_auth.h>
#include <sa/tasks/ike_auth_lifetime.h>
-#include <sa/tasks/ike_cert.h>
+#include <sa/tasks/ike_cert_pre.h>
+#include <sa/tasks/ike_cert_post.h>
#include <sa/tasks/ike_rekey.h>
#include <sa/tasks/ike_delete.h>
#include <sa/tasks/ike_config.h>
@@ -42,8 +38,8 @@
#include <encoding/payloads/delete_payload.h>
#include <processing/jobs/retransmit_job.h>
-#ifdef P2P
-#include <sa/tasks/ike_p2p.h>
+#ifdef ME
+#include <sa/tasks/ike_me.h>
#endif
typedef struct exchange_t exchange_t;
@@ -328,15 +324,16 @@ static status_t build_request(private_task_manager_t *this)
this->initiating.mid = 0;
exchange = IKE_SA_INIT;
activate_task(this, IKE_NATD);
- activate_task(this, IKE_CERT);
-#ifdef P2P
+ activate_task(this, IKE_CERT_PRE);
+#ifdef ME
/* this task has to be activated before the IKE_AUTHENTICATE
* task, because that task pregenerates the packet after
* which no payloads can be added to the message anymore.
*/
- activate_task(this, IKE_P2P);
-#endif /* P2P */
+ activate_task(this, IKE_ME);
+#endif /* ME */
activate_task(this, IKE_AUTHENTICATE);
+ activate_task(this, IKE_CERT_POST);
activate_task(this, IKE_CONFIG);
activate_task(this, CHILD_CREATE);
activate_task(this, IKE_AUTH_LIFETIME);
@@ -384,13 +381,13 @@ static status_t build_request(private_task_manager_t *this)
exchange = INFORMATIONAL;
break;
}
-#ifdef P2P
- if (activate_task(this, IKE_P2P))
+#ifdef ME
+ if (activate_task(this, IKE_ME))
{
- exchange = P2P_CONNECT;
+ exchange = ME_CONNECT;
break;
}
-#endif /* P2P */
+#endif /* ME */
case IKE_REKEYING:
if (activate_task(this, IKE_DELETE))
{
@@ -687,14 +684,16 @@ static status_t process_request(private_task_manager_t *this,
this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)ike_natd_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
- task = (task_t*)ike_cert_create(this->ike_sa, FALSE);
+ task = (task_t*)ike_cert_pre_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
-#ifdef P2P
- task = (task_t*)ike_p2p_create(this->ike_sa, FALSE);
+#ifdef ME
+ task = (task_t*)ike_me_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
-#endif /* P2P */
+#endif /* ME */
task = (task_t*)ike_auth_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
+ task = (task_t*)ike_cert_post_create(this->ike_sa, FALSE);
+ this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)ike_config_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)child_create_create(this->ike_sa, NULL);
@@ -818,13 +817,13 @@ static status_t process_request(private_task_manager_t *this,
this->passive_tasks->insert_last(this->passive_tasks, task);
break;
}
-#ifdef P2P
- case P2P_CONNECT:
+#ifdef ME
+ case ME_CONNECT:
{
- task = (task_t*)ike_p2p_create(this->ike_sa, FALSE);
+ task = (task_t*)ike_me_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
}
-#endif /* P2P */
+#endif /* ME */
default:
break;
}
diff --git a/src/charon/sa/task_manager.h b/src/charon/sa/task_manager.h
index 38c63c1a9..6243ac888 100644
--- a/src/charon/sa/task_manager.h
+++ b/src/charon/sa/task_manager.h
@@ -1,10 +1,3 @@
-/**
- * @file task_manager.h
- *
- * @brief Interface of task_manager_t.
- *
- */
-
/*
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: task_manager.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup task_manager task_manager
+ * @{ @ingroup sa
*/
#ifndef TASK_MANAGER_H_
@@ -32,42 +32,32 @@ typedef struct task_manager_t task_manager_t;
/**
* First retransmit timeout in milliseconds.
- *
- * @ingroup sa
*/
#define RETRANSMIT_TIMEOUT 4000
/**
* Base which is raised to the power of the retransmission try.
- *
- * @ingroup sa
*/
#define RETRANSMIT_BASE 1.8
/**
* Number of retransmits done before giving up.
- *
- * @ingroup sa
*/
#define RETRANSMIT_TRIES 5
/**
* Interval for mobike routability checks in ms.
- *
- * @ingroup sa
*/
#define ROUTEABILITY_CHECK_INTERVAL 2500
/**
* Number of routability checks before giving up
- *
- * @ingroup sa
*/
#define ROUTEABILITY_CHECK_TRIES 10
/**
- * @brief The task manager, juggles task and handles message exchanges.
+ * The task manager, juggles task and handles message exchanges.
*
* On incoming requests, the task manager creates new tasks on demand and
* juggles the request through all available tasks. Each task inspects the
@@ -97,18 +87,12 @@ typedef struct task_manager_t task_manager_t;
@endberbatim
* The peer is considered dead after 2min 45s when no reply comes in.
- *
- * @b Constructors:
- * - task_manager_create()
- *
- * @ingroup sa
*/
struct task_manager_t {
/**
- * @brief Process an incoming message.
+ * Process an incoming message.
*
- * @param this calling object
* @param message message to add payloads to
* @return
* - DESTROY_ME if IKE_SA must be closed
@@ -117,28 +101,24 @@ struct task_manager_t {
status_t (*process_message) (task_manager_t *this, message_t *message);
/**
- * @brief Initiate an exchange with the currently queued tasks.
- *
- * @param this calling object
+ * Initiate an exchange with the currently queued tasks.
*/
status_t (*initiate) (task_manager_t *this);
/**
- * @brief Queue a task in the manager.
+ * Queue a task in the manager.
*
- * @param this calling object
* @param task task to queue
*/
void (*queue_task) (task_manager_t *this, task_t *task);
/**
- * @brief Retransmit a request if it hasn't been acknowledged yet.
+ * Retransmit a request if it hasn't been acknowledged yet.
*
* A return value of INVALID_STATE means that the message was already
* acknowledged and has not to be retransmitted. A return value of SUCCESS
* means retransmission was required and the message has been resent.
*
- * @param this calling object
* @param message_id ID of the message to retransmit
* @return
* - INVALID_STATE if retransmission not required
@@ -147,52 +127,45 @@ struct task_manager_t {
status_t (*retransmit) (task_manager_t *this, u_int32_t message_id);
/**
- * @brief Migrate all tasks from other to this.
+ * Migrate all tasks from other to this.
*
* To rekey or reestablish an IKE_SA completely, all queued or active
* tasks should get migrated to the new IKE_SA.
*
- * @param this manager which gets all tasks
* @param other manager which gives away its tasks
*/
void (*adopt_tasks) (task_manager_t *this, task_manager_t *other);
/**
- * @brief Reset message ID counters of the task manager.
+ * Reset message ID counters of the task manager.
*
* The IKEv2 protocol requires to restart exchanges with message IDs
* reset to zero (INVALID_KE_PAYLOAD, COOKIES, ...). The reset() method
* resets the message IDs and resets all active tasks using the migrate()
* method.
*
- * @param this calling object
* @param other manager which gives away its tasks
*/
void (*reset) (task_manager_t *this);
/**
- * @brief Check if we are currently waiting for a reply.
+ * Check if we are currently waiting for a reply.
*
- * @param this calling object
* @return TRUE if we are waiting, FALSE otherwise
*/
bool (*busy) (task_manager_t *this);
/**
- * @brief Destroy the task_manager_t.
- *
- * @param this calling object
+ * Destroy the task_manager_t.
*/
void (*destroy) (task_manager_t *this);
};
/**
- * @brief Create an instance of the task manager.
+ * Create an instance of the task manager.
*
* @param ike_sa IKE_SA to manage.
- *
- * @ingroup sa
*/
task_manager_t *task_manager_create(ike_sa_t *ike_sa);
-#endif /* TASK_MANAGER_H_ */
+#endif /* TASK_MANAGER_H_ @} */
diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c
index 3947a84d1..4638da03e 100644
--- a/src/charon/sa/tasks/child_create.c
+++ b/src/charon/sa/tasks/child_create.c
@@ -1,11 +1,5 @@
-/**
- * @file child_create.c
- *
- * @brief Implementation of the child_create task.
- *
- */
-
/*
+ * Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -19,6 +13,8 @@
* 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.
+ *
+ * $Id: child_create.c 3920 2008-05-08 16:19:11Z tobias $
*/
#include "child_create.h"
@@ -105,6 +101,21 @@ struct private_child_create_t {
mode_t mode;
/**
+ * IPComp transform to use
+ */
+ ipcomp_transform_t ipcomp;
+
+ /**
+ * IPComp transform proposed or accepted by the other peer
+ */
+ ipcomp_transform_t ipcomp_received;
+
+ /**
+ * Other Compression Parameter Index (CPI)
+ */
+ u_int16_t other_cpi;
+
+ /**
* reqid to use if we are rekeying
*/
u_int32_t reqid;
@@ -141,17 +152,16 @@ static status_t get_nonce(message_t *message, chunk_t *nonce)
*/
static status_t generate_nonce(chunk_t *nonce)
{
- status_t status;
- randomizer_t *randomizer = randomizer_create();
+ rng_t *rng;
- status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
- nonce);
- randomizer->destroy(randomizer);
- if (status != SUCCESS)
+ rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+ if (!rng)
{
- DBG1(DBG_IKE, "error generating random nonce value");
+ DBG1(DBG_IKE, "error generating nonce value, no RNG found");
return FAILED;
}
+ rng->allocate_bytes(rng, NONCE_SIZE, nonce);
+ rng->destroy(rng);
return SUCCESS;
}
@@ -227,11 +237,11 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
if (!this->proposal->has_dh_group(this->proposal, this->dh_group))
{
- algorithm_t *algo;
+ u_int16_t group;
+
if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
- &algo))
+ &group, NULL))
{
- u_int16_t group = algo->algorithm;
SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N",
diffie_hellman_group_names, this->dh_group,
diffie_hellman_group_names, group);
@@ -332,6 +342,12 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
}
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
+ if (this->ipcomp != IPCOMP_NONE)
+ {
+ this->child_sa->activate_ipcomp(this->child_sa, this->ipcomp,
+ this->other_cpi);
+ }
+
if (this->initiator)
{
status = this->child_sa->update(this->child_sa, this->proposal,
@@ -422,6 +438,36 @@ static void build_payloads(private_child_create_t *this, message_t *message)
}
/**
+ * Adds an IPCOMP_SUPPORTED notify to the message, if possible
+ */
+static void build_ipcomp_supported_notify(private_child_create_t *this, message_t *message)
+{
+ if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
+ {
+ DBG1(DBG_IKE, "IPComp is not supported if either peer is natted, IPComp is disabled");
+ this->ipcomp = IPCOMP_NONE;
+ return;
+ }
+
+ u_int16_t cpi = this->child_sa->get_my_cpi(this->child_sa);
+ if (cpi)
+ {
+ chunk_t cpi_chunk, tid_chunk, data;
+ u_int8_t tid = this->ipcomp;
+ cpi_chunk = chunk_from_thing(cpi);
+ tid_chunk = chunk_from_thing(tid);
+ data = chunk_cat("cc", cpi_chunk, tid_chunk);
+ message->add_notify(message, FALSE, IPCOMP_SUPPORTED, data);
+ chunk_free(&data);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "unable to allocate a CPI from kernel, IPComp is disabled");
+ this->ipcomp = IPCOMP_NONE;
+ }
+}
+
+/**
* Read payloads from message
*/
static void process_payloads(private_child_create_t *this, message_t *message)
@@ -450,7 +496,7 @@ static void process_payloads(private_child_create_t *this, message_t *message)
if (!this->initiator)
{
this->dh_group = ke_payload->get_dh_group_number(ke_payload);
- this->dh = diffie_hellman_create(this->dh_group);
+ this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
}
if (this->dh)
{
@@ -476,6 +522,25 @@ static void process_payloads(private_child_create_t *this, message_t *message)
case USE_BEET_MODE:
this->mode = MODE_BEET;
break;
+ case IPCOMP_SUPPORTED:
+ {
+ chunk_t data = notify_payload->get_notification_data(notify_payload);
+ u_int16_t cpi = *(u_int16_t*)data.ptr;
+ ipcomp_transform_t ipcomp = (ipcomp_transform_t)(*(data.ptr + 2));
+ switch(ipcomp)
+ {
+ case IPCOMP_DEFLATE:
+ this->other_cpi = cpi;
+ this->ipcomp_received = ipcomp;
+ break;
+ case IPCOMP_LZS:
+ case IPCOMP_LZJH:
+ default:
+ DBG1(DBG_IKE, "received IPCOMP_SUPPORTED notify with a transform"
+ " ID we don't support %N", ipcomp_transform_names, ipcomp);
+ break;
+ }
+ }
default:
break;
}
@@ -540,11 +605,10 @@ static status_t build_i(private_child_create_t *this, message_t *message)
if (!this->reqid)
{
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
- vip = peer_cfg->get_my_virtual_ip(peer_cfg);
+ vip = peer_cfg->get_virtual_ip(peer_cfg);
if (vip)
{
propose_all = TRUE;
- vip->destroy(vip);
}
}
@@ -580,7 +644,13 @@ static status_t build_i(private_child_create_t *this, message_t *message)
if (this->dh_group != MODP_NONE)
{
- this->dh = diffie_hellman_create(this->dh_group);
+ this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
+ }
+
+ if (this->config->use_ipcomp(this->config)) {
+ /* IPCOMP_DEFLATE is the only transform we support at the moment */
+ this->ipcomp = IPCOMP_DEFLATE;
+ build_ipcomp_supported_notify(this, message);
}
build_payloads(this, message);
@@ -700,6 +770,16 @@ static status_t build_r(private_child_create_t *this, message_t *message)
this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid,
this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
+ if (this->config->use_ipcomp(this->config) && this->ipcomp_received != IPCOMP_NONE)
+ {
+ this->ipcomp = this->ipcomp_received;
+ build_ipcomp_supported_notify(this, message);
+ }
+ else if (this->ipcomp_received != IPCOMP_NONE)
+ {
+ DBG1(DBG_IKE, "received IPCOMP_SUPPORTED notify but IPComp is disabled, ignoring");
+ }
+
switch (select_and_install(this, no_dh))
{
case SUCCESS:
@@ -806,6 +886,25 @@ static status_t process_i(private_child_create_t *this, message_t *message)
process_payloads(this, message);
+ if (this->ipcomp == IPCOMP_NONE && this->ipcomp_received != IPCOMP_NONE)
+ {
+ SIG(CHILD_UP_FAILED, "received an IPCOMP_SUPPORTED notify but we did not "
+ "send one previously, no CHILD_SA built");
+ return SUCCESS;
+ }
+ else if (this->ipcomp != IPCOMP_NONE && this->ipcomp_received == IPCOMP_NONE)
+ {
+ DBG1(DBG_IKE, "peer didn't accept our proposed IPComp transforms, "
+ "IPComp is disabled");
+ this->ipcomp = IPCOMP_NONE;
+ }
+ else if (this->ipcomp != IPCOMP_NONE && this->ipcomp != this->ipcomp_received)
+ {
+ SIG(CHILD_UP_FAILED, "received an IPCOMP_SUPPORTED notify for a transform "
+ "we did not propose, no CHILD_SA built");
+ return SUCCESS;
+ }
+
if (select_and_install(this, no_dh) == SUCCESS)
{
SIG(CHILD_UP_SUCCESS, "CHILD_SA '%s' established successfully",
@@ -884,6 +983,9 @@ static void migrate(private_child_create_t *this, ike_sa_t *ike_sa)
this->dh = NULL;
this->child_sa = NULL;
this->mode = MODE_TUNNEL;
+ this->ipcomp = IPCOMP_NONE;
+ this->ipcomp_received = IPCOMP_NONE;
+ this->other_cpi = 0;
this->reqid = 0;
this->established = FALSE;
}
@@ -957,6 +1059,9 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config)
this->dh_group = MODP_NONE;
this->child_sa = NULL;
this->mode = MODE_TUNNEL;
+ this->ipcomp = IPCOMP_NONE;
+ this->ipcomp_received = IPCOMP_NONE;
+ this->other_cpi = 0;
this->reqid = 0;
this->established = FALSE;
diff --git a/src/charon/sa/tasks/child_create.h b/src/charon/sa/tasks/child_create.h
index 9f4815215..cee37121e 100644
--- a/src/charon/sa/tasks/child_create.h
+++ b/src/charon/sa/tasks/child_create.h
@@ -1,10 +1,3 @@
-/**
- * @file child_create.h
- *
- * @brief Interface child_create_t.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: child_create.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup child_create child_create
+ * @{ @ingroup tasks
*/
#ifndef CHILD_CREATE_H_
@@ -31,15 +31,10 @@ typedef struct child_create_t child_create_t;
#include <config/child_cfg.h>
/**
- * @brief Task of type CHILD_CREATE, established a new CHILD_SA.
+ * Task of type CHILD_CREATE, established a new CHILD_SA.
*
* This task may be included in the IKE_AUTH message or in a separate
* CREATE_CHILD_SA exchange.
- *
- * @b Constructors:
- * - child_create_create()
- *
- * @ingroup tasks
*/
struct child_create_t {
@@ -49,35 +44,32 @@ struct child_create_t {
task_t task;
/**
- * @brief Use a specific reqid for the CHILD_SA.
+ * Use a specific reqid for the CHILD_SA.
*
* When this task is used for rekeying, the same reqid is used
* for the new CHILD_SA.
*
- * @param this calling object
* @param reqid reqid to use
*/
void (*use_reqid) (child_create_t *this, u_int32_t reqid);
/**
- * @brief Get the lower of the two nonces, used for rekey collisions.
+ * Get the lower of the two nonces, used for rekey collisions.
*
- * @param this calling object
* @return lower nonce
*/
chunk_t (*get_lower_nonce) (child_create_t *this);
/**
- * @brief Get the CHILD_SA established/establishing by this task.
+ * Get the CHILD_SA established/establishing by this task.
*
- * @param this calling object
* @return child_sa
*/
child_sa_t* (*get_child) (child_create_t *this);
};
/**
- * @brief Create a new child_create task.
+ * Create a new child_create task.
*
* @param ike_sa IKE_SA this task works for
* @param config child_cfg if task initiator, NULL if responder
@@ -85,4 +77,4 @@ struct child_create_t {
*/
child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config);
-#endif /* CHILD_CREATE_H_ */
+#endif /* CHILD_CREATE_H_ @} */
diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c
index d0b34a276..4156f9704 100644
--- a/src/charon/sa/tasks/child_delete.c
+++ b/src/charon/sa/tasks/child_delete.c
@@ -1,10 +1,3 @@
-/**
- * @file child_delete.c
- *
- * @brief Implementation of the child_delete task.
- *
- */
-
/*
* Copyright (C) 2006-2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,8 @@
* 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.
+ *
+ * $Id: child_delete.c 3802 2008-04-14 08:17:18Z martin $
*/
#include "child_delete.h"
@@ -157,23 +152,48 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
}
/**
- * destroy the children listed in this->child_sas
+ * destroy the children listed in this->child_sas, reestablish by policy
*/
-static void destroy_children(private_child_delete_t *this)
+static status_t destroy_and_reestablish(private_child_delete_t *this)
{
iterator_t *iterator;
child_sa_t *child_sa;
+ child_cfg_t *child_cfg;
protocol_id_t protocol;
u_int32_t spi;
+ status_t status = SUCCESS;
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
spi = child_sa->get_spi(child_sa, TRUE);
protocol = child_sa->get_protocol(child_sa);
+ child_cfg = child_sa->get_config(child_sa);
+ child_cfg->get_ref(child_cfg);
this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
+ if (!this->initiator)
+ { /* enforce child_cfg policy if deleted passively */
+ switch (child_cfg->get_close_action(child_cfg))
+ {
+ case ACTION_RESTART:
+ child_cfg->get_ref(child_cfg);
+ status = this->ike_sa->initiate(this->ike_sa, child_cfg);
+ break;
+ case ACTION_ROUTE:
+ status = this->ike_sa->route(this->ike_sa, child_cfg);
+ break;
+ default:
+ break;
+ }
+ }
+ child_cfg->destroy(child_cfg);
+ if (status != SUCCESS)
+ {
+ break;
+ }
}
iterator->destroy(iterator);
+ return status;
}
/**
@@ -214,9 +234,8 @@ static status_t process_i(private_child_delete_t *this, message_t *message)
this->child_sas = linked_list_create();
process_payloads(this, message);
- destroy_children(this);
SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed");
- return SUCCESS;
+ return destroy_and_reestablish(this);
}
/**
@@ -239,9 +258,8 @@ static status_t build_r(private_child_delete_t *this, message_t *message)
{
build_payloads(this, message);
}
- destroy_children(this);
SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed");
- return SUCCESS;
+ return destroy_and_reestablish(this);
}
/**
diff --git a/src/charon/sa/tasks/child_delete.h b/src/charon/sa/tasks/child_delete.h
index a7e676a50..c304ea9d8 100644
--- a/src/charon/sa/tasks/child_delete.h
+++ b/src/charon/sa/tasks/child_delete.h
@@ -1,10 +1,3 @@
-/**
- * @file child_delete.h
- *
- * @brief Interface child_delete_t.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: child_delete.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup child_delete child_delete
+ * @{ @ingroup tasks
*/
#ifndef CHILD_DELETE_H_
@@ -31,12 +31,7 @@ typedef struct child_delete_t child_delete_t;
#include <sa/child_sa.h>
/**
- * @brief Task of type child_delete, delete a CHILD_SA.
- *
- * @b Constructors:
- * - child_delete_create()
- *
- * @ingroup tasks
+ * Task of type child_delete, delete a CHILD_SA.
*/
struct child_delete_t {
@@ -46,16 +41,15 @@ struct child_delete_t {
task_t task;
/**
- * @brief Get the CHILD_SA to delete by this task.
+ * Get the CHILD_SA to delete by this task.
*
- * @param this calling object
* @return child_sa
*/
child_sa_t* (*get_child) (child_delete_t *this);
};
/**
- * @brief Create a new child_delete task.
+ * Create a new child_delete task.
*
* @param ike_sa IKE_SA this task works for
* @param child_sa CHILD_SA to delete, or NULL as responder
@@ -63,4 +57,4 @@ struct child_delete_t {
*/
child_delete_t *child_delete_create(ike_sa_t *ike_sa, child_sa_t *child_sa);
-#endif /* CHILD_DELETE_H_ */
+#endif /* CHILD_DELETE_H_ @} */
diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c
index 3667d8fad..3953951a3 100644
--- a/src/charon/sa/tasks/child_rekey.c
+++ b/src/charon/sa/tasks/child_rekey.c
@@ -1,10 +1,3 @@
-/**
- * @file child_rekey.c
- *
- * @brief Implementation of the child_rekey task.
- *
- */
-
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -19,6 +12,8 @@
* 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.
+ *
+ * $Id: child_rekey.c 3589 2008-03-13 14:14:44Z martin $
*/
#include "child_rekey.h"
diff --git a/src/charon/sa/tasks/child_rekey.h b/src/charon/sa/tasks/child_rekey.h
index 3515f0c3f..b386ef3c6 100644
--- a/src/charon/sa/tasks/child_rekey.h
+++ b/src/charon/sa/tasks/child_rekey.h
@@ -1,10 +1,3 @@
-/**
- * @file child_rekey.h
- *
- * @brief Interface child_rekey_t.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: child_rekey.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup child_rekey child_rekey
+ * @{ @ingroup tasks
*/
#ifndef CHILD_REKEY_H_
@@ -31,12 +31,7 @@ typedef struct child_rekey_t child_rekey_t;
#include <sa/tasks/task.h>
/**
- * @brief Task of type CHILD_REKEY, rekey an established CHILD_SA.
- *
- * @b Constructors:
- * - child_rekey_create()
- *
- * @ingroup tasks
+ * Task of type CHILD_REKEY, rekey an established CHILD_SA.
*/
struct child_rekey_t {
@@ -46,20 +41,19 @@ struct child_rekey_t {
task_t task;
/**
- * @brief Register a rekeying task which collides with this one
+ * Register a rekeying task which collides with this one
*
* If two peers initiate rekeying at the same time, the collision must
* be handled gracefully. The task manager is aware of what exchanges
* are going on and notifies the outgoing task by passing the incoming.
*
- * @param this task initated by us
* @param other incoming task
*/
void (*collide)(child_rekey_t* this, task_t *other);
};
/**
- * @brief Create a new CHILD_REKEY task.
+ * Create a new CHILD_REKEY task.
*
* @param ike_sa IKE_SA this task works for
* @param child_sa child_sa to rekey, NULL if responder
@@ -67,4 +61,4 @@ struct child_rekey_t {
*/
child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa);
-#endif /* CHILD_REKEY_H_ */
+#endif /* CHILD_REKEY_H_ @} */
diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c
index de88a0abe..fd5012ee6 100644
--- a/src/charon/sa/tasks/ike_auth.c
+++ b/src/charon/sa/tasks/ike_auth.c
@@ -1,10 +1,3 @@
-/**
- * @file ike_auth.c
- *
- * @brief Implementation of the ike_auth task.
- *
- */
-
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -18,7 +11,9 @@
* 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.
+ * for more details
+ *
+ * $Id: ike_auth.c 4051 2008-06-10 09:08:27Z tobias $
*/
#include "ike_auth.h"
@@ -94,6 +89,68 @@ struct private_ike_auth_t {
};
/**
+ * check uniqueness and delete duplicates
+ */
+static bool check_uniqueness(private_ike_auth_t *this)
+{
+ ike_sa_t *duplicate;
+ unique_policy_t policy;
+ status_t status = SUCCESS;
+ peer_cfg_t *peer_cfg;
+ bool cancel = FALSE;
+
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+ policy = peer_cfg->get_unique_policy(peer_cfg);
+ if (policy == UNIQUE_NO)
+ {
+ return FALSE;
+ }
+ duplicate = charon->ike_sa_manager->checkout_duplicate(
+ charon->ike_sa_manager, this->ike_sa);
+ if (duplicate)
+ {
+ peer_cfg = duplicate->get_peer_cfg(duplicate);
+ if (peer_cfg &&
+ peer_cfg->equals(peer_cfg, this->ike_sa->get_peer_cfg(this->ike_sa)))
+ {
+ switch (duplicate->get_state(duplicate))
+ {
+ case IKE_ESTABLISHED:
+ case IKE_REKEYING:
+ switch (policy)
+ {
+ case UNIQUE_REPLACE:
+ DBG1(DBG_IKE, "deleting duplicate IKE_SA due "
+ "uniqueness policy");
+ status = duplicate->delete(duplicate);
+ break;
+ case UNIQUE_KEEP:
+ DBG1(DBG_IKE, "cancelling IKE_SA setup due "
+ "uniqueness policy");
+ cancel = TRUE;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (status == DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+ duplicate);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, duplicate);
+ }
+ }
+ return cancel;
+}
+
+/**
* build the AUTH payload
*/
static status_t build_auth(private_ike_auth_t *this, message_t *message)
@@ -101,7 +158,7 @@ static status_t build_auth(private_ike_auth_t *this, message_t *message)
authenticator_t *auth;
auth_payload_t *auth_payload;
peer_cfg_t *config;
- auth_method_t method;
+ config_auth_method_t method;
status_t status;
/* create own authenticator and add auth payload */
@@ -117,7 +174,7 @@ static status_t build_auth(private_ike_auth_t *this, message_t *message)
if (auth == NULL)
{
SIG(IKE_UP_FAILED, "configured authentication method %N not supported",
- auth_method_names, method);
+ config_auth_method_names, method);
return FAILED;
}
@@ -186,13 +243,13 @@ static status_t process_auth(private_ike_auth_t *this, message_t *message)
/* AUTH payload is missing, client wants to use EAP authentication */
return NOT_FOUND;
}
-
+
auth_method = auth_payload->get_auth_method(auth_payload);
- auth = authenticator_create(this->ike_sa, auth_method);
+ auth = authenticator_create_from_auth_payload(this->ike_sa, auth_payload);
if (auth == NULL)
{
- SIG(IKE_UP_FAILED, "authentication method %N used by %D not "
+ SIG(IKE_UP_FAILED, "authentication method %N used by '%D' not "
"supported", auth_method_names, auth_method,
this->ike_sa->get_other_id(this->ike_sa));
return NOT_SUPPORTED;
@@ -231,9 +288,9 @@ static status_t process_id(private_ike_auth_t *this, message_t *message)
{
id = idr->get_identification(idr);
req = this->ike_sa->get_other_id(this->ike_sa);
- if (!id->matches(id, req, NULL))
+ if (!id->matches(id, req))
{
- SIG(IKE_UP_FAILED, "peer ID %D unacceptable, %D required", id, req);
+ SIG(IKE_UP_FAILED, "peer ID '%D' unacceptable, '%D' required", id, req);
id->destroy(id);
return FAILED;
}
@@ -321,12 +378,12 @@ static status_t build_auth_eap(private_ike_auth_t *this, message_t *message)
if (!this->initiator)
{
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
- SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %D[%H]...[%H]%D",
+ SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...[%D]%H",
this->ike_sa->get_name(this->ike_sa),
- this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_my_host(this->ike_sa),
- this->ike_sa->get_other_host(this->ike_sa),
- this->ike_sa->get_other_id(this->ike_sa));
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa));
return SUCCESS;
}
return NEED_MORE;
@@ -367,12 +424,12 @@ static status_t process_auth_eap(private_ike_auth_t *this, message_t *message)
if (this->initiator)
{
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
- SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %D[%H]...[%H]%D",
+ SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...[%D]%H",
this->ike_sa->get_name(this->ike_sa),
- this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_my_host(this->ike_sa),
- this->ike_sa->get_other_host(this->ike_sa),
- this->ike_sa->get_other_id(this->ike_sa));
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa));
return SUCCESS;
}
return NEED_MORE;
@@ -404,7 +461,7 @@ static status_t process_eap_i(private_ike_auth_t *this, message_t *message)
return NEED_MORE;
default:
this->eap_payload = NULL;
- SIG(IKE_UP_FAILED, "failed to authenticate against %D using EAP",
+ SIG(IKE_UP_FAILED, "failed to authenticate against '%D' using EAP",
this->ike_sa->get_other_id(this->ike_sa));
return FAILED;
}
@@ -482,7 +539,7 @@ static status_t build_i(private_ike_auth_t *this, message_t *message)
}
config = this->ike_sa->get_peer_cfg(this->ike_sa);
- if (config->get_auth_method(config) == AUTH_EAP)
+ if (config->get_auth_method(config) == CONF_AUTH_EAP)
{
this->eap_auth = eap_authenticator_create(this->ike_sa);
}
@@ -525,13 +582,13 @@ static status_t process_r(private_ike_auth_t *this, message_t *message)
this->eap_auth = eap_authenticator_create(this->ike_sa);
break;
default:
- break;
+ return NEED_MORE;
}
config = charon->backends->get_peer_cfg(charon->backends,
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa),
- this->ike_sa->get_other_ca(this->ike_sa));
+ this->ike_sa->get_other_auth(this->ike_sa));
if (config)
{
this->ike_sa->set_peer_cfg(this->ike_sa, config);
@@ -557,10 +614,17 @@ static status_t build_r(private_ike_auth_t *this, message_t *message)
return collect_my_init_data(this, message);
}
+ if (!this->peer_authenticated && this->eap_auth == NULL)
+ {
+ /* peer not authenticated, nor does it want to use EAP */
+ message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
+ return FAILED;
+ }
+
config = this->ike_sa->get_peer_cfg(this->ike_sa);
if (config == NULL)
{
- SIG(IKE_UP_FAILED, "no matching config found for %D...%D",
+ SIG(IKE_UP_FAILED, "no matching config found for '%D'...'%D'",
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
@@ -574,26 +638,25 @@ static status_t build_r(private_ike_auth_t *this, message_t *message)
return FAILED;
}
+ if (check_uniqueness(this))
+ {
+ message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
+ return FAILED;
+ }
+
/* use "traditional" authentication if we could authenticate peer */
if (this->peer_authenticated)
{
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
- SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %D[%H]...[%H]%D",
+ SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...[%D]%H",
this->ike_sa->get_name(this->ike_sa),
- this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_my_host(this->ike_sa),
- this->ike_sa->get_other_host(this->ike_sa),
- this->ike_sa->get_other_id(this->ike_sa));
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa));
return SUCCESS;
}
- if (this->eap_auth == NULL)
- {
- /* peer not authenticated, nor does it want to use EAP */
- message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
- return FAILED;
- }
-
/* initiate EAP authenitcation */
eap_type = config->get_eap_type(config, &eap_vendor);
status = this->eap_auth->initiate(this->eap_auth, eap_type,
@@ -618,6 +681,8 @@ static status_t process_i(private_ike_auth_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
+ peer_cfg_t *config;
+ auth_info_t *auth;
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
@@ -652,8 +717,8 @@ static status_t process_i(private_ike_auth_t *this, message_t *message)
case AUTH_LIFETIME:
/* handled in ike_auth_lifetime task */
break;
- case P2P_ENDPOINT:
- /* handled in ike_p2p task */
+ case ME_ENDPOINT:
+ /* handled in ike_me task */
break;
default:
{
@@ -664,7 +729,7 @@ static status_t process_i(private_ike_auth_t *this, message_t *message)
iterator->destroy(iterator);
return FAILED;
}
- DBG1(DBG_IKE, "received %N notify",
+ DBG2(DBG_IKE, "received %N notify",
notify_type_names, type);
break;
}
@@ -687,13 +752,21 @@ static status_t process_i(private_ike_auth_t *this, message_t *message)
return process_eap_i(this, message);
}
+ config = this->ike_sa->get_peer_cfg(this->ike_sa);
+ auth = this->ike_sa->get_other_auth(this->ike_sa);
+ if (!auth->complies(auth, config->get_auth(config)))
+ {
+ SIG(IKE_UP_FAILED, "authorization of '%D' for config %s failed",
+ this->ike_sa->get_other_id(this->ike_sa), config->get_name(config));
+ return FAILED;
+ }
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
- SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %D[%H]...[%H]%D",
+ SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...[%D]%H",
this->ike_sa->get_name(this->ike_sa),
- this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_my_host(this->ike_sa),
- this->ike_sa->get_other_host(this->ike_sa),
- this->ike_sa->get_other_id(this->ike_sa));
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa));
return SUCCESS;
}
diff --git a/src/charon/sa/tasks/ike_auth.h b/src/charon/sa/tasks/ike_auth.h
index d7326c988..15f98f312 100644
--- a/src/charon/sa/tasks/ike_auth.h
+++ b/src/charon/sa/tasks/ike_auth.h
@@ -1,10 +1,3 @@
-/**
- * @file ike_auth.h
- *
- * @brief Interface ike_auth_t.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: ike_auth.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup ike_auth ike_auth
+ * @{ @ingroup tasks
*/
#ifndef IKE_AUTH_H_
@@ -30,7 +30,7 @@ typedef struct ike_auth_t ike_auth_t;
#include <sa/tasks/task.h>
/**
- * @brief Task of type ike_auth, authenticates an IKE_SA using authenticators.
+ * Task of type ike_auth, authenticates an IKE_SA using authenticators.
*
* The ike_auth task authenticates the IKE_SA using the IKE_AUTH
* exchange. It processes and build IDi and IDr payloads and also
@@ -38,11 +38,6 @@ typedef struct ike_auth_t ike_auth_t;
* which do the actual authentication process. If the ike_auth task is used
* with EAP authentication, it stays alive over multiple exchanges until
* EAP has completed.
- *
- * @b Constructors:
- * - ike_auth_create()
- *
- * @ingroup tasks
*/
struct ike_auth_t {
@@ -53,7 +48,7 @@ struct ike_auth_t {
};
/**
- * @brief Create a new task of type IKE_AUTHENTICATE.
+ * Create a new task of type IKE_AUTHENTICATE.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if thask is the initator of an exchange
@@ -61,4 +56,4 @@ struct ike_auth_t {
*/
ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator);
-#endif /* IKE_AUTH_H_ */
+#endif /* IKE_AUTH_H_ @} */
diff --git a/src/charon/sa/tasks/ike_auth_lifetime.c b/src/charon/sa/tasks/ike_auth_lifetime.c
index 9d37ec608..2d18c6a1e 100644
--- a/src/charon/sa/tasks/ike_auth_lifetime.c
+++ b/src/charon/sa/tasks/ike_auth_lifetime.c
@@ -1,10 +1,3 @@
-/**
- * @file ike_auth_lifetime.c
- *
- * @brief Implementation of the ike_auth_lifetime task.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,8 @@
* 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.
+ *
+ * $Id: ike_auth_lifetime.c 3589 2008-03-13 14:14:44Z martin $
*/
#include "ike_auth_lifetime.h"
diff --git a/src/charon/sa/tasks/ike_auth_lifetime.h b/src/charon/sa/tasks/ike_auth_lifetime.h
index 500b89d39..21a3bbfdc 100644
--- a/src/charon/sa/tasks/ike_auth_lifetime.h
+++ b/src/charon/sa/tasks/ike_auth_lifetime.h
@@ -1,10 +1,3 @@
-/**
- * @file ike_auth_lifetime.h
- *
- * @brief Interface ike_auth_lifetime_t.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: ike_auth_lifetime.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup ike_auth_lifetime ike_auth_lifetime
+ * @{ @ingroup tasks
*/
#ifndef IKE_AUTH_LIFETIME_H_
@@ -30,15 +30,10 @@ typedef struct ike_auth_lifetime_t ike_auth_lifetime_t;
#include <sa/tasks/task.h>
/**
- * @brief Task of type IKE_AUTH_LIFETIME, implements RFC4478.
+ * Task of type IKE_AUTH_LIFETIME, implements RFC4478.
*
* This task exchanges lifetimes for IKE_AUTH to force a client to
* reauthenticate before the responders lifetime reaches the limit.
- *
- * @b Constructors:
- * - ike_auth_lifetime_create()
- *
- * @ingroup tasks
*/
struct ike_auth_lifetime_t {
@@ -49,7 +44,7 @@ struct ike_auth_lifetime_t {
};
/**
- * @brief Create a new IKE_AUTH_LIFETIME task.
+ * Create a new IKE_AUTH_LIFETIME task.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if taks is initiated by us
@@ -57,5 +52,4 @@ struct ike_auth_lifetime_t {
*/
ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator);
-#endif /* IKE_MOBIKE_H_ */
-
+#endif /* IKE_MOBIKE_H_ @} */
diff --git a/src/charon/sa/tasks/ike_cert.c b/src/charon/sa/tasks/ike_cert.c
deleted file mode 100644
index 880ed9c42..000000000
--- a/src/charon/sa/tasks/ike_cert.c
+++ /dev/null
@@ -1,366 +0,0 @@
-/**
- * @file ike_cert.c
- *
- * @brief Implementation of the ike_cert task.
- *
- */
-
-/*
- * Copyright (C) 2006-2007 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "ike_cert.h"
-
-#include <daemon.h>
-#include <sa/ike_sa.h>
-#include <crypto/hashers/hasher.h>
-#include <encoding/payloads/cert_payload.h>
-#include <encoding/payloads/certreq_payload.h>
-
-
-typedef struct private_ike_cert_t private_ike_cert_t;
-
-/**
- * Private members of a ike_cert_t task.
- */
-struct private_ike_cert_t {
-
- /**
- * Public methods and task_t interface.
- */
- ike_cert_t public;
-
- /**
- * Assigned IKE_SA.
- */
- ike_sa_t *ike_sa;
-
- /**
- * Are we the initiator?
- */
- bool initiator;
-
- /**
- * list of CA cert hashes requested, items point to 20 byte chunk
- */
- linked_list_t *cas;
-
- /**
- * have we seen a certificate request?
- */
- bool certreq_seen;
-};
-
-/**
- * read certificate requests
- */
-static void process_certreqs(private_ike_cert_t *this, message_t *message)
-{
- iterator_t *iterator;
- payload_t *payload;
-
- iterator = message->get_payload_iterator(message);
- while (iterator->iterate(iterator, (void**)&payload))
- {
- if (payload->get_type(payload) == CERTIFICATE_REQUEST)
- {
- certreq_payload_t *certreq = (certreq_payload_t*)payload;
- cert_encoding_t encoding;
- chunk_t keyids, keyid;
-
- this->certreq_seen = TRUE;
-
- encoding = certreq->get_cert_encoding(certreq);
- if (encoding != CERT_X509_SIGNATURE)
- {
- DBG1(DBG_IKE, "certreq payload %N not supported - ignored",
- cert_encoding_names, encoding);
- continue;
- }
-
- keyids = certreq->get_data(certreq);
-
- while (keyids.len >= HASH_SIZE_SHA1)
- {
- keyid = chunk_create(keyids.ptr, HASH_SIZE_SHA1);
- keyid = chunk_clone(keyid);
- this->cas->insert_last(this->cas, keyid.ptr);
- keyids = chunk_skip(keyids, HASH_SIZE_SHA1);
- }
- }
- }
- iterator->destroy(iterator);
-}
-
-/**
- * import certificates
- */
-static void process_certs(private_ike_cert_t *this, message_t *message)
-{
- iterator_t *iterator;
- payload_t *payload;
-
- iterator = message->get_payload_iterator(message);
- while (iterator->iterate(iterator, (void**)&payload))
- {
- if (payload->get_type(payload) == CERTIFICATE)
- {
- cert_encoding_t encoding;
- x509_t *cert;
- chunk_t cert_data;
- bool found;
- cert_payload_t *cert_payload = (cert_payload_t*)payload;
-
- encoding = cert_payload->get_cert_encoding(cert_payload);
- if (encoding != CERT_X509_SIGNATURE)
- {
- DBG1(DBG_IKE, "certificate payload %N not supported - ignored",
- cert_encoding_names, encoding);
- continue;
- }
-
- cert_data = cert_payload->get_data_clone(cert_payload);
- cert = x509_create_from_chunk(cert_data, 0);
- if (cert)
- {
- if (charon->credentials->verify(charon->credentials, cert, &found))
- {
- DBG2(DBG_IKE, "received end entity certificate is trusted - "
- "added to store");
- if (found)
- {
- cert->destroy(cert);
- }
- else
- {
- charon->credentials->add_end_certificate(charon->credentials, cert);
- }
- }
- else
- {
- DBG1(DBG_IKE, "received end entity certificate is not trusted - "
- "discarded");
- cert->destroy(cert);
- }
- }
- else
- {
- DBG1(DBG_IKE, "parsing of received certificate failed - discarded");
- chunk_free(&cert_data);
- }
- }
- }
- iterator->destroy(iterator);
-}
-
-/**
- * build certificate requests
- */
-static void build_certreqs(private_ike_cert_t *this, message_t *message)
-{
- ike_cfg_t *ike_cfg;
- peer_cfg_t *peer_cfg;
- identification_t *ca;
- certreq_payload_t *certreq;
-
- ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
-
- if (ike_cfg->send_certreq(ike_cfg) != CERT_NEVER_SEND)
- {
- peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
-
- if (peer_cfg)
- {
- ca = peer_cfg->get_other_ca(peer_cfg);
-
- if (ca && ca->get_type(ca) != ID_ANY)
- {
- certreq = certreq_payload_create_from_cacert(ca);
- }
- else
- {
- certreq = certreq_payload_create_from_cacerts();
- }
- }
- else
- {
- certreq = certreq_payload_create_from_cacerts();
- }
-
- if (certreq)
- {
- message->add_payload(message, (payload_t*)certreq);
- }
- }
-}
-
-/**
- * add certificates to message
- */
-static void build_certs(private_ike_cert_t *this, message_t *message)
-{
- peer_cfg_t *peer_cfg;
- x509_t *cert;
- cert_payload_t *payload;
-
- peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
-
- if (peer_cfg && peer_cfg->get_auth_method(peer_cfg) == AUTH_RSA)
- {
- switch (peer_cfg->get_cert_policy(peer_cfg))
- {
- case CERT_NEVER_SEND:
- break;
- case CERT_SEND_IF_ASKED:
- if (!this->certreq_seen)
- {
- break;
- }
- /* FALL */
- case CERT_ALWAYS_SEND:
- {
- /* TODO: respect CA cert request */
- cert = charon->credentials->get_certificate(charon->credentials,
- peer_cfg->get_my_id(peer_cfg));
- if (cert)
- {
- payload = cert_payload_create_from_x509(cert);
- message->add_payload(message, (payload_t*)payload);
- }
- }
- }
- }
-}
-
-/**
- * Implementation of task_t.process for initiator
- */
-static status_t build_i(private_ike_cert_t *this, message_t *message)
-{
- if (message->get_exchange_type(message) == IKE_SA_INIT)
- {
- return NEED_MORE;
- }
-
- build_certreqs(this, message);
- build_certs(this, message);
-
- return NEED_MORE;
-}
-
-/**
- * Implementation of task_t.process for responder
- */
-static status_t process_r(private_ike_cert_t *this, message_t *message)
-{
- if (message->get_exchange_type(message) == IKE_SA_INIT)
- {
- return NEED_MORE;
- }
-
- process_certreqs(this, message);
- process_certs(this, message);
-
- return NEED_MORE;
-}
-
-/**
- * Implementation of task_t.build for responder
- */
-static status_t build_r(private_ike_cert_t *this, message_t *message)
-{
- if (message->get_exchange_type(message) == IKE_SA_INIT)
- {
- build_certreqs(this, message);
- return NEED_MORE;
- }
-
- build_certs(this, message);
-
- return SUCCESS;
-}
-
-/**
- * Implementation of task_t.process for initiator
- */
-static status_t process_i(private_ike_cert_t *this, message_t *message)
-{
- if (message->get_exchange_type(message) == IKE_SA_INIT)
- {
- process_certreqs(this, message);
- return NEED_MORE;
- }
-
- process_certs(this, message);
- return SUCCESS;
-}
-
-/**
- * Implementation of task_t.get_type
- */
-static task_type_t get_type(private_ike_cert_t *this)
-{
- return IKE_CERT;
-}
-
-/**
- * Implementation of task_t.migrate
- */
-static void migrate(private_ike_cert_t *this, ike_sa_t *ike_sa)
-{
- this->ike_sa = ike_sa;
-
- this->cas->destroy_function(this->cas, free);
- this->cas = linked_list_create();
- this->certreq_seen = FALSE;
-}
-
-/**
- * Implementation of task_t.destroy
- */
-static void destroy(private_ike_cert_t *this)
-{
- this->cas->destroy_function(this->cas, free);
- free(this);
-}
-
-/*
- * Described in header.
- */
-ike_cert_t *ike_cert_create(ike_sa_t *ike_sa, bool initiator)
-{
- private_ike_cert_t *this = malloc_thing(private_ike_cert_t);
-
- this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
- this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
- this->public.task.destroy = (void(*)(task_t*))destroy;
-
- if (initiator)
- {
- this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
- this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
- }
- else
- {
- this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
- this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
- }
-
- this->ike_sa = ike_sa;
- this->initiator = initiator;
- this->cas = linked_list_create();
- this->certreq_seen = FALSE;
-
- return &this->public;
-}
diff --git a/src/charon/sa/tasks/ike_cert_post.c b/src/charon/sa/tasks/ike_cert_post.c
new file mode 100644
index 000000000..184868b28
--- /dev/null
+++ b/src/charon/sa/tasks/ike_cert_post.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2006-2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * $Id: ike_cert_post.c 4051 2008-06-10 09:08:27Z tobias $
+ */
+
+#include "ike_cert_post.h"
+
+#include <daemon.h>
+#include <sa/ike_sa.h>
+#include <encoding/payloads/cert_payload.h>
+#include <encoding/payloads/certreq_payload.h>
+#include <credentials/certificates/x509.h>
+
+
+typedef struct private_ike_cert_post_t private_ike_cert_post_t;
+
+/**
+ * Private members of a ike_cert_post_t task.
+ */
+struct private_ike_cert_post_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ ike_cert_post_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Are we the initiator?
+ */
+ bool initiator;
+};
+
+/**
+ * Generates the cert payload, if possible with "Hash and URL"
+ */
+static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, certificate_t *cert)
+{
+ cert_payload_t *payload = NULL;
+
+ if (this->ike_sa->supports_extension(this->ike_sa, EXT_HASH_AND_URL))
+ {
+ /* ok, our peer sent us a HTTP_CERT_LOOKUP_SUPPORTED Notify */
+ hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+ if (hasher != NULL)
+ {
+ chunk_t hash, encoded = cert->get_encoding(cert);
+ enumerator_t *enumerator;
+ char *url;
+
+ hasher->allocate_hash(hasher, encoded, &hash);
+ identification_t *id = identification_create_from_encoding(ID_CERT_DER_SHA1, hash);
+
+ enumerator = charon->credentials->create_cdp_enumerator(charon->credentials, CERT_X509, id);
+ if (enumerator->enumerate(enumerator, &url))
+ {
+ /* if we have an URL available we send that to our peer */
+ payload = cert_payload_create_from_hash_and_url(hash, url);
+ }
+ enumerator->destroy(enumerator);
+
+ id->destroy(id);
+ chunk_free(&hash);
+ chunk_free(&encoded);
+ hasher->destroy(hasher);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "unable to use hash-and-url: sha1 not supported");
+ }
+ }
+
+ if (!payload)
+ {
+ /* our peer does not support "Hash and URL" or we do not have an URL
+ * to send to our peer, just create a normal cert payload */
+ payload = cert_payload_create_from_cert(cert);
+ }
+
+ return payload;
+}
+
+/**
+ * add certificates to message
+ */
+static void build_certs(private_ike_cert_post_t *this, message_t *message)
+{
+ peer_cfg_t *peer_cfg;
+
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+ if (peer_cfg && peer_cfg->get_auth_method(peer_cfg) == CONF_AUTH_PUBKEY)
+ {
+ switch (peer_cfg->get_cert_policy(peer_cfg))
+ {
+ case CERT_NEVER_SEND:
+ break;
+ case CERT_SEND_IF_ASKED:
+ if (!this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN))
+ {
+ break;
+ }
+ /* FALL */
+ case CERT_ALWAYS_SEND:
+ {
+ cert_payload_t *payload;
+ enumerator_t *enumerator;
+ certificate_t *cert;
+ auth_info_t *auth;
+ auth_item_t item;
+
+ auth = this->ike_sa->get_my_auth(this->ike_sa);
+ /* get subject cert first, then issuing certificates */
+ if (!auth->get_item(auth, AUTHZ_SUBJECT_CERT, (void**)&cert))
+ {
+ break;
+ }
+ payload = build_cert_payload(this, cert);
+ if (!payload)
+ {
+ break;
+ }
+ DBG1(DBG_IKE, "sending end entity cert \"%D\"",
+ cert->get_subject(cert));
+ message->add_payload(message, (payload_t*)payload);
+
+ enumerator = auth->create_item_enumerator(auth);
+ while (enumerator->enumerate(enumerator, &item, &cert))
+ {
+ if (item == AUTHZ_IM_CERT)
+ {
+ payload = cert_payload_create_from_cert(cert);
+ if (payload)
+ {
+ DBG1(DBG_IKE, "sending issuer cert \"%D\"",
+ cert->get_subject(cert));
+ message->add_payload(message, (payload_t*)payload);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ }
+ }
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t build_i(private_ike_cert_post_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ return NEED_MORE;
+ }
+ build_certs(this, message);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for responder
+ */
+static status_t process_r(private_ike_cert_post_t *this, message_t *message)
+{
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_cert_post_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ return NEED_MORE;
+ }
+ build_certs(this, message);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_cert_post_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ return NEED_MORE;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_cert_post_t *this)
+{
+ return IKE_CERT_POST;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_cert_post_t *this, ike_sa_t *ike_sa)
+{
+ this->ike_sa = ike_sa;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_cert_post_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator)
+{
+ private_ike_cert_post_t *this = malloc_thing(private_ike_cert_post_t);
+
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+
+ if (initiator)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ }
+
+ this->ike_sa = ike_sa;
+ this->initiator = initiator;
+
+ return &this->public;
+}
+
diff --git a/src/charon/sa/tasks/ike_cert_post.h b/src/charon/sa/tasks/ike_cert_post.h
new file mode 100644
index 000000000..78b32d67a
--- /dev/null
+++ b/src/charon/sa/tasks/ike_cert_post.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007-2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * $Id: ike_cert_post.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup ike_cert_post ike_cert_post
+ * @{ @ingroup tasks
+ */
+
+#ifndef IKE_CERT_POST_H_
+#define IKE_CERT_POST_H_
+
+typedef struct ike_cert_post_t ike_cert_post_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * Task of type ike_cert_post, certificate processing after authentication.
+ */
+struct ike_cert_post_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+};
+
+/**
+ * Create a new ike_cert_post task.
+ *
+ * The initiator parameter means the original initiator, not the initiator
+ * of the certificate request.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @param initiator TRUE if thask is the original initator
+ * @return ike_cert_post task to handle by the task_manager
+ */
+ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator);
+
+#endif /* IKE_CERT_POST_H_ @} */
diff --git a/src/charon/sa/tasks/ike_cert_pre.c b/src/charon/sa/tasks/ike_cert_pre.c
new file mode 100644
index 000000000..3568a214e
--- /dev/null
+++ b/src/charon/sa/tasks/ike_cert_pre.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2006-2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * $Id: ike_cert_pre.c 3852 2008-04-18 21:27:08Z andreas $
+ */
+
+#include "ike_cert_pre.h"
+
+#include <daemon.h>
+#include <sa/ike_sa.h>
+#include <encoding/payloads/cert_payload.h>
+#include <encoding/payloads/certreq_payload.h>
+#include <credentials/certificates/x509.h>
+
+
+typedef struct private_ike_cert_pre_t private_ike_cert_pre_t;
+
+/**
+ * Private members of a ike_cert_pre_t task.
+ */
+struct private_ike_cert_pre_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ ike_cert_pre_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Are we the initiator?
+ */
+ bool initiator;
+
+ /**
+ * Did we send a HTTP_CERT_LOOKUP_SUPPORTED Notify?
+ */
+ bool http_cert_lookup_supported_sent;
+};
+
+/**
+ * read certificate requests
+ */
+static void process_certreqs(private_ike_cert_pre_t *this, message_t *message)
+{
+ iterator_t *iterator;
+ payload_t *payload;
+ auth_info_t *auth;
+ bool ca_found = FALSE;
+
+ auth = this->ike_sa->get_my_auth(this->ike_sa);
+
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ switch(payload->get_type(payload))
+ {
+ case CERTIFICATE_REQUEST:
+ {
+ certreq_payload_t *certreq = (certreq_payload_t*)payload;
+ chunk_t keyid;
+ enumerator_t *enumerator;
+
+ this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE);
+
+ if (certreq->get_cert_type(certreq) != CERT_X509)
+ {
+ DBG1(DBG_IKE, "cert payload %N not supported - ignored",
+ certificate_type_names, certreq->get_cert_type(certreq));
+ break;
+ }
+ enumerator = certreq->create_keyid_enumerator(certreq);
+ while (enumerator->enumerate(enumerator, &keyid))
+ {
+ identification_t *id;
+ certificate_t *cert;
+
+ id = identification_create_from_encoding(
+ ID_PUBKEY_INFO_SHA1, keyid);
+ cert = charon->credentials->get_cert(charon->credentials,
+ CERT_X509, KEY_ANY, id, TRUE);
+ if (cert)
+ {
+ DBG1(DBG_IKE, "received cert request for \"%D\"",
+ cert->get_subject(cert));
+ auth->add_item(auth, AUTHN_CA_CERT, cert);
+ cert->destroy(cert);
+ ca_found = TRUE;
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received cert request for unknown ca "
+ "with keyid %D", id);
+ auth->add_item(auth, AUTHN_CA_CERT_KEYID, id);
+ }
+ id->destroy(id);
+ }
+ enumerator->destroy(enumerator);
+ break;
+ }
+ case NOTIFY:
+ {
+ notify_payload_t *notify = (notify_payload_t*)payload;
+
+ /* we only handle one type of notify here */
+ if (notify->get_notify_type(notify) == HTTP_CERT_LOOKUP_SUPPORTED)
+ {
+ this->ike_sa->enable_extension(this->ike_sa, EXT_HASH_AND_URL);
+ }
+ break;
+ }
+ default:
+ /* ignore other payloads here, these are handled elsewhere */
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * tries to extract a certificate from the cert payload or the credential
+ * manager (based on the hash of a "Hash and URL" encoded cert).
+ * Note: the returned certificate (if any) has to be destroyed
+ */
+static certificate_t *try_get_cert(cert_payload_t *cert_payload)
+{
+ certificate_t *cert = NULL;
+ switch (cert_payload->get_cert_encoding(cert_payload))
+ {
+ case ENC_X509_SIGNATURE:
+ {
+ cert = cert_payload->get_cert(cert_payload);
+ break;
+ }
+ case ENC_X509_HASH_AND_URL:
+ {
+ identification_t *id;
+ chunk_t hash = cert_payload->get_hash(cert_payload);
+ if (!hash.ptr)
+ {
+ /* invalid "Hash and URL" data (logged elsewhere) */
+ break;
+ }
+ id = identification_create_from_encoding(ID_CERT_DER_SHA1, hash);
+ cert = charon->credentials->get_cert(charon->credentials,
+ CERT_X509, KEY_ANY, id, FALSE);
+ id->destroy(id);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ return cert;
+}
+
+/**
+ * import certificates
+ */
+static void process_certs(private_ike_cert_pre_t *this, message_t *message)
+{
+ iterator_t *iterator;
+ payload_t *payload;
+ auth_info_t *auth;
+ bool first = TRUE;
+
+ auth = this->ike_sa->get_other_auth(this->ike_sa);
+
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ if (payload->get_type(payload) == CERTIFICATE)
+ {
+ cert_payload_t *cert_payload = (cert_payload_t*)payload;
+ cert_encoding_t type = cert_payload->get_cert_encoding(cert_payload);
+ switch (type)
+ {
+ case ENC_X509_SIGNATURE:
+ case ENC_X509_HASH_AND_URL:
+ {
+ if (type == ENC_X509_HASH_AND_URL &&
+ !this->http_cert_lookup_supported_sent)
+ {
+ DBG1(DBG_IKE, "received hash-and-url encoded cert, but"
+ " we don't accept them, ignore");
+ break;
+ }
+
+ certificate_t *cert = try_get_cert(cert_payload);
+
+ if (cert)
+ {
+ /* we've got a certificate from the payload or the cache */
+ if (first)
+ { /* the first certificate MUST be an end entity one */
+ DBG1(DBG_IKE, "received end entity cert \"%D\"",
+ cert->get_subject(cert));
+ auth->add_item(auth, AUTHN_SUBJECT_CERT, cert);
+ first = FALSE;
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received issuer cert \"%D\"",
+ cert->get_subject(cert));
+ auth->add_item(auth, AUTHN_IM_CERT, cert);
+ }
+ cert->destroy(cert);
+ }
+ else if (type == ENC_X509_HASH_AND_URL)
+ {
+ /* we received a "Hash and URL" encoded certificate that
+ * we haven't fetched yet, we store the URL and fetch
+ * it later */
+ char *url = cert_payload->get_url(cert_payload);
+ if (!url)
+ {
+ DBG1(DBG_IKE, "received invalid hash-and-url encoded"
+ " cert, ignore");
+ break;
+ }
+
+ if (first)
+ { /* the first certificate MUST be an end entity one */
+ DBG1(DBG_IKE, "received hash-and-url for end"
+ " entity cert \"%s\"", url);
+ auth->add_item(auth, AUTHN_SUBJECT_HASH_URL, url);
+ first = FALSE;
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received hash-and-url for issuer"
+ " cert \"%s\"", url);
+ auth->add_item(auth, AUTHN_IM_HASH_URL, url);
+ }
+ }
+ break;
+ }
+ case ENC_PKCS7_WRAPPED_X509:
+ case ENC_PGP:
+ case ENC_DNS_SIGNED_KEY:
+ case ENC_KERBEROS_TOKEN:
+ case ENC_CRL:
+ case ENC_ARL:
+ case ENC_SPKI:
+ case ENC_X509_ATTRIBUTE:
+ case ENC_RAW_RSA_KEY:
+ case ENC_X509_HASH_AND_URL_BUNDLE:
+ case ENC_OCSP_CONTENT:
+ default:
+ DBG1(DBG_ENC, "certificate encoding %N not supported",
+ cert_encoding_names, cert_payload->get_cert_encoding(cert_payload));
+ }
+ }
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * add a certificate request to the message, building request payload if required.
+ */
+static void add_certreq_payload(message_t *message, certreq_payload_t **reqp,
+ certificate_t *cert)
+{
+ public_key_t *public;
+ certreq_payload_t *req;
+
+ public = cert->get_public_key(cert);
+ if (!public)
+ {
+ return;
+ }
+ switch (cert->get_type(cert))
+ {
+ case CERT_X509:
+ {
+ identification_t *keyid;
+ x509_t *x509 = (x509_t*)cert;
+
+ if (!(x509->get_flags(x509) & X509_CA))
+ { /* no CA cert, skip */
+ break;
+ }
+ if (*reqp == NULL)
+ {
+ *reqp = certreq_payload_create_type(CERT_X509);
+ message->add_payload(message, (payload_t*)*reqp);
+ }
+ req = *reqp;
+ keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1);
+ req->add_keyid(req, keyid->get_encoding(keyid));
+ DBG1(DBG_IKE, "sending cert request for \"%D\"",
+ cert->get_subject(cert));
+ break;
+ }
+ default:
+ break;
+ }
+ public->destroy(public);
+}
+
+/**
+ * build certificate requests
+ */
+static void build_certreqs(private_ike_cert_pre_t *this, message_t *message)
+{
+ ike_cfg_t *ike_cfg;
+ enumerator_t *enumerator;
+ certificate_t *cert;
+ auth_info_t *auth;
+ bool restricted = FALSE;
+ auth_item_t item;
+ certreq_payload_t *x509_req = NULL;
+
+ ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
+ if (!ike_cfg->send_certreq(ike_cfg))
+ {
+ return;
+ }
+ auth = this->ike_sa->get_other_auth(this->ike_sa);
+
+ /* check if we require a specific CA for that peer */
+ enumerator = auth->create_item_enumerator(auth);
+ while (enumerator->enumerate(enumerator, &item, &cert))
+ {
+ if (item == AUTHN_CA_CERT)
+ {
+ restricted = TRUE;
+ add_certreq_payload(message, &x509_req, cert);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (!restricted)
+ {
+ /* otherwise include all trusted CA certificates */
+ enumerator = charon->credentials->create_cert_enumerator(
+ charon->credentials, CERT_ANY, KEY_ANY, NULL, TRUE);
+ while (enumerator->enumerate(enumerator, &cert, TRUE))
+ {
+ add_certreq_payload(message, &x509_req, cert);
+ }
+ enumerator->destroy(enumerator);
+ }
+
+ /* if we've added at least one certreq, we notify our peer that we support
+ * "Hash and URL" for the requested certificates */
+ if (lib->settings->get_bool(lib->settings, "charon.hash_and_url", FALSE) &&
+ message->get_payload(message, CERTIFICATE_REQUEST))
+ {
+ message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED, chunk_empty);
+ this->http_cert_lookup_supported_sent = TRUE;
+ }
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t build_i(private_ike_cert_pre_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ return NEED_MORE;
+ }
+ build_certreqs(this, message);
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for responder
+ */
+static status_t process_r(private_ike_cert_pre_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ return NEED_MORE;
+ }
+ process_certreqs(this, message);
+ process_certs(this, message);
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_cert_pre_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ build_certreqs(this, message);
+ return NEED_MORE;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_cert_pre_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ process_certreqs(this, message);
+ return NEED_MORE;
+ }
+ process_certs(this, message);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_cert_pre_t *this)
+{
+ return IKE_CERT_PRE;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_cert_pre_t *this, ike_sa_t *ike_sa)
+{
+ this->ike_sa = ike_sa;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_cert_pre_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator)
+{
+ private_ike_cert_pre_t *this = malloc_thing(private_ike_cert_pre_t);
+
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+
+ if (initiator)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ }
+
+ this->ike_sa = ike_sa;
+ this->initiator = initiator;
+ this->http_cert_lookup_supported_sent = FALSE;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_cert.h b/src/charon/sa/tasks/ike_cert_pre.h
index ba0283953..d8793a8e2 100644
--- a/src/charon/sa/tasks/ike_cert.h
+++ b/src/charon/sa/tasks/ike_cert_pre.h
@@ -1,12 +1,5 @@
-/**
- * @file ike_cert.h
- *
- * @brief Interface ike_cert_t.
- *
- */
-
/*
- * Copyright (C) 2007 Martin Willi
+ * Copyright (C) 2007-2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -18,27 +11,28 @@
* 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.
+ *
+ * $Id: ike_cert_pre.h 3589 2008-03-13 14:14:44Z martin $
*/
-#ifndef IKE_CERT_H_
-#define IKE_CERT_H_
+/**
+ * @defgroup ike_cert_pre ike_cert_pre
+ * @{ @ingroup tasks
+ */
-typedef struct ike_cert_t ike_cert_t;
+#ifndef IKE_CERT_PRE_H_
+#define IKE_CERT_PRE_H_
+
+typedef struct ike_cert_pre_t ike_cert_pre_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
- * @brief Task of type ike_cert, exchanges certificates and
- * certificate requests.
- *
- * @b Constructors:
- * - ike_cert_create()
- *
- * @ingroup tasks
+ * Task of type ike_cert_post, certificate processing before authentication.
*/
-struct ike_cert_t {
+struct ike_cert_pre_t {
/**
* Implements the task_t interface
@@ -47,15 +41,15 @@ struct ike_cert_t {
};
/**
- * @brief Create a new ike_cert task.
+ * Create a new ike_cert_pre task.
*
* The initiator parameter means the original initiator, not the initiator
* of the certificate request.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if thask is the original initator
- * @return ike_cert task to handle by the task_manager
+ * @return ike_cert_pre task to handle by the task_manager
*/
-ike_cert_t *ike_cert_create(ike_sa_t *ike_sa, bool initiator);
+ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator);
-#endif /* IKE_CERT_H_ */
+#endif /* IKE_CERT_PRE_H_ @} */
diff --git a/src/charon/sa/tasks/ike_config.c b/src/charon/sa/tasks/ike_config.c
index 3c73395a5..c31e62750 100644
--- a/src/charon/sa/tasks/ike_config.c
+++ b/src/charon/sa/tasks/ike_config.c
@@ -1,10 +1,3 @@
-/**
- * @file ike_config.c
- *
- * @brief Implementation of the ike_config task.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
@@ -19,6 +12,8 @@
* 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.
+ *
+ * $Id: ike_config.c 3800 2008-04-14 07:18:16Z martin $
*/
#include "ike_config.h"
@@ -266,14 +261,14 @@ static status_t build_i(private_ike_config_t *this, message_t *message)
/* reuse virtual IP if we already have one */
vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
- if (vip)
+ if (!vip)
{
- this->virtual_ip = vip->clone(vip);
+ config = this->ike_sa->get_peer_cfg(this->ike_sa);
+ vip = config->get_virtual_ip(config);
}
- else
+ if (vip)
{
- config = this->ike_sa->get_peer_cfg(this->ike_sa);
- this->virtual_ip = config->get_my_virtual_ip(config);
+ this->virtual_ip = vip->clone(vip);
}
build_payloads(this, message, CFG_REQUEST);
@@ -307,14 +302,20 @@ static status_t build_r(private_ike_config_t *this, message_t *message)
if (config && this->virtual_ip)
{
- host_t *ip;
+ host_t *ip = NULL;
DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
- ip = config->get_other_virtual_ip(config, this->virtual_ip);
- if (ip == NULL || ip->is_anyaddr(ip))
+ if (config->get_pool(config))
+ {
+ ip = charon->attributes->acquire_address(charon->attributes,
+ config->get_pool(config),
+ this->ike_sa->get_other_id(this->ike_sa),
+ this->ike_sa->get_other_auth(this->ike_sa),
+ this->virtual_ip);
+ }
+ if (ip == NULL)
{
DBG1(DBG_IKE, "not assigning a virtual IP to peer");
- DESTROY_IF(ip);
return SUCCESS;
}
DBG1(DBG_IKE, "assigning virtual IP %H to peer", ip);
@@ -323,16 +324,6 @@ static status_t build_r(private_ike_config_t *this, message_t *message)
this->virtual_ip->destroy(this->virtual_ip);
this->virtual_ip = ip;
- /* DNS testing values
- if (this->dns->remove_last(this->dns, (void**)&ip) == SUCCESS)
- {
- ip->destroy(ip);
- ip = host_create_from_string("10.3.0.1", 0);
- this->dns->insert_last(this->dns, ip);
- ip = host_create_from_string("10.3.0.2", 0);
- this->dns->insert_last(this->dns, ip);
- } */
-
build_payloads(this, message, CFG_REPLY);
}
return SUCCESS;
@@ -359,7 +350,11 @@ static status_t process_i(private_ike_config_t *this, message_t *message)
if (this->virtual_ip == NULL)
{ /* force a configured virtual IP, even server didn't return one */
config = this->ike_sa->get_peer_cfg(this->ike_sa);
- this->virtual_ip = config->get_my_virtual_ip(config);
+ this->virtual_ip = config->get_virtual_ip(config);
+ if (this->virtual_ip)
+ {
+ this->virtual_ip = this->virtual_ip->clone(this->virtual_ip);
+ }
}
if (this->virtual_ip && !this->virtual_ip->is_anyaddr(this->virtual_ip))
diff --git a/src/charon/sa/tasks/ike_config.h b/src/charon/sa/tasks/ike_config.h
index a7cfddff0..23410a196 100644
--- a/src/charon/sa/tasks/ike_config.h
+++ b/src/charon/sa/tasks/ike_config.h
@@ -1,10 +1,3 @@
-/**
- * @file ike_config.h
- *
- * @brief Interface ike_config_t.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: ike_config.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup ike_config ike_config
+ * @{ @ingroup tasks
*/
#ifndef IKE_CONFIG_H_
@@ -30,13 +30,8 @@ typedef struct ike_config_t ike_config_t;
#include <sa/tasks/task.h>
/**
- * @brief Task of type IKE_CONFIG, sets up a virtual IP and other
+ * Task of type IKE_CONFIG, sets up a virtual IP and other
* configurations for an IKE_SA.
- *
- * @b Constructors:
- * - ike_config_create()
- *
- * @ingroup tasks
*/
struct ike_config_t {
@@ -47,7 +42,7 @@ struct ike_config_t {
};
/**
- * @brief Create a new ike_config task.
+ * Create a new ike_config task.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE for initiator
@@ -55,4 +50,4 @@ struct ike_config_t {
*/
ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator);
-#endif /* IKE_CONFIG_H_ */
+#endif /* IKE_CONFIG_H_ @} */
diff --git a/src/charon/sa/tasks/ike_delete.c b/src/charon/sa/tasks/ike_delete.c
index 1a3656ca6..aa7950ef7 100644
--- a/src/charon/sa/tasks/ike_delete.c
+++ b/src/charon/sa/tasks/ike_delete.c
@@ -1,10 +1,3 @@
-/**
- * @file ike_delete.c
- *
- * @brief Implementation of the ike_delete task.
- *
- */
-
/*
* Copyright (C) 2006-2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,8 @@
* 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.
+ *
+ * $Id: ike_delete.c 3802 2008-04-14 08:17:18Z martin $
*/
#include "ike_delete.h"
@@ -87,18 +82,18 @@ static status_t process_r(private_ike_delete_t *this, message_t *message)
* come so far without being correct */
switch (this->ike_sa->get_state(this->ike_sa))
{
- case IKE_DELETING:
- this->simultaneous = TRUE;
- break;
case IKE_ESTABLISHED:
DBG1(DBG_IKE, "deleting IKE_SA on request");
+ this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
+ this->ike_sa->reestablish(this->ike_sa);
break;
- case IKE_REKEYING:
- break;
+ case IKE_DELETING:
+ this->simultaneous = TRUE;
+ /* FALL */
default:
+ this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
break;
}
- this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
return NEED_MORE;
}
diff --git a/src/charon/sa/tasks/ike_delete.h b/src/charon/sa/tasks/ike_delete.h
index e8ec5ebbe..6d08d345d 100644
--- a/src/charon/sa/tasks/ike_delete.h
+++ b/src/charon/sa/tasks/ike_delete.h
@@ -1,10 +1,3 @@
-/**
- * @file ike_delete.h
- *
- * @brief Interface ike_delete_t.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: ike_delete.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup ike_delete ike_delete
+ * @{ @ingroup tasks
*/
#ifndef IKE_DELETE_H_
@@ -30,12 +30,7 @@ typedef struct ike_delete_t ike_delete_t;
#include <sa/tasks/task.h>
/**
- * @brief Task of type ike_delete, delete an IKE_SA.
- *
- * @b Constructors:
- * - ike_delete_create()
- *
- * @ingroup tasks
+ * Task of type ike_delete, delete an IKE_SA.
*/
struct ike_delete_t {
@@ -46,7 +41,7 @@ struct ike_delete_t {
};
/**
- * @brief Create a new ike_delete task.
+ * Create a new ike_delete task.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if we initiate the delete
@@ -54,4 +49,4 @@ struct ike_delete_t {
*/
ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator);
-#endif /* IKE_DELETE_H_ */
+#endif /* IKE_DELETE_H_ @} */
diff --git a/src/charon/sa/tasks/ike_dpd.c b/src/charon/sa/tasks/ike_dpd.c
index be751766e..9f1d43cbf 100644
--- a/src/charon/sa/tasks/ike_dpd.c
+++ b/src/charon/sa/tasks/ike_dpd.c
@@ -1,10 +1,3 @@
-/**
- * @file ike_dpd.c
- *
- * @brief Implementation of the ike_dpd task.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,8 @@
* 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.
+ *
+ * $Id: ike_dpd.c 3589 2008-03-13 14:14:44Z martin $
*/
#include "ike_dpd.h"
diff --git a/src/charon/sa/tasks/ike_dpd.h b/src/charon/sa/tasks/ike_dpd.h
index 531b0502d..62b8a6a10 100644
--- a/src/charon/sa/tasks/ike_dpd.h
+++ b/src/charon/sa/tasks/ike_dpd.h
@@ -1,10 +1,3 @@
-/**
- * @file ike_dpd.h
- *
- * @brief Interface ike_dpd_t.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: ike_dpd.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup ike_dpd ike_dpd
+ * @{ @ingroup tasks
*/
#ifndef IKE_DPD_H_
@@ -30,14 +30,9 @@ typedef struct ike_dpd_t ike_dpd_t;
#include <sa/tasks/task.h>
/**
- * @brief Task of type ike_dpd, detects dead peers.
+ * Task of type ike_dpd, detects dead peers.
*
* The DPD task actually does nothing, as a DPD has no associated payloads.
- *
- * @b Constructors:
- * - ike_dpd_create()
- *
- * @ingroup tasks
*/
struct ike_dpd_t {
@@ -48,11 +43,11 @@ struct ike_dpd_t {
};
/**
- * @brief Create a new ike_dpd task.
+ * Create a new ike_dpd task.
*
* @param initiator TRUE if thask is the original initator
* @return ike_dpd task to handle by the task_manager
*/
ike_dpd_t *ike_dpd_create(bool initiator);
-#endif /* IKE_DPD_H_ */
+#endif /* IKE_DPD_H_ @} */
diff --git a/src/charon/sa/tasks/ike_init.c b/src/charon/sa/tasks/ike_init.c
index 42b47a82f..7def3a556 100644
--- a/src/charon/sa/tasks/ike_init.c
+++ b/src/charon/sa/tasks/ike_init.c
@@ -1,11 +1,5 @@
-/**
- * @file ike_init.c
- *
- * @brief Implementation of the ike_init task.
- *
- */
-
/*
+ * Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -19,6 +13,8 @@
* 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.
+ *
+ * $Id: ike_init.c 4086 2008-06-22 11:24:33Z andreas $
*/
#include "ike_init.h"
@@ -195,7 +191,7 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
this->dh_group = ke_payload->get_dh_group_number(ke_payload);
if (!this->initiator)
{
- this->dh = diffie_hellman_create(this->dh_group);
+ this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
}
if (this->dh)
{
@@ -222,13 +218,12 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
*/
static status_t build_i(private_ike_init_t *this, message_t *message)
{
- randomizer_t *randomizer;
- status_t status;
+ rng_t *rng;
this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
SIG(IKE_UP_START, "initiating IKE_SA '%s' to %H",
this->ike_sa->get_name(this->ike_sa),
- this->config->get_other_host(this->config));
+ this->ike_sa->get_other_host(this->ike_sa));
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
if (this->retry++ >= MAX_RETRIES)
@@ -241,7 +236,7 @@ static status_t build_i(private_ike_init_t *this, message_t *message)
if (!this->dh)
{
this->dh_group = this->config->get_dh_group(this->config);
- this->dh = diffie_hellman_create(this->dh_group);
+ this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
if (this->dh == NULL)
{
SIG(IKE_UP_FAILED, "configured DH group %N not supported",
@@ -253,15 +248,14 @@ static status_t build_i(private_ike_init_t *this, message_t *message)
/* generate nonce only when we are trying the first time */
if (this->my_nonce.ptr == NULL)
{
- randomizer = randomizer_create();
- status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
- &this->my_nonce);
- randomizer->destroy(randomizer);
- if (status != SUCCESS)
+ rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+ if (!rng)
{
- SIG(IKE_UP_FAILED, "error generating random nonce value");
+ SIG(IKE_UP_FAILED, "error generating nonce");
return FAILED;
}
+ rng->allocate_bytes(rng, NONCE_SIZE, &this->my_nonce);
+ rng->destroy(rng);
}
if (this->cookie.ptr)
@@ -270,30 +264,90 @@ static status_t build_i(private_ike_init_t *this, message_t *message)
}
build_payloads(this, message);
-
+
+#ifdef ME
+ {
+ chunk_t connect_id = this->ike_sa->get_connect_id(this->ike_sa);
+ if (connect_id.ptr)
+ {
+ message->add_notify(message, FALSE, ME_CONNECTID, connect_id);
+ }
+ }
+#endif /* ME */
return NEED_MORE;
}
/**
- * Implementation of task_t.process for initiator
+ * Implementation of task_t.process for responder
*/
static status_t process_r(private_ike_init_t *this, message_t *message)
{
- randomizer_t *randomizer;
+ rng_t *rng;
this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
- SIG(IKE_UP_FAILED, "%H is initiating an IKE_SA",
+ SIG(IKE_UP_START, "%H is initiating an IKE_SA",
message->get_source(message));
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
- randomizer = randomizer_create();
- if (randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
- &this->my_nonce) != SUCCESS)
+ rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+ if (!rng)
+ {
+ DBG1(DBG_IKE, "error generating nonce");
+ return FAILED;
+ }
+ rng->allocate_bytes(rng, NONCE_SIZE, &this->my_nonce);
+ rng->destroy(rng);
+
+#ifdef ME
{
- DBG1(DBG_IKE, "error generating random nonce value");
+ chunk_t connect_id = chunk_empty;
+ iterator_t *iterator;
+ payload_t *payload;
+
+ /* check for a ME_CONNECTID notify */
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ if (payload->get_type(payload) == NOTIFY)
+ {
+ notify_payload_t *notify = (notify_payload_t*)payload;
+ notify_type_t type = notify->get_notify_type(notify);
+
+ switch (type)
+ {
+ case ME_CONNECTID:
+ {
+ chunk_free(&connect_id);
+ connect_id = chunk_clone(notify->get_notification_data(notify));
+ DBG2(DBG_IKE, "received ME_CONNECTID %#B", &connect_id);
+ break;
+ }
+ default:
+ {
+ if (type < 16383)
+ {
+ DBG1(DBG_IKE, "received %N notify error",
+ notify_type_names, type);
+ break;
+ }
+ DBG2(DBG_IKE, "received %N notify",
+ notify_type_names, type);
+ break;
+ }
+ }
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (connect_id.ptr)
+ {
+ charon->connect_manager->stop_checks(charon->connect_manager,
+ connect_id);
+ chunk_free(&connect_id);
+ }
}
- randomizer->destroy(randomizer);
+#endif /* ME */
process_payloads(this, message);
@@ -321,11 +375,11 @@ static status_t build_r(private_ike_init_t *this, message_t *message)
!this->proposal->has_dh_group(this->proposal, this->dh_group) ||
this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
{
- algorithm_t *algo;
+ u_int16_t group;
+
if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
- &algo))
+ &group, NULL))
{
- u_int16_t group = algo->algorithm;
SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N",
diffie_hellman_group_names, this->dh_group,
diffie_hellman_group_names, group);
@@ -370,9 +424,16 @@ static status_t build_r(private_ike_init_t *this, message_t *message)
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
return FAILED;
}
-
- build_payloads(this, message);
+ /* Keep the selected IKE proposal for status information purposes */
+ {
+ char buf[BUF_LEN];
+
+ snprintf(buf, BUF_LEN, "%P", this->proposal);
+ this->ike_sa->set_proposal(this->ike_sa, buf+4);
+ }
+
+ build_payloads(this, message);
return SUCCESS;
}
@@ -427,7 +488,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message)
this->cookie = chunk_clone(notify->get_notification_data(notify));
this->ike_sa->reset(this->ike_sa);
iterator->destroy(iterator);
- DBG1(DBG_IKE, "received %N notify", notify_type_names, type);
+ DBG2(DBG_IKE, "received %N notify", notify_type_names, type);
return NEED_MORE;
}
default:
@@ -439,7 +500,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message)
iterator->destroy(iterator);
return FAILED;
}
- DBG1(DBG_IKE, "received %N notify",
+ DBG2(DBG_IKE, "received %N notify",
notify_type_names, type);
break;
}
@@ -454,7 +515,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message)
if (this->proposal == NULL ||
this->other_nonce.len == 0 || this->my_nonce.len == 0)
{
- SIG(IKE_UP_FAILED, "peers proposal selection invalid");
+ SIG(IKE_UP_FAILED, "peer's proposal selection invalid");
return FAILED;
}
@@ -462,7 +523,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message)
!this->proposal->has_dh_group(this->proposal, this->dh_group) ||
this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
{
- SIG(IKE_UP_FAILED, "peers DH group selection invalid");
+ SIG(IKE_UP_FAILED, "peer's DH group selection invalid");
return FAILED;
}
@@ -494,6 +555,15 @@ static status_t process_i(private_ike_init_t *this, message_t *message)
SIG(IKE_UP_FAILED, "key derivation failed");
return FAILED;
}
+
+ /* Keep the selected IKE proposal for status information purposes */
+ {
+ char buf[BUF_LEN];
+
+ snprintf(buf, BUF_LEN, "%P", this->proposal);
+ this->ike_sa->set_proposal(this->ike_sa, buf+4);
+ }
+
return SUCCESS;
}
@@ -532,7 +602,7 @@ static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
this->ike_sa = ike_sa;
this->proposal = NULL;
- this->dh = diffie_hellman_create(this->dh_group);
+ this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
}
/**
diff --git a/src/charon/sa/tasks/ike_init.h b/src/charon/sa/tasks/ike_init.h
index f60c096e8..0e5a913fd 100644
--- a/src/charon/sa/tasks/ike_init.h
+++ b/src/charon/sa/tasks/ike_init.h
@@ -1,10 +1,3 @@
-/**
- * @file ike_init.h
- *
- * @brief Interface ike_init_t.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: ike_init.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup ike_init ike_init
+ * @{ @ingroup tasks
*/
#ifndef IKE_INIT_H_
@@ -30,14 +30,9 @@ typedef struct ike_init_t ike_init_t;
#include <sa/tasks/task.h>
/**
- * @brief Task of type IKE_INIT, creates an IKE_SA without authentication.
+ * Task of type IKE_INIT, creates an IKE_SA without authentication.
*
* The authentication of is handle in the ike_auth task.
- *
- * @b Constructors:
- * - ike_init_create()
- *
- * @ingroup tasks
*/
struct ike_init_t {
@@ -47,16 +42,15 @@ struct ike_init_t {
task_t task;
/**
- * @brief Get the lower of the two nonces, used for rekey collisions.
+ * Get the lower of the two nonces, used for rekey collisions.
*
- * @param this calling object
* @return lower nonce
*/
chunk_t (*get_lower_nonce) (ike_init_t *this);
};
/**
- * @brief Create a new IKE_INIT task.
+ * Create a new IKE_INIT task.
*
* @param ike_sa IKE_SA this task works for (new one when rekeying)
* @param initiator TRUE if thask is the original initator
@@ -65,4 +59,4 @@ struct ike_init_t {
*/
ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa);
-#endif /* IKE_INIT_H_ */
+#endif /* IKE_INIT_H_ @} */
diff --git a/src/charon/sa/tasks/ike_p2p.c b/src/charon/sa/tasks/ike_me.c
index 84b88e16b..2d7c64d70 100644
--- a/src/charon/sa/tasks/ike_p2p.c
+++ b/src/charon/sa/tasks/ike_me.c
@@ -1,12 +1,5 @@
-/**
- * @file ike_p2p.c
- *
- * @brief Implementation of the ike_p2p task.
- *
- */
-
/*
- * Copyright (C) 2007 Tobias Brunner
+ * Copyright (C) 2007-2008 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -18,9 +11,11 @@
* 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.
+ *
+ * $Id: ike_me.c 3806 2008-04-15 05:56:35Z martin $
*/
-
-#include "ike_p2p.h"
+
+#include "ike_me.h"
#include <string.h>
@@ -31,27 +26,20 @@
#include <encoding/payloads/endpoint_notify.h>
#include <processing/jobs/mediation_job.h>
-#define P2P_SESSIONID_LEN 8
-#define P2P_SESSIONKEY_LEN 16
+#define ME_CONNECTID_LEN 4
+#define ME_CONNECTKEY_LEN 16
-/* FIXME: proposed values */
-#define P2P_SESSIONID_MIN_LEN 4
-#define P2P_SESSIONID_MAX_LEN 16
-#define P2P_SESSIONKEY_MIN_LEN 8
-#define P2P_SESSIONKEY_MAX_LEN 64
-
-
-typedef struct private_ike_p2p_t private_ike_p2p_t;
+typedef struct private_ike_me_t private_ike_me_t;
/**
- * Private members of a ike_p2p_t task.
+ * Private members of a ike_me_t task.
*/
-struct private_ike_p2p_t {
+struct private_ike_me_t {
/**
* Public methods and task_t interface.
*/
- ike_p2p_t public;
+ ike_me_t public;
/**
* Assigned IKE_SA.
@@ -105,12 +93,12 @@ struct private_ike_p2p_t {
/**
* Received ID used for connectivity checks
*/
- chunk_t session_id;
+ chunk_t connect_id;
/**
* Received key used for connectivity checks
*/
- chunk_t session_key;
+ chunk_t connect_key;
/**
* Peer config of the mediated connection
@@ -138,7 +126,7 @@ static void add_endpoints_to_message(message_t *message, linked_list_t *endpoint
/**
* Gathers endpoints and adds them to the current message
*/
-static void gather_and_add_endpoints(private_ike_p2p_t *this, message_t *message)
+static void gather_and_add_endpoints(private_ike_me_t *this, message_t *message)
{
iterator_t *iterator;
host_t *addr, *host;
@@ -176,7 +164,7 @@ static void gather_and_add_endpoints(private_ike_p2p_t *this, message_t *message
/**
* read notifys from message and evaluate them
*/
-static void process_payloads(private_ike_p2p_t *this, message_t *message)
+static void process_payloads(private_ike_me_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
@@ -193,55 +181,55 @@ static void process_payloads(private_ike_p2p_t *this, message_t *message)
switch (notify->get_notify_type(notify))
{
- case P2P_CONNECT_FAILED:
+ case ME_CONNECT_FAILED:
{
- DBG2(DBG_IKE, "received P2P_CONNECT_FAILED notify");
+ DBG2(DBG_IKE, "received ME_CONNECT_FAILED notify");
this->failed = TRUE;
break;
}
- case P2P_MEDIATION:
+ case ME_MEDIATION:
{
- DBG2(DBG_IKE, "received P2P_MEDIATION notify");
+ DBG2(DBG_IKE, "received ME_MEDIATION notify");
this->mediation = TRUE;
break;
}
- case P2P_ENDPOINT:
+ case ME_ENDPOINT:
{
endpoint_notify_t *endpoint = endpoint_notify_create_from_payload(notify);
if (!endpoint)
{
- DBG1(DBG_IKE, "received invalid P2P_ENDPOINT notify");
+ DBG1(DBG_IKE, "received invalid ME_ENDPOINT notify");
break;
}
- DBG1(DBG_IKE, "received %N P2P_ENDPOINT %#H", p2p_endpoint_type_names,
+ DBG1(DBG_IKE, "received %N ME_ENDPOINT %#H", me_endpoint_type_names,
endpoint->get_type(endpoint), endpoint->get_host(endpoint));
this->remote_endpoints->insert_last(this->remote_endpoints, endpoint);
break;
}
- case P2P_CALLBACK:
+ case ME_CALLBACK:
{
- DBG2(DBG_IKE, "received P2P_CALLBACK notify");
+ DBG2(DBG_IKE, "received ME_CALLBACK notify");
this->callback = TRUE;
break;
}
- case P2P_SESSIONID:
+ case ME_CONNECTID:
{
- chunk_free(&this->session_id);
- this->session_id = chunk_clone(notify->get_notification_data(notify));
- DBG3(DBG_IKE, "received p2p_sessionid %B", &this->session_id);
+ chunk_free(&this->connect_id);
+ this->connect_id = chunk_clone(notify->get_notification_data(notify));
+ DBG2(DBG_IKE, "received ME_CONNECTID %#B", &this->connect_id);
break;
}
- case P2P_SESSIONKEY:
+ case ME_CONNECTKEY:
{
- chunk_free(&this->session_key);
- this->session_key = chunk_clone(notify->get_notification_data(notify));
- DBG4(DBG_IKE, "received p2p_sessionkey %B", &this->session_key);
+ chunk_free(&this->connect_key);
+ this->connect_key = chunk_clone(notify->get_notification_data(notify));
+ DBG4(DBG_IKE, "received ME_CONNECTKEY %#B", &this->connect_key);
break;
}
- case P2P_RESPONSE:
+ case ME_RESPONSE:
{
- DBG2(DBG_IKE, "received P2P_RESPONSE notify");
+ DBG2(DBG_IKE, "received ME_RESPONSE notify");
this->response = TRUE;
break;
}
@@ -253,9 +241,9 @@ static void process_payloads(private_ike_p2p_t *this, message_t *message)
}
/**
- * Implementation of task_t.process for initiator
+ * Implementation of task_t.build for initiator
*/
-static status_t build_i(private_ike_p2p_t *this, message_t *message)
+static status_t build_i(private_ike_me_t *this, message_t *message)
{
switch(message->get_exchange_type(message))
{
@@ -264,8 +252,8 @@ static status_t build_i(private_ike_p2p_t *this, message_t *message)
peer_cfg_t *peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
if (peer_cfg->is_mediation(peer_cfg))
{
- DBG2(DBG_IKE, "adding P2P_MEDIATION");
- message->add_notify(message, FALSE, P2P_MEDIATION, chunk_empty);
+ DBG2(DBG_IKE, "adding ME_MEDIATION");
+ message->add_notify(message, FALSE, ME_MEDIATION, chunk_empty);
}
else
{
@@ -283,48 +271,40 @@ static status_t build_i(private_ike_p2p_t *this, message_t *message)
}
break;
}
- case P2P_CONNECT:
+ case ME_CONNECT:
{
id_payload_t *id_payload;
- randomizer_t *rand = randomizer_create();
+ rng_t *rng;
id_payload = id_payload_create_from_identification(ID_PEER, this->peer_id);
message->add_payload(message, (payload_t*)id_payload);
- if (!this->response)
+ rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
+ if (!rng)
{
- /* only the initiator creates a session ID. the responder returns
- * the session ID that it received from the initiator */
- if (rand->allocate_pseudo_random_bytes(rand,
- P2P_SESSIONID_LEN, &this->session_id) != SUCCESS)
- {
- DBG1(DBG_IKE, "unable to generate session ID for P2P_CONNECT");
- rand->destroy(rand);
- return FAILED;
- }
+ DBG1(DBG_IKE, "unable to generate connect ID for ME_CONNECT");
+ return FAILED;
}
-
- if (rand->allocate_pseudo_random_bytes(rand,
- P2P_SESSIONKEY_LEN, &this->session_key) != SUCCESS)
+ if (!this->response)
{
- DBG1(DBG_IKE, "unable to generate session key for P2P_CONNECT");
- rand->destroy(rand);
- return FAILED;
+ /* only the initiator creates a connect ID. the responder returns
+ * the connect ID that it received from the initiator */
+ rng->allocate_bytes(rng, ME_CONNECTID_LEN, &this->connect_id);
}
+ rng->allocate_bytes(rng, ME_CONNECTKEY_LEN, &this->connect_key);
+ rng->destroy(rng);
- rand->destroy(rand);
-
- message->add_notify(message, FALSE, P2P_SESSIONID, this->session_id);
- message->add_notify(message, FALSE, P2P_SESSIONKEY, this->session_key);
+ message->add_notify(message, FALSE, ME_CONNECTID, this->connect_id);
+ message->add_notify(message, FALSE, ME_CONNECTKEY, this->connect_key);
if (this->response)
{
- message->add_notify(message, FALSE, P2P_RESPONSE, chunk_empty);
+ message->add_notify(message, FALSE, ME_RESPONSE, chunk_empty);
}
else
{
- /* FIXME: should we make that configurable */
- message->add_notify(message, FALSE, P2P_CALLBACK, chunk_empty);
+ /* FIXME: should we make that configurable? */
+ message->add_notify(message, FALSE, ME_CALLBACK, chunk_empty);
}
gather_and_add_endpoints(this, message);
@@ -340,17 +320,17 @@ static status_t build_i(private_ike_p2p_t *this, message_t *message)
/**
* Implementation of task_t.process for responder
*/
-static status_t process_r(private_ike_p2p_t *this, message_t *message)
+static status_t process_r(private_ike_me_t *this, message_t *message)
{
switch(message->get_exchange_type(message))
{
- case P2P_CONNECT:
+ case ME_CONNECT:
{
id_payload_t *id_payload;
id_payload = (id_payload_t*)message->get_payload(message, ID_PEER);
if (!id_payload)
{
- DBG1(DBG_IKE, "received P2P_CONNECT without ID_PEER payload, aborting");
+ DBG1(DBG_IKE, "received ME_CONNECT without ID_PEER payload, aborting");
break;
}
this->peer_id = id_payload->get_identification(id_payload);
@@ -359,32 +339,32 @@ static status_t process_r(private_ike_p2p_t *this, message_t *message)
if (this->callback)
{
- DBG1(DBG_IKE, "received P2P_CALLBACK for '%D'", this->peer_id);
+ DBG1(DBG_IKE, "received ME_CALLBACK for '%D'", this->peer_id);
break;
}
- if (!this->session_id.ptr)
+ if (!this->connect_id.ptr)
{
- DBG1(DBG_IKE, "received P2P_CONNECT without P2P_SESSIONID notify, aborting");
+ DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTID notify, aborting");
this->invalid_syntax = TRUE;
break;
}
- if (!this->session_key.ptr)
+ if (!this->connect_key.ptr)
{
- DBG1(DBG_IKE, "received P2P_CONNECT without P2P_SESSIONKEY notify, aborting");
+ DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTKEY notify, aborting");
this->invalid_syntax = TRUE;
break;
}
if (!this->remote_endpoints->get_count(this->remote_endpoints))
{
- DBG1(DBG_IKE, "received P2P_CONNECT without any P2P_ENDPOINT payloads, aborting");
+ DBG1(DBG_IKE, "received ME_CONNECT without any ME_ENDPOINT payloads, aborting");
this->invalid_syntax = TRUE;
break;
}
- DBG1(DBG_IKE, "received P2P_CONNECT");
+ DBG1(DBG_IKE, "received ME_CONNECT");
break;
}
default:
@@ -396,11 +376,11 @@ static status_t process_r(private_ike_p2p_t *this, message_t *message)
/**
* Implementation of task_t.build for responder
*/
-static status_t build_r(private_ike_p2p_t *this, message_t *message)
+static status_t build_r(private_ike_me_t *this, message_t *message)
{
switch(message->get_exchange_type(message))
{
- case P2P_CONNECT:
+ case ME_CONNECT:
{
if (this->invalid_syntax)
{
@@ -422,7 +402,7 @@ static status_t build_r(private_ike_p2p_t *this, message_t *message)
* as initiator, upon receiving a response from another peer,
* update the checklist and start sending checks */
charon->connect_manager->set_responder_data(charon->connect_manager,
- this->session_id, this->session_key, this->remote_endpoints);
+ this->connect_id, this->connect_key, this->remote_endpoints);
}
else
{
@@ -430,10 +410,10 @@ static status_t build_r(private_ike_p2p_t *this, message_t *message)
* as responder, create a checklist with the initiator's data */
charon->connect_manager->set_initiator_data(charon->connect_manager,
this->peer_id, this->ike_sa->get_my_id(this->ike_sa),
- this->session_id, this->session_key, this->remote_endpoints,
+ this->connect_id, this->connect_key, this->remote_endpoints,
FALSE);
if (this->ike_sa->respond(this->ike_sa, this->peer_id,
- this->session_id) != SUCCESS)
+ this->connect_id) != SUCCESS)
{
return FAILED;
}
@@ -449,7 +429,7 @@ static status_t build_r(private_ike_p2p_t *this, message_t *message)
/**
* Implementation of task_t.process for initiator
*/
-static status_t process_i(private_ike_p2p_t *this, message_t *message)
+static status_t process_i(private_ike_me_t *this, message_t *message)
{
switch(message->get_exchange_type(message))
{
@@ -459,7 +439,7 @@ static status_t process_i(private_ike_p2p_t *this, message_t *message)
if (!this->mediation)
{
- DBG1(DBG_IKE, "server did not return a P2P_MEDIATION, aborting");
+ DBG1(DBG_IKE, "server did not return a ME_MEDIATION, aborting");
return FAILED;
}
@@ -485,16 +465,14 @@ static status_t process_i(private_ike_p2p_t *this, message_t *message)
break;
}
- case P2P_CONNECT:
+ case ME_CONNECT:
{
process_payloads(this, message);
if (this->failed)
{
DBG1(DBG_IKE, "peer '%D' is not online", this->peer_id);
- /* FIXME: notify the mediated connection (job?)
- * FIXME: probably delete the created checklist, at least as
- * responder */
+ /* FIXME: notify the mediated connection (job?) */
}
else
{
@@ -503,7 +481,7 @@ static status_t process_i(private_ike_p2p_t *this, message_t *message)
/* FIXME: handle result of set_responder_data.
* as responder, we update the checklist and start sending checks */
charon->connect_manager->set_responder_data(charon->connect_manager,
- this->session_id, this->session_key, this->local_endpoints);
+ this->connect_id, this->connect_key, this->local_endpoints);
}
else
{
@@ -511,8 +489,10 @@ static status_t process_i(private_ike_p2p_t *this, message_t *message)
* as initiator, we create a checklist and set the initiator's data */
charon->connect_manager->set_initiator_data(charon->connect_manager,
this->ike_sa->get_my_id(this->ike_sa), this->peer_id,
- this->session_id, this->session_key, this->local_endpoints,
+ this->connect_id, this->connect_key, this->local_endpoints,
TRUE);
+ /* FIXME: also start a timer for the whole transaction (maybe
+ * within the connect_manager?) */
}
}
break;
@@ -524,29 +504,29 @@ static status_t process_i(private_ike_p2p_t *this, message_t *message)
}
/**
- * Implementation of task_t.process for initiator (mediation server)
+ * Implementation of task_t.build for initiator (mediation server)
*/
-static status_t build_i_ms(private_ike_p2p_t *this, message_t *message)
+static status_t build_i_ms(private_ike_me_t *this, message_t *message)
{
switch(message->get_exchange_type(message))
{
- case P2P_CONNECT:
+ case ME_CONNECT:
{
id_payload_t *id_payload = id_payload_create_from_identification(ID_PEER, this->peer_id);
message->add_payload(message, (payload_t*)id_payload);
if (this->callback)
{
- message->add_notify(message, FALSE, P2P_CALLBACK, chunk_empty);
+ message->add_notify(message, FALSE, ME_CALLBACK, chunk_empty);
}
else
{
if (this->response)
{
- message->add_notify(message, FALSE, P2P_RESPONSE, chunk_empty);
+ message->add_notify(message, FALSE, ME_RESPONSE, chunk_empty);
}
- message->add_notify(message, FALSE, P2P_SESSIONID, this->session_id);
- message->add_notify(message, FALSE, P2P_SESSIONKEY, this->session_key);
+ message->add_notify(message, FALSE, ME_CONNECTID, this->connect_id);
+ message->add_notify(message, FALSE, ME_CONNECTKEY, this->connect_key);
add_endpoints_to_message(message, this->remote_endpoints);
}
@@ -562,27 +542,37 @@ static status_t build_i_ms(private_ike_p2p_t *this, message_t *message)
/**
* Implementation of task_t.process for responder (mediation server)
*/
-static status_t process_r_ms(private_ike_p2p_t *this, message_t *message)
+static status_t process_r_ms(private_ike_me_t *this, message_t *message)
{
switch(message->get_exchange_type(message))
{
case IKE_SA_INIT:
{
+ /* FIXME: we should check for SA* and TS* payloads
+ * if any are there send NO_ADDITIONAL_SAS back and delete this SA */
process_payloads(this, message);
return this->mediation ? NEED_MORE : SUCCESS;
}
case IKE_AUTH:
{
+ /* FIXME: we should check whether the current peer_config is configured
+ * as mediation connection */
process_payloads(this, message);
break;
}
- case P2P_CONNECT:
+ case CREATE_CHILD_SA:
+ {
+ /* FIXME: if this is not to rekey the IKE SA we have to return a
+ * NO_ADDITIONAL_SAS and then delete the SA */
+ break;
+ }
+ case ME_CONNECT:
{
id_payload_t *id_payload;
id_payload = (id_payload_t*)message->get_payload(message, ID_PEER);
if (!id_payload)
{
- DBG1(DBG_IKE, "received P2P_CONNECT without ID_PEER payload, aborting");
+ DBG1(DBG_IKE, "received ME_CONNECT without ID_PEER payload, aborting");
this->invalid_syntax = TRUE;
break;
}
@@ -591,23 +581,23 @@ static status_t process_r_ms(private_ike_p2p_t *this, message_t *message)
process_payloads(this, message);
- if (!this->session_id.ptr)
+ if (!this->connect_id.ptr)
{
- DBG1(DBG_IKE, "received P2P_CONNECT without P2P_SESSIONID notify, aborting");
+ DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTID notify, aborting");
this->invalid_syntax = TRUE;
break;
}
- if (!this->session_key.ptr)
+ if (!this->connect_key.ptr)
{
- DBG1(DBG_IKE, "received P2P_CONNECT without P2P_SESSIONKEY notify, aborting");
+ DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTKEY notify, aborting");
this->invalid_syntax = TRUE;
break;
}
if (!this->remote_endpoints->get_count(this->remote_endpoints))
{
- DBG1(DBG_IKE, "received P2P_CONNECT without any P2P_ENDPOINT payloads, aborting");
+ DBG1(DBG_IKE, "received ME_CONNECT without any ME_ENDPOINT payloads, aborting");
this->invalid_syntax = TRUE;
break;
}
@@ -623,13 +613,13 @@ static status_t process_r_ms(private_ike_p2p_t *this, message_t *message)
/**
* Implementation of task_t.build for responder (mediation server)
*/
-static status_t build_r_ms(private_ike_p2p_t *this, message_t *message)
+static status_t build_r_ms(private_ike_me_t *this, message_t *message)
{
switch(message->get_exchange_type(message))
{
case IKE_SA_INIT:
{
- message->add_notify(message, FALSE, P2P_MEDIATION, chunk_empty);
+ message->add_notify(message, FALSE, ME_MEDIATION, chunk_empty);
return NEED_MORE;
}
case IKE_AUTH:
@@ -645,17 +635,17 @@ static status_t build_r_ms(private_ike_p2p_t *this, message_t *message)
endpoint = endpoint_notify_create_from_host(SERVER_REFLEXIVE, host, NULL);
message->add_payload(message, (payload_t*)endpoint->build_notify(endpoint));
+ endpoint->destroy(endpoint);
}
- charon->mediation_manager->update_sa_id(charon->mediation_manager,
- this->ike_sa->get_other_id(this->ike_sa),
- this->ike_sa->get_id(this->ike_sa));
+ /* FIXME: we actually must delete any existing IKE_SAs with the same remote id */
+ this->ike_sa->act_as_mediation_server(this->ike_sa);
SIG(CHILD_UP_SUCCESS, "established mediation connection without CHILD_SA successfully");
break;
}
- case P2P_CONNECT:
+ case ME_CONNECT:
{
if (this->invalid_syntax)
{
@@ -678,13 +668,13 @@ static status_t build_r_ms(private_ike_p2p_t *this, message_t *message)
if (!peer_sa)
{
/* the peer is not online */
- message->add_notify(message, TRUE, P2P_CONNECT_FAILED, chunk_empty);
+ message->add_notify(message, TRUE, ME_CONNECT_FAILED, chunk_empty);
break;
}
job_t *job = (job_t*)mediation_job_create(this->peer_id,
- this->ike_sa->get_other_id(this->ike_sa), this->session_id,
- this->session_key, this->remote_endpoints, this->response);
+ this->ike_sa->get_other_id(this->ike_sa), this->connect_id,
+ this->connect_key, this->remote_endpoints, this->response);
charon->processor->queue_job(charon->processor, job);
break;
@@ -698,64 +688,71 @@ static status_t build_r_ms(private_ike_p2p_t *this, message_t *message)
/**
* Implementation of task_t.process for initiator (mediation server)
*/
-static status_t process_i_ms(private_ike_p2p_t *this, message_t *message)
+static status_t process_i_ms(private_ike_me_t *this, message_t *message)
{
+ /* FIXME: theoretically we should be prepared to receive a ME_CONNECT_FAILED
+ * here if the responding peer is not able to proceed. in this case we shall
+ * notify the initiating peer with a ME_CONNECT request containing only a
+ * ME_CONNECT_FAILED */
return SUCCESS;
}
/**
- * Implementation of ike_p2p.connect
+ * Implementation of ike_me.connect
*/
-static void p2p_connect(private_ike_p2p_t *this, identification_t *peer_id)
+static void me_connect(private_ike_me_t *this, identification_t *peer_id)
{
this->peer_id = peer_id->clone(peer_id);
}
/**
- * Implementation of ike_p2p.respond
+ * Implementation of ike_me.respond
*/
-static void p2p_respond(private_ike_p2p_t *this, identification_t *peer_id,
- chunk_t session_id)
+static void me_respond(private_ike_me_t *this, identification_t *peer_id,
+ chunk_t connect_id)
{
this->peer_id = peer_id->clone(peer_id);
- this->session_id = chunk_clone(session_id);
+ this->connect_id = chunk_clone(connect_id);
this->response = TRUE;
}
/**
- * Implementation of ike_p2p.callback
+ * Implementation of ike_me.callback
*/
-static void p2p_callback(private_ike_p2p_t *this, identification_t *peer_id)
+static void me_callback(private_ike_me_t *this, identification_t *peer_id)
{
this->peer_id = peer_id->clone(peer_id);
this->callback = TRUE;
}
/**
- * Implementation of ike_p2p.relay
+ * Implementation of ike_me.relay
*/
-static void relay(private_ike_p2p_t *this, identification_t *requester, chunk_t session_id,
- chunk_t session_key, linked_list_t *endpoints, bool response)
+static void relay(private_ike_me_t *this, identification_t *requester, chunk_t connect_id,
+ chunk_t connect_key, linked_list_t *endpoints, bool response)
{
this->peer_id = requester->clone(requester);
- this->session_id = chunk_clone(session_id);
- this->session_key = chunk_clone(session_key);
+ this->connect_id = chunk_clone(connect_id);
+ this->connect_key = chunk_clone(connect_key);
+
+ this->remote_endpoints->destroy_offset(this->remote_endpoints, offsetof(endpoint_notify_t, destroy));
this->remote_endpoints = endpoints->clone_offset(endpoints, offsetof(endpoint_notify_t, clone));
+
this->response = response;
}
/**
* Implementation of task_t.get_type
*/
-static task_type_t get_type(private_ike_p2p_t *this)
+static task_type_t get_type(private_ike_me_t *this)
{
- return IKE_P2P;
+ return IKE_ME;
}
/**
* Implementation of task_t.migrate
*/
-static void migrate(private_ike_p2p_t *this, ike_sa_t *ike_sa)
+static void migrate(private_ike_me_t *this, ike_sa_t *ike_sa)
{
this->ike_sa = ike_sa;
}
@@ -763,12 +760,12 @@ static void migrate(private_ike_p2p_t *this, ike_sa_t *ike_sa)
/**
* Implementation of task_t.destroy
*/
-static void destroy(private_ike_p2p_t *this)
+static void destroy(private_ike_me_t *this)
{
DESTROY_IF(this->peer_id);
- chunk_free(&this->session_id);
- chunk_free(&this->session_key);
+ chunk_free(&this->connect_id);
+ chunk_free(&this->connect_key);
this->local_endpoints->destroy_offset(this->local_endpoints, offsetof(endpoint_notify_t, destroy));
this->remote_endpoints->destroy_offset(this->remote_endpoints, offsetof(endpoint_notify_t, destroy));
@@ -780,16 +777,15 @@ static void destroy(private_ike_p2p_t *this)
/*
* Described in header.
*/
-ike_p2p_t *ike_p2p_create(ike_sa_t *ike_sa, bool initiator)
+ike_me_t *ike_me_create(ike_sa_t *ike_sa, bool initiator)
{
- private_ike_p2p_t *this = malloc_thing(private_ike_p2p_t);
+ private_ike_me_t *this = malloc_thing(private_ike_me_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
- ike_sa_id_t *id = ike_sa->get_id(ike_sa);
- if (id->is_initiator(id))
+ if (ike_sa->is_ike_initiator(ike_sa))
{
if (initiator)
{
@@ -817,17 +813,17 @@ ike_p2p_t *ike_p2p_create(ike_sa_t *ike_sa, bool initiator)
}
}
- this->public.connect = (void(*)(ike_p2p_t*,identification_t*))p2p_connect;
- this->public.respond = (void(*)(ike_p2p_t*,identification_t*,chunk_t))p2p_respond;
- this->public.callback = (void(*)(ike_p2p_t*,identification_t*))p2p_callback;
- this->public.relay = (void(*)(ike_p2p_t*,identification_t*,chunk_t,chunk_t,linked_list_t*,bool))relay;
+ this->public.connect = (void(*)(ike_me_t*,identification_t*))me_connect;
+ this->public.respond = (void(*)(ike_me_t*,identification_t*,chunk_t))me_respond;
+ this->public.callback = (void(*)(ike_me_t*,identification_t*))me_callback;
+ this->public.relay = (void(*)(ike_me_t*,identification_t*,chunk_t,chunk_t,linked_list_t*,bool))relay;
this->ike_sa = ike_sa;
this->initiator = initiator;
this->peer_id = NULL;
- this->session_id = chunk_empty;
- this->session_key = chunk_empty;
+ this->connect_id = chunk_empty;
+ this->connect_key = chunk_empty;
this->local_endpoints = linked_list_create();
this->remote_endpoints = linked_list_create();
this->mediation = FALSE;
diff --git a/src/charon/sa/tasks/ike_p2p.h b/src/charon/sa/tasks/ike_me.h
index 327ac49d8..c9a515c8f 100644
--- a/src/charon/sa/tasks/ike_p2p.h
+++ b/src/charon/sa/tasks/ike_me.h
@@ -1,10 +1,3 @@
-/**
- * @file ike_p2p.h
- *
- * @brief Interface ike_p2p_t.
- *
- */
-
/*
* Copyright (C) 2007 Tobias Brunner
* Hochschule fuer Technik Rapperswil
@@ -18,35 +11,37 @@
* 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.
+ *
+ * $Id: ike_me.h 3666 2008-03-26 18:40:19Z tobias $
*/
-#ifndef IKE_P2P_H_
-#define IKE_P2P_H_
+/**
+ * @defgroup ike_me ike_me
+ * @{ @ingroup tasks
+ */
+
+#ifndef IKE_ME_H_
+#define IKE_ME_H_
-typedef struct ike_p2p_t ike_p2p_t;
+typedef struct ike_me_t ike_me_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
- * @brief Task of type IKE_P2P, detects and handles P2P-NAT-T extensions.
+ * Task of type IKE_ME, detects and handles IKE-ME extensions.
*
- * This tasks handles the P2P_MEDIATION notify exchange to setup a mediation
- * connection, allows to initiate mediated connections using P2P_CONNECT
+ * This tasks handles the ME_MEDIATION Notify exchange to setup a mediation
+ * connection, allows to initiate mediated connections using ME_CONNECT
* exchanges and to request reflexive addresses from the mediation server using
- * P2P_ENDPOINT notifies.
+ * ME_ENDPOINT notifies.
*
* @note This task has to be activated before the IKE_AUTH task, because that
* task generates the IKE_SA_INIT message so that no more payloads can be added
* to it afterwards.
- *
- * @b Constructors:
- * - ike_p2p_create()
- *
- * @ingroup tasks
*/
-struct ike_p2p_t {
+struct ike_me_t {
/**
* Implements the task_t interface
@@ -54,57 +49,52 @@ struct ike_p2p_t {
task_t task;
/**
- * @brief Initiates a connection with another peer (i.e. sends a P2P_CONNECT
+ * Initiates a connection with another peer (i.e. sends a ME_CONNECT
* to the mediation server)
*
- * @param this object
* @param peer_id ID of the other peer (gets cloned)
*/
- void (*connect)(ike_p2p_t *this, identification_t *peer_id);
+ void (*connect)(ike_me_t *this, identification_t *peer_id);
/**
- * @brief Responds to a P2P_CONNECT from another peer (i.e. sends a P2P_CONNECT
+ * Responds to a ME_CONNECT from another peer (i.e. sends a ME_CONNECT
* to the mediation server)
*
- * @param this object
* @param peer_id ID of the other peer (gets cloned)
- * @param session_id the session ID as provided by the initiator (gets cloned)
+ * @param connect_id the connect ID as provided by the initiator (gets cloned)
*/
- void (*respond)(ike_p2p_t *this, identification_t *peer_id, chunk_t session_id);
+ void (*respond)(ike_me_t *this, identification_t *peer_id, chunk_t connect_id);
/**
- * @brief Sends a P2P_CALLBACK to a peer that previously requested another peer.
+ * Sends a ME_CALLBACK to a peer that previously requested another peer.
*
- * @param this object
* @param peer_id ID of the other peer (gets cloned)
*/
- void (*callback)(ike_p2p_t *this, identification_t *peer_id);
+ void (*callback)(ike_me_t *this, identification_t *peer_id);
/**
- * @brief Relays data to another peer (i.e. sends a P2P_CONNECT to the peer)
+ * Relays data to another peer (i.e. sends a ME_CONNECT to the peer)
*
* Data gets cloned.
*
- * @param this object
* @param requester ID of the requesting peer
- * @param session_id content of the P2P_SESSIONID notify
- * @param session_key content of the P2P_SESSIONKEY notify
+ * @param connect_id content of the ME_CONNECTID notify
+ * @param connect_key content of the ME_CONNECTKEY notify
* @param endpoints endpoints
* @param response TRUE if this is a response
*/
- void (*relay)(ike_p2p_t *this, identification_t *requester, chunk_t session_id,
- chunk_t session_key, linked_list_t *endpoints, bool response);
+ void (*relay)(ike_me_t *this, identification_t *requester, chunk_t connect_id,
+ chunk_t connect_key, linked_list_t *endpoints, bool response);
};
/**
- * @brief Create a new ike_p2p task.
+ * Create a new ike_me task.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if taks is initiated by us
- * @return ike_p2p task to handle by the task_manager
+ * @return ike_me task to handle by the task_manager
*/
-ike_p2p_t *ike_p2p_create(ike_sa_t *ike_sa, bool initiator);
-
+ike_me_t *ike_me_create(ike_sa_t *ike_sa, bool initiator);
-#endif /*IKE_P2P_H_*/
+#endif /*IKE_ME_H_ @} */
diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c
index a53c243f0..23c68b9e9 100644
--- a/src/charon/sa/tasks/ike_mobike.c
+++ b/src/charon/sa/tasks/ike_mobike.c
@@ -1,10 +1,3 @@
-/**
- * @file ike_mobike.c
- *
- * @brief Implementation of the ike_mobike task.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,8 @@
* 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.
+ *
+ * $Id: ike_mobike.c 4006 2008-05-23 15:43:42Z martin $
*/
#include "ike_mobike.h"
@@ -28,6 +23,7 @@
#include <sa/tasks/ike_natd.h>
#include <encoding/payloads/notify_payload.h>
+#define COOKIE2_SIZE 16
typedef struct private_ike_mobike_t private_ike_mobike_t;
@@ -125,6 +121,12 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message)
this->ike_sa->enable_extension(this->ike_sa, EXT_MOBIKE);
break;
}
+ case COOKIE2:
+ {
+ chunk_free(&this->cookie2);
+ this->cookie2 = chunk_clone(notify->get_notification_data(notify));
+ break;
+ }
case ADDITIONAL_IP6_ADDRESS:
{
family = AF_INET6;
@@ -211,6 +213,23 @@ static void build_address_list(private_ike_mobike_t *this, message_t *message)
}
/**
+ * build a cookie and add it to the message
+ */
+static void build_cookie(private_ike_mobike_t *this, message_t *message)
+{
+ rng_t *rng;
+
+ chunk_free(&this->cookie2);
+ rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
+ if (rng)
+ {
+ rng->allocate_bytes(rng, COOKIE2_SIZE, &this->cookie2);
+ rng->destroy(rng);
+ message->add_notify(message, FALSE, COOKIE2, this->cookie2);
+ }
+}
+
+/**
* update addresses of associated CHILD_SAs
*/
static void update_children(private_ike_mobike_t *this)
@@ -262,6 +281,11 @@ static void transmit(private_ike_mobike_t *this, packet_t *packet)
charon->kernel_interface, other);
if (me)
{
+ if (me->get_family(me) != other->get_family(other))
+ {
+ me->destroy(me);
+ continue;
+ }
/* reuse port for an active address, 4500 otherwise */
me->set_port(me, me->ip_equals(me, me_old) ?
me_old->get_port(me_old) : IKEV2_NATT_PORT);
@@ -297,6 +321,7 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message)
if (this->update)
{
message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, chunk_empty);
+ build_cookie(this, message);
update_children(this);
}
if (this->address)
@@ -363,6 +388,11 @@ static status_t build_r(private_ike_mobike_t *this, message_t *message)
{
this->natd->task.build(&this->natd->task, message);
}
+ if (this->cookie2.ptr)
+ {
+ message->add_notify(message, FALSE, COOKIE2, this->cookie2);
+ chunk_free(&this->cookie2);
+ }
if (this->update)
{
update_children(this);
@@ -392,7 +422,25 @@ static status_t process_i(private_ike_mobike_t *this, message_t *message)
/* newer update queued, ignore this one */
return SUCCESS;
}
- process_payloads(this, message);
+ if (this->cookie2.ptr)
+ { /* check cookie if we included none */
+ chunk_t cookie2;
+
+ cookie2 = this->cookie2;
+ this->cookie2 = chunk_empty;
+ process_payloads(this, message);
+ if (!chunk_equals(cookie2, this->cookie2))
+ {
+ chunk_free(&cookie2);
+ DBG1(DBG_IKE, "COOKIE2 mismatch, closing IKE_SA");
+ return FAILED;
+ }
+ chunk_free(&cookie2);
+ }
+ else
+ {
+ process_payloads(this, message);
+ }
if (this->natd)
{
this->natd->task.process(&this->natd->task, message);
diff --git a/src/charon/sa/tasks/ike_mobike.h b/src/charon/sa/tasks/ike_mobike.h
index bb5150723..9dd29970e 100644
--- a/src/charon/sa/tasks/ike_mobike.h
+++ b/src/charon/sa/tasks/ike_mobike.h
@@ -1,10 +1,3 @@
-/**
- * @file ike_mobike.h
- *
- * @brief Interface ike_mobike_t.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: ike_mobike.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup ike_mobike ike_mobike
+ * @{ @ingroup tasks
*/
#ifndef IKE_MOBIKE_H_
@@ -31,7 +31,7 @@ typedef struct ike_mobike_t ike_mobike_t;
#include <network/packet.h>
/**
- * @brief Task of type ike_mobike, detects and handles MOBIKE extension.
+ * Task of type ike_mobike, detects and handles MOBIKE extension.
*
* The MOBIKE extension is defined in RFC4555. It allows to update IKE
* and IPsec tunnel addresses.
@@ -39,11 +39,6 @@ typedef struct ike_mobike_t ike_mobike_t;
* support, allows the exchange of ADDITIONAL_*_ADDRESS to exchange additional
* endpoints and handles the UPDATE_SA_ADDRESS notify to finally update
* endpoints.
- *
- * @b Constructors:
- * - ike_mobike_create()
- *
- * @ingroup tasks
*/
struct ike_mobike_t {
@@ -53,36 +48,33 @@ struct ike_mobike_t {
task_t task;
/**
- * @brief Use the task to roam to other addresses.
+ * Use the task to roam to other addresses.
*
- * @param this calling object
* @param address TRUE to include address list update
*/
void (*roam)(ike_mobike_t *this, bool address);
/**
- * @brief Transmision hook, called by task manager.
+ * Transmision hook, called by task manager.
*
* The task manager calls this hook whenever it transmits a packet. It
* allows the mobike task to send the packet on multiple paths to do path
* probing.
*
- * @param this calling object
* @param packet the packet to transmit
*/
void (*transmit)(ike_mobike_t *this, packet_t *packet);
/**
- * @brief Check if this task is probing for routability.
+ * Check if this task is probing for routability.
*
- * @param this calling object
* @return TRUE if task is probing
*/
bool (*is_probing)(ike_mobike_t *this);
};
/**
- * @brief Create a new ike_mobike task.
+ * Create a new ike_mobike task.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if taks is initiated by us
@@ -90,5 +82,4 @@ struct ike_mobike_t {
*/
ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator);
-#endif /* IKE_MOBIKE_H_ */
-
+#endif /* IKE_MOBIKE_H_ @} */
diff --git a/src/charon/sa/tasks/ike_natd.c b/src/charon/sa/tasks/ike_natd.c
index 4c64ff8ba..69e5bac26 100644
--- a/src/charon/sa/tasks/ike_natd.c
+++ b/src/charon/sa/tasks/ike_natd.c
@@ -1,10 +1,3 @@
-/**
- * @file ike_natd.c
- *
- * @brief Implementation of the ike_natd task.
- *
- */
-
/*
* Copyright (C) 2006-2007 Martin Willi
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
@@ -19,6 +12,8 @@
* 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.
+ *
+ * $Id: ike_natd.c 3806 2008-04-15 05:56:35Z martin $
*/
#include "ike_natd.h"
@@ -118,17 +113,17 @@ static chunk_t generate_natd_hash(private_ike_natd_t *this,
*/
static chunk_t generate_natd_hash_faked(private_ike_natd_t *this)
{
- randomizer_t *randomizer;
+ rng_t *rng;
chunk_t chunk;
- randomizer = randomizer_create();
- if (randomizer->allocate_pseudo_random_bytes(randomizer, HASH_SIZE_SHA1,
- &chunk) != SUCCESS)
+ rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+ if (!rng)
{
DBG1(DBG_IKE, "unable to get random bytes for NATD fake");
- chunk = chunk_empty;
+ return chunk_empty;
}
- randomizer->destroy(randomizer);
+ rng->allocate_bytes(rng, HASH_SIZE_SHA1, &chunk);
+ rng->destroy(rng);
return chunk;
}
@@ -259,7 +254,7 @@ static status_t process_i(private_ike_natd_t *this, message_t *message)
{
peer_cfg_t *peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
-#ifdef P2P
+#ifdef ME
/* if we are on a mediated connection we have already switched to
* port 4500 and the correct destination port is already configured,
* therefore we must not switch again */
@@ -267,14 +262,14 @@ static status_t process_i(private_ike_natd_t *this, message_t *message)
{
return SUCCESS;
}
-#endif /* P2P */
+#endif /* ME */
if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY) ||
-#ifdef P2P
+#ifdef ME
/* if we are on a mediation connection we swith to port 4500 even
* if no NAT is detected. */
peer_cfg->is_mediation(peer_cfg) ||
-#endif /* P2P */
+#endif /* ME */
/* if peer supports NAT-T, we switch to port 4500 even
* if no NAT is detected. MOBIKE requires this. */
(peer_cfg->use_mobike(peer_cfg) &&
@@ -308,6 +303,12 @@ static status_t build_i(private_ike_natd_t *this, message_t *message)
iterator_t *iterator;
host_t *host;
+ if (this->hasher == NULL)
+ {
+ DBG1(DBG_IKE, "unable to build NATD payloads, SHA1 not supported");
+ return NEED_MORE;
+ }
+
/* destination is always set */
host = message->get_destination(message);
notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host);
@@ -368,6 +369,12 @@ static status_t build_r(private_ike_natd_t *this, message_t *message)
if (this->src_seen && this->dst_seen)
{
+ if (this->hasher == NULL)
+ {
+ DBG1(DBG_IKE, "unable to build NATD payloads, SHA1 not supported");
+ return SUCCESS;
+ }
+
/* initiator seems to support NAT detection, add response */
me = message->get_source(message);
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, me);
@@ -415,7 +422,7 @@ static void migrate(private_ike_natd_t *this, ike_sa_t *ike_sa)
*/
static void destroy(private_ike_natd_t *this)
{
- this->hasher->destroy(this->hasher);
+ DESTROY_IF(this->hasher);
free(this);
}
@@ -443,7 +450,7 @@ ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator)
this->ike_sa = ike_sa;
this->initiator = initiator;
- this->hasher = hasher_create(HASH_SHA1);
+ this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
this->src_seen = FALSE;
this->dst_seen = FALSE;
this->src_matched = FALSE;
diff --git a/src/charon/sa/tasks/ike_natd.h b/src/charon/sa/tasks/ike_natd.h
index 8d0cb58b4..d78c931d9 100644
--- a/src/charon/sa/tasks/ike_natd.h
+++ b/src/charon/sa/tasks/ike_natd.h
@@ -1,10 +1,3 @@
-/**
- * @file ike_natd.h
- *
- * @brief Interface ike_natd_t.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: ike_natd.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup ike_natd ike_natd
+ * @{ @ingroup tasks
*/
#ifndef IKE_NATD_H_
@@ -30,12 +30,7 @@ typedef struct ike_natd_t ike_natd_t;
#include <sa/tasks/task.h>
/**
- * @brief Task of type ike_natd, detects NAT situation in IKE_SA_INIT exchange.
- *
- * @b Constructors:
- * - ike_natd_create()
- *
- * @ingroup tasks
+ * Task of type ike_natd, detects NAT situation in IKE_SA_INIT exchange.
*/
struct ike_natd_t {
@@ -46,7 +41,7 @@ struct ike_natd_t {
};
/**
- * @brief Create a new ike_natd task.
+ * Create a new ike_natd task.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if thask is the original initator
@@ -54,4 +49,4 @@ struct ike_natd_t {
*/
ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator);
-#endif /* IKE_NATD_H_ */
+#endif /* IKE_NATD_H_ @} */
diff --git a/src/charon/sa/tasks/ike_reauth.c b/src/charon/sa/tasks/ike_reauth.c
index 0e98382a8..854e9359d 100644
--- a/src/charon/sa/tasks/ike_reauth.c
+++ b/src/charon/sa/tasks/ike_reauth.c
@@ -1,10 +1,3 @@
-/**
- * @file ike_reauth.c
- *
- * @brief Implementation of the ike_reauth task.
- *
- */
-
/*
* Copyright (C) 2006-2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,8 @@
* 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.
+ *
+ * $Id: ike_reauth.c 3793 2008-04-11 08:14:48Z martin $
*/
#include "ike_reauth.h"
@@ -66,22 +61,30 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message)
host_t *host;
iterator_t *iterator;
child_sa_t *child_sa;
+ peer_cfg_t *peer_cfg;
/* process delete response first */
this->ike_delete->task.process(&this->ike_delete->task, message);
- /* reestablish only if we have children */
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+
+ /* reauthenticate only if we have children */
iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa);
- if (iterator->get_count(iterator) == 0)
+ if (iterator->get_count(iterator) == 0
+#ifdef ME
+ /* we allow a peer to reauth a mediation connection (without CHILD_SA) */
+ && !peer_cfg->is_mediation(peer_cfg)
+#endif /* ME */
+ )
{
- DBG1(DBG_IKE, "unable to reestablish IKE_SA, no CHILD_SA to recreate");
+ DBG1(DBG_IKE, "unable to reauthenticate IKE_SA, no CHILD_SA to recreate");
iterator->destroy(iterator);
return FAILED;
}
new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE);
- new->set_peer_cfg(new, this->ike_sa->get_peer_cfg(this->ike_sa));
+ new->set_peer_cfg(new, peer_cfg);
host = this->ike_sa->get_other_host(this->ike_sa);
new->set_other_host(new, host->clone(host));
host = this->ike_sa->get_my_host(this->ike_sa);
@@ -93,6 +96,20 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message)
new->set_virtual_ip(new, TRUE, host);
}
+#ifdef ME
+ /* we initiate the new IKE_SA of the mediation connection without CHILD_SA */
+ if (peer_cfg->is_mediation(peer_cfg))
+ {
+ if (new->initiate(new, NULL) == DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, new);
+ DBG1(DBG_IKE, "reauthenticating IKE_SA failed");
+ return FAILED;
+ }
+ }
+#endif /* ME */
+
while (iterator->iterate(iterator, (void**)&child_sa))
{
switch (child_sa->get_state(child_sa))
@@ -114,7 +131,7 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message)
iterator->destroy(iterator);
charon->ike_sa_manager->checkin_and_destroy(
charon->ike_sa_manager, new);
- DBG1(DBG_IKE, "reestablishing IKE_SA failed");
+ DBG1(DBG_IKE, "reauthenticating IKE_SA failed");
return FAILED;
}
break;
diff --git a/src/charon/sa/tasks/ike_reauth.h b/src/charon/sa/tasks/ike_reauth.h
index 3c872e1e1..1076cc7cc 100644
--- a/src/charon/sa/tasks/ike_reauth.h
+++ b/src/charon/sa/tasks/ike_reauth.h
@@ -1,10 +1,3 @@
-/**
- * @file ike_reauth.h
- *
- * @brief Interface ike_reauth_t.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: ike_reauth.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup ike_reauth ike_reauth
+ * @{ @ingroup tasks
*/
#ifndef IKE_REAUTH_H_
@@ -30,12 +30,7 @@ typedef struct ike_reauth_t ike_reauth_t;
#include <sa/tasks/task.h>
/**
- * @brief Task of type ike_reauth, reestablishes an IKE_SA.
- *
- * @b Constructors:
- * - ike_reauth_create()
- *
- * @ingroup tasks
+ * Task of type ike_reauth, reestablishes an IKE_SA.
*/
struct ike_reauth_t {
@@ -46,7 +41,7 @@ struct ike_reauth_t {
};
/**
- * @brief Create a new ike_reauth task.
+ * Create a new ike_reauth task.
*
* This task is initiator only.
*
@@ -55,5 +50,4 @@ struct ike_reauth_t {
*/
ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa);
-#endif /* IKE_REAUTH_H_ */
-
+#endif /* IKE_REAUTH_H_ @} */
diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c
index 827f95156..9c0d1805c 100644
--- a/src/charon/sa/tasks/ike_rekey.c
+++ b/src/charon/sa/tasks/ike_rekey.c
@@ -1,10 +1,3 @@
-/**
- * @file ike_rekey.c
- *
- * @brief Implementation of the ike_rekey task.
- *
- */
-
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -19,6 +12,8 @@
* 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.
+ *
+ * $Id: ike_rekey.c 3589 2008-03-13 14:14:44Z martin $
*/
#include "ike_rekey.h"
diff --git a/src/charon/sa/tasks/ike_rekey.h b/src/charon/sa/tasks/ike_rekey.h
index 125422efd..1bfde8a54 100644
--- a/src/charon/sa/tasks/ike_rekey.h
+++ b/src/charon/sa/tasks/ike_rekey.h
@@ -1,10 +1,3 @@
-/**
- * @file ike_rekey.h
- *
- * @brief Interface ike_rekey_t.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,6 +11,13 @@
* 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.
+ *
+ * $Id: ike_rekey.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup ike_rekey ike_rekey
+ * @{ @ingroup tasks
*/
#ifndef IKE_REKEY_H_
@@ -30,12 +30,7 @@ typedef struct ike_rekey_t ike_rekey_t;
#include <sa/tasks/task.h>
/**
- * @brief Task of type IKE_REKEY, rekey an established IKE_SA.
- *
- * @b Constructors:
- * - ike_rekey_create()
- *
- * @ingroup tasks
+ * Task of type IKE_REKEY, rekey an established IKE_SA.
*/
struct ike_rekey_t {
@@ -45,20 +40,19 @@ struct ike_rekey_t {
task_t task;
/**
- * @brief Register a rekeying task which collides with this one.
+ * Register a rekeying task which collides with this one.
*
* If two peers initiate rekeying at the same time, the collision must
* be handled gracefully. The task manager is aware of what exchanges
* are going on and notifies the outgoing task by passing the incoming.
*
- * @param this task initated by us
* @param other incoming task
*/
void (*collide)(ike_rekey_t* this, task_t *other);
};
/**
- * @brief Create a new IKE_REKEY task.
+ * Create a new IKE_REKEY task.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE for initiator, FALSE for responder
@@ -66,4 +60,4 @@ struct ike_rekey_t {
*/
ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator);
-#endif /* IKE_REKEY_H_ */
+#endif /* IKE_REKEY_H_ @} */
diff --git a/src/charon/sa/tasks/task.c b/src/charon/sa/tasks/task.c
index cc20a8861..3192b688a 100644
--- a/src/charon/sa/tasks/task.c
+++ b/src/charon/sa/tasks/task.c
@@ -1,10 +1,3 @@
-/**
- * @file task.c
- *
- * @brief Enum values for task types
- *
- */
-
/*
* Copyright (C) 2007 Tobias Brunner
* Copyright (C) 2007 Martin Willi
@@ -19,6 +12,8 @@
* 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.
+ *
+ * $Id: task.c 3666 2008-03-26 18:40:19Z tobias $
*/
#include "task.h"
@@ -29,15 +24,16 @@ ENUM(task_type_names, IKE_INIT, CHILD_REKEY,
"IKE_MOBIKE",
"IKE_AUTHENTICATE",
"IKE_AUTH_LIFETIME",
- "IKE_CERT",
+ "IKE_CERT_PRE",
+ "IKE_CERT_POST",
"IKE_CONFIG",
"IKE_REKEY",
"IKE_REAUTH",
"IKE_DELETE",
"IKE_DPD",
-#ifdef P2P
- "IKE_P2P",
-#endif /* P2P */
+#ifdef ME
+ "IKE_ME",
+#endif /* ME */
"CHILD_CREATE",
"CHILD_DELETE",
"CHILD_REKEY",
diff --git a/src/charon/sa/tasks/task.h b/src/charon/sa/tasks/task.h
index a59207711..26b4f214e 100644
--- a/src/charon/sa/tasks/task.h
+++ b/src/charon/sa/tasks/task.h
@@ -1,10 +1,3 @@
-/**
- * @file task.h
- *
- * @brief Interface task_t.
- *
- */
-
/*
* Copyright (C) 2007 Tobias Brunner
* Copyright (C) 2006 Martin Willi
@@ -19,6 +12,13 @@
* 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.
+ *
+ * $Id: task.h 3666 2008-03-26 18:40:19Z tobias $
+ */
+
+/**
+ * @defgroup task task
+ * @{ @ingroup tasks
*/
#ifndef TASK_H_
@@ -32,9 +32,7 @@ typedef struct task_t task_t;
#include <encoding/message.h>
/**
- * @brief Different kinds of tasks.
- *
- * @ingroup tasks
+ * Different kinds of tasks.
*/
enum task_type_t {
/** establish an unauthenticated IKE_SA */
@@ -47,8 +45,10 @@ enum task_type_t {
IKE_AUTHENTICATE,
/** AUTH_LIFETIME negotiation, RFC4478 */
IKE_AUTH_LIFETIME,
- /** exchange certificates and requests */
- IKE_CERT,
+ /** certificate processing before authentication (certreqs, cert parsing) */
+ IKE_CERT_PRE,
+ /** certificate processing after authentication (certs payload generation) */
+ IKE_CERT_POST,
/** Configuration payloads, virtual IP and such */
IKE_CONFIG,
/** rekey an IKE_SA */
@@ -59,10 +59,10 @@ enum task_type_t {
IKE_DELETE,
/** liveness check */
IKE_DPD,
-#ifdef P2P
- /** handle P2P-NAT-T stuff */
- IKE_P2P,
-#endif /* P2P */
+#ifdef ME
+ /** handle ME stuff */
+ IKE_ME,
+#endif /* ME */
/** establish a CHILD_SA within an IKE_SA */
CHILD_CREATE,
/** delete an established CHILD_SA */
@@ -77,7 +77,7 @@ enum task_type_t {
extern enum_name_t *task_type_names;
/**
- * @brief Interface for a task, an operation handled within exchanges.
+ * Interface for a task, an operation handled within exchanges.
*
* A task is an elemantary operation. It may be handled by a single or by
* multiple exchanges. An exchange may even complete multiple tasks.
@@ -94,18 +94,12 @@ extern enum_name_t *task_type_names;
* the task needs further build()/process() calls to complete, the manager
* leaves the taks in the queue. A returned FAILED indicates a critical failure.
* The manager closes the IKE_SA whenever a task returns FAILED.
- *
- * @b Constructors:
- * - None, use implementations specific constructors
- *
- * @ingroup tasks
*/
struct task_t {
/**
- * @brief Build a request or response message for this task.
+ * Build a request or response message for this task.
*
- * @param this calling object
* @param message message to add payloads to
* @return
* - FAILED if a critical error occured
@@ -115,9 +109,8 @@ struct task_t {
status_t (*build) (task_t *this, message_t *message);
/**
- * @brief Process a request or response message for this task.
+ * Process a request or response message for this task.
*
- * @param this calling object
* @param message message to read payloads from
* @return
* - FAILED if a critical error occured
@@ -127,14 +120,12 @@ struct task_t {
status_t (*process) (task_t *this, message_t *message);
/**
- * @brief Get the type of the task implementation.
- *
- * @param this calling object
+ * Get the type of the task implementation.
*/
task_type_t (*get_type) (task_t *this);
/**
- * @brief Migrate a task to a new IKE_SA.
+ * Migrate a task to a new IKE_SA.
*
* After migrating a task, it goes back to a state where it can be
* used again to initate an exchange. This is useful when a task
@@ -144,17 +135,14 @@ struct task_t {
* try.
* The ike_sa is the new IKE_SA this task belongs to and operates on.
*
- * @param this calling object
* @param ike_sa new IKE_SA this task works for
*/
void (*migrate) (task_t *this, ike_sa_t *ike_sa);
/**
- * @brief Destroys a task_t object.
- *
- * @param this calling object
+ * Destroys a task_t object.
*/
void (*destroy) (task_t *this);
};
-#endif /* TASK_H_ */
+#endif /* TASK_H_ @} */